Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 331c7a40 authored by David Ahern's avatar David Ahern Committed by David S. Miller
Browse files

ipv4: Move IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN to helper



in_dev lookup followed by IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN check
is called in several places, some with the rcu lock and others with the
rtnl held.

Move the check to a helper similar to what IPv6 has. Since the helper
can be invoked from either context use rcu_dereference_rtnl to
dereference ip_ptr.

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 8373c6c8
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -237,6 +237,20 @@ static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev)
	return rtnl_dereference(dev->ip_ptr);
}

/* called with rcu_read_lock or rtnl held */
static inline bool ip_ignore_linkdown(const struct net_device *dev)
{
	struct in_device *in_dev;
	bool rc = false;

	in_dev = rcu_dereference_rtnl(dev->ip_ptr);
	if (in_dev &&
	    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
		rc = true;

	return rc;
}

static inline struct neigh_parms *__in_dev_arp_parms_get_rcu(const struct net_device *dev)
{
	struct in_device *in_dev = __in_dev_get_rcu(dev);
+7 −24
Original line number Diff line number Diff line
@@ -558,7 +558,6 @@ static void fib_rebalance(struct fib_info *fi)
{
	int total;
	int w;
	struct in_device *in_dev;

	if (fi->fib_nhs < 2)
		return;
@@ -568,10 +567,7 @@ static void fib_rebalance(struct fib_info *fi)
		if (nh->nh_flags & RTNH_F_DEAD)
			continue;

		in_dev = __in_dev_get_rtnl(nh->nh_dev);

		if (in_dev &&
		    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
		if (ip_ignore_linkdown(nh->nh_dev) &&
		    nh->nh_flags & RTNH_F_LINKDOWN)
			continue;

@@ -582,12 +578,9 @@ static void fib_rebalance(struct fib_info *fi)
	change_nexthops(fi) {
		int upper_bound;

		in_dev = __in_dev_get_rtnl(nexthop_nh->nh_dev);

		if (nexthop_nh->nh_flags & RTNH_F_DEAD) {
			upper_bound = -1;
		} else if (in_dev &&
			   IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
		} else if (ip_ignore_linkdown(nexthop_nh->nh_dev) &&
			   nexthop_nh->nh_flags & RTNH_F_LINKDOWN) {
			upper_bound = -1;
		} else {
@@ -1325,12 +1318,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
		    nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif))
			goto nla_put_failure;
		if (fi->fib_nh->nh_flags & RTNH_F_LINKDOWN) {
			struct in_device *in_dev;

			rcu_read_lock();
			in_dev = __in_dev_get_rcu(fi->fib_nh->nh_dev);
			if (in_dev &&
			    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
			if (ip_ignore_linkdown(fi->fib_nh->nh_dev))
				rtm->rtm_flags |= RTNH_F_DEAD;
			rcu_read_unlock();
		}
@@ -1361,12 +1350,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,

			rtnh->rtnh_flags = nh->nh_flags & 0xFF;
			if (nh->nh_flags & RTNH_F_LINKDOWN) {
				struct in_device *in_dev;

				rcu_read_lock();
				in_dev = __in_dev_get_rcu(nh->nh_dev);
				if (in_dev &&
				    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
				if (ip_ignore_linkdown(nh->nh_dev))
					rtnh->rtnh_flags |= RTNH_F_DEAD;
				rcu_read_unlock();
			}
@@ -1433,7 +1418,7 @@ int fib_sync_down_addr(struct net_device *dev, __be32 local)
static int call_fib_nh_notifiers(struct fib_nh *fib_nh,
				 enum fib_event_type event_type)
{
	struct in_device *in_dev = __in_dev_get_rtnl(fib_nh->nh_dev);
	bool ignore_link_down = ip_ignore_linkdown(fib_nh->nh_dev);
	struct fib_nh_notifier_info info = {
		.fib_nh = fib_nh,
	};
@@ -1442,14 +1427,12 @@ static int call_fib_nh_notifiers(struct fib_nh *fib_nh,
	case FIB_EVENT_NH_ADD:
		if (fib_nh->nh_flags & RTNH_F_DEAD)
			break;
		if (IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
		    fib_nh->nh_flags & RTNH_F_LINKDOWN)
		if (ignore_link_down && fib_nh->nh_flags & RTNH_F_LINKDOWN)
			break;
		return call_fib4_notifiers(dev_net(fib_nh->nh_dev), event_type,
					   &info.info);
	case FIB_EVENT_NH_DEL:
		if ((in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
		     fib_nh->nh_flags & RTNH_F_LINKDOWN) ||
		if ((ignore_link_down && fib_nh->nh_flags & RTNH_F_LINKDOWN) ||
		    (fib_nh->nh_flags & RTNH_F_DEAD))
			return call_fib4_notifiers(dev_net(fib_nh->nh_dev),
						   event_type, &info.info);
+1 −3
Original line number Diff line number Diff line
@@ -1471,12 +1471,10 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
			continue;
		for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
			const struct fib_nh *nh = &fi->fib_nh[nhsel];
			struct in_device *in_dev = __in_dev_get_rcu(nh->nh_dev);

			if (nh->nh_flags & RTNH_F_DEAD)
				continue;
			if (in_dev &&
			    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
			if (ip_ignore_linkdown(nh->nh_dev) &&
			    nh->nh_flags & RTNH_F_LINKDOWN &&
			    !(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
				continue;