Commit 448d7248 authored by David Ahern's avatar David Ahern Committed by David S. Miller

ipv4: Refactor fib_check_nh

fib_check_nh is currently huge covering multiple uses cases - device only,
device + gateway, and device + gateway with ONLINK. The next patch adds
validation checks for IPv6 which only further complicates it. So, break
fib_check_nh into 2 helpers - one for gateway validation and one for device
only.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Reviewed-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a4ea5d43
...@@ -885,23 +885,18 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi) ...@@ -885,23 +885,18 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi)
* | * |
* |-> {local prefix} (terminal node) * |-> {local prefix} (terminal node)
*/ */
static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
struct netlink_ext_ack *extack) u8 scope, struct netlink_ext_ack *extack)
{ {
int err = 0;
struct net *net;
struct net_device *dev; struct net_device *dev;
net = cfg->fc_nlinfo.nl_net;
if (nh->fib_nh_gw4) {
struct fib_result res; struct fib_result res;
int err;
if (nh->fib_nh_flags & RTNH_F_ONLINK) { if (nh->fib_nh_flags & RTNH_F_ONLINK) {
unsigned int addr_type; unsigned int addr_type;
if (cfg->fc_scope >= RT_SCOPE_LINK) { if (scope >= RT_SCOPE_LINK) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack, "Nexthop has invalid scope");
"Nexthop has invalid scope");
return -EINVAL; return -EINVAL;
} }
dev = __dev_get_by_index(net, nh->fib_nh_oif); dev = __dev_get_by_index(net, nh->fib_nh_oif);
...@@ -910,15 +905,12 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, ...@@ -910,15 +905,12 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
return -ENODEV; return -ENODEV;
} }
if (!(dev->flags & IFF_UP)) { if (!(dev->flags & IFF_UP)) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack, "Nexthop device is not up");
"Nexthop device is not up");
return -ENETDOWN; return -ENETDOWN;
} }
addr_type = inet_addr_type_dev_table(net, dev, addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4);
nh->fib_nh_gw4);
if (addr_type != RTN_UNICAST) { if (addr_type != RTN_UNICAST) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
"Nexthop has invalid gateway");
return -EINVAL; return -EINVAL;
} }
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
...@@ -933,7 +925,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, ...@@ -933,7 +925,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
struct fib_table *tbl = NULL; struct fib_table *tbl = NULL;
struct flowi4 fl4 = { struct flowi4 fl4 = {
.daddr = nh->fib_nh_gw4, .daddr = nh->fib_nh_gw4,
.flowi4_scope = cfg->fc_scope + 1, .flowi4_scope = scope + 1,
.flowi4_oif = nh->fib_nh_oif, .flowi4_oif = nh->fib_nh_oif,
.flowi4_iif = LOOPBACK_IFINDEX, .flowi4_iif = LOOPBACK_IFINDEX,
}; };
...@@ -942,8 +934,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, ...@@ -942,8 +934,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
if (fl4.flowi4_scope < RT_SCOPE_LINK) if (fl4.flowi4_scope < RT_SCOPE_LINK)
fl4.flowi4_scope = RT_SCOPE_LINK; fl4.flowi4_scope = RT_SCOPE_LINK;
if (cfg->fc_table) if (table)
tbl = fib_get_table(net, cfg->fc_table); tbl = fib_get_table(net, table);
if (tbl) if (tbl)
err = fib_table_lookup(tbl, &fl4, &res, err = fib_table_lookup(tbl, &fl4, &res,
...@@ -960,12 +952,11 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, ...@@ -960,12 +952,11 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
} }
if (err) { if (err) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
"Nexthop has invalid gateway"); goto out;
rcu_read_unlock();
return err;
} }
} }
err = -EINVAL; err = -EINVAL;
if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) { if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway"); NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
...@@ -983,15 +974,25 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, ...@@ -983,15 +974,25 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_flags |= RTNH_F_LINKDOWN;
err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
} else { out:
rcu_read_unlock();
return err;
}
static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
struct netlink_ext_ack *extack)
{
struct in_device *in_dev; struct in_device *in_dev;
int err;
if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) { if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack,
"Invalid flags for nexthop - PERVASIVE and ONLINK can not be set"); "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set");
return -EINVAL; return -EINVAL;
} }
rcu_read_lock(); rcu_read_lock();
err = -ENODEV; err = -ENODEV;
in_dev = inetdev_by_index(net, nh->fib_nh_oif); in_dev = inetdev_by_index(net, nh->fib_nh_oif);
if (!in_dev) if (!in_dev)
...@@ -1001,18 +1002,33 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, ...@@ -1001,18 +1002,33 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
NL_SET_ERR_MSG(extack, "Device for nexthop is not up"); NL_SET_ERR_MSG(extack, "Device for nexthop is not up");
goto out; goto out;
} }
nh->fib_nh_dev = in_dev->dev; nh->fib_nh_dev = in_dev->dev;
dev_hold(nh->fib_nh_dev); dev_hold(nh->fib_nh_dev);
nh->fib_nh_scope = RT_SCOPE_HOST; nh->fib_nh_scope = RT_SCOPE_HOST;
if (!netif_carrier_ok(nh->fib_nh_dev)) if (!netif_carrier_ok(nh->fib_nh_dev))
nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_flags |= RTNH_F_LINKDOWN;
err = 0; err = 0;
}
out: out:
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
struct netlink_ext_ack *extack)
{
struct net *net = cfg->fc_nlinfo.nl_net;
u32 table = cfg->fc_table;
int err;
if (nh->fib_nh_gw_family == AF_INET)
err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
else
err = fib_check_nh_nongw(net, nh, extack);
return err;
}
static inline unsigned int fib_laddr_hashfn(__be32 val) static inline unsigned int fib_laddr_hashfn(__be32 val)
{ {
unsigned int mask = (fib_info_hash_size - 1); unsigned int mask = (fib_info_hash_size - 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment