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

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
Loading
Loading
Loading
Loading
+125 −109
Original line number Diff line number Diff line
@@ -885,23 +885,18 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi)
 *					|
 *					|-> {local prefix} (terminal node)
 */
static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
			struct netlink_ext_ack *extack)
static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
			      u8 scope, struct netlink_ext_ack *extack)
{
	int err = 0;
	struct net *net;
	struct net_device *dev;

	net = cfg->fc_nlinfo.nl_net;
	if (nh->fib_nh_gw4) {
	struct fib_result res;
	int err;

	if (nh->fib_nh_flags & RTNH_F_ONLINK) {
		unsigned int addr_type;

			if (cfg->fc_scope >= RT_SCOPE_LINK) {
				NL_SET_ERR_MSG(extack,
					       "Nexthop has invalid scope");
		if (scope >= RT_SCOPE_LINK) {
			NL_SET_ERR_MSG(extack, "Nexthop has invalid scope");
			return -EINVAL;
		}
		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,
			return -ENODEV;
		}
		if (!(dev->flags & IFF_UP)) {
				NL_SET_ERR_MSG(extack,
					       "Nexthop device is not up");
			NL_SET_ERR_MSG(extack, "Nexthop device is not up");
			return -ENETDOWN;
		}
			addr_type = inet_addr_type_dev_table(net, dev,
							     nh->fib_nh_gw4);
		addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4);
		if (addr_type != RTN_UNICAST) {
				NL_SET_ERR_MSG(extack,
					       "Nexthop has invalid gateway");
			NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
			return -EINVAL;
		}
		if (!netif_carrier_ok(dev))
@@ -933,7 +925,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
		struct fib_table *tbl = NULL;
		struct flowi4 fl4 = {
			.daddr = nh->fib_nh_gw4,
				.flowi4_scope = cfg->fc_scope + 1,
			.flowi4_scope = scope + 1,
			.flowi4_oif = nh->fib_nh_oif,
			.flowi4_iif = LOOPBACK_IFINDEX,
		};
@@ -942,8 +934,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
		if (fl4.flowi4_scope < RT_SCOPE_LINK)
			fl4.flowi4_scope = RT_SCOPE_LINK;

			if (cfg->fc_table)
				tbl = fib_get_table(net, cfg->fc_table);
		if (table)
			tbl = fib_get_table(net, table);

		if (tbl)
			err = fib_table_lookup(tbl, &fl4, &res,
@@ -960,12 +952,11 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
		}

		if (err) {
				NL_SET_ERR_MSG(extack,
					       "Nexthop has invalid gateway");
				rcu_read_unlock();
				return err;
			NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
			goto out;
		}
	}

	err = -EINVAL;
	if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
		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,
	if (!netif_carrier_ok(dev))
		nh->fib_nh_flags |= RTNH_F_LINKDOWN;
	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;
	int err;

	if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) {
		NL_SET_ERR_MSG(extack,
			       "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set");
		return -EINVAL;
	}

	rcu_read_lock();

	err = -ENODEV;
	in_dev = inetdev_by_index(net, nh->fib_nh_oif);
	if (!in_dev)
@@ -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");
		goto out;
	}

	nh->fib_nh_dev = in_dev->dev;
	dev_hold(nh->fib_nh_dev);
	nh->fib_nh_scope = RT_SCOPE_HOST;
	if (!netif_carrier_ok(nh->fib_nh_dev))
		nh->fib_nh_flags |= RTNH_F_LINKDOWN;
	err = 0;
	}
out:
	rcu_read_unlock();
	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)
{
	unsigned int mask = (fib_info_hash_size - 1);