diff options
Diffstat (limited to 'include/net/nexthop.h')
| -rw-r--r-- | include/net/nexthop.h | 100 | 
1 files changed, 84 insertions, 16 deletions
| diff --git a/include/net/nexthop.h b/include/net/nexthop.h index c440ccc861fc..8c9f1a718859 100644 --- a/include/net/nexthop.h +++ b/include/net/nexthop.h @@ -70,6 +70,7 @@ struct nh_grp_entry {  };  struct nh_group { +	struct nh_group		*spare; /* spare group for removals */  	u16			num_nh;  	bool			mpath;  	bool			has_v4; @@ -136,21 +137,20 @@ static inline unsigned int nexthop_num_path(const struct nexthop *nh)  {  	unsigned int rc = 1; -	if (nexthop_is_multipath(nh)) { +	if (nh->is_group) {  		struct nh_group *nh_grp;  		nh_grp = rcu_dereference_rtnl(nh->nh_grp); -		rc = nh_grp->num_nh; +		if (nh_grp->mpath) +			rc = nh_grp->num_nh;  	}  	return rc;  }  static inline -struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel) +struct nexthop *nexthop_mpath_select(const struct nh_group *nhg, int nhsel)  { -	const struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp); -  	/* for_nexthops macros in fib_semantics.c grabs a pointer to  	 * the nexthop before checking nhsel  	 */ @@ -185,12 +185,14 @@ static inline bool nexthop_is_blackhole(const struct nexthop *nh)  {  	const struct nh_info *nhi; -	if (nexthop_is_multipath(nh)) { -		if (nexthop_num_path(nh) > 1) -			return false; -		nh = nexthop_mpath_select(nh, 0); -		if (!nh) +	if (nh->is_group) { +		struct nh_group *nh_grp; + +		nh_grp = rcu_dereference_rtnl(nh->nh_grp); +		if (nh_grp->num_nh > 1)  			return false; + +		nh = nh_grp->nh_entries[0].nh;  	}  	nhi = rcu_dereference_rtnl(nh->nh_info); @@ -216,16 +218,79 @@ struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)  	BUILD_BUG_ON(offsetof(struct fib_nh, nh_common) != 0);  	BUILD_BUG_ON(offsetof(struct fib6_nh, nh_common) != 0); -	if (nexthop_is_multipath(nh)) { -		nh = nexthop_mpath_select(nh, nhsel); -		if (!nh) -			return NULL; +	if (nh->is_group) { +		struct nh_group *nh_grp; + +		nh_grp = rcu_dereference_rtnl(nh->nh_grp); +		if (nh_grp->mpath) { +			nh = nexthop_mpath_select(nh_grp, nhsel); +			if (!nh) +				return NULL; +		}  	}  	nhi = rcu_dereference_rtnl(nh->nh_info);  	return &nhi->fib_nhc;  } +/* called from fib_table_lookup with rcu_lock */ +static inline +struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh, +					     int fib_flags, +					     const struct flowi4 *flp, +					     int *nhsel) +{ +	struct nh_info *nhi; + +	if (nh->is_group) { +		struct nh_group *nhg = rcu_dereference(nh->nh_grp); +		int i; + +		for (i = 0; i < nhg->num_nh; i++) { +			struct nexthop *nhe = nhg->nh_entries[i].nh; + +			nhi = rcu_dereference(nhe->nh_info); +			if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) { +				*nhsel = i; +				return &nhi->fib_nhc; +			} +		} +	} else { +		nhi = rcu_dereference(nh->nh_info); +		if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) { +			*nhsel = 0; +			return &nhi->fib_nhc; +		} +	} + +	return NULL; +} + +static inline bool nexthop_uses_dev(const struct nexthop *nh, +				    const struct net_device *dev) +{ +	struct nh_info *nhi; + +	if (nh->is_group) { +		struct nh_group *nhg = rcu_dereference(nh->nh_grp); +		int i; + +		for (i = 0; i < nhg->num_nh; i++) { +			struct nexthop *nhe = nhg->nh_entries[i].nh; + +			nhi = rcu_dereference(nhe->nh_info); +			if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev)) +				return true; +		} +	} else { +		nhi = rcu_dereference(nh->nh_info); +		if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev)) +			return true; +	} + +	return false; +} +  static inline unsigned int fib_info_num_path(const struct fib_info *fi)  {  	if (unlikely(fi->nh)) @@ -263,8 +328,11 @@ static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)  {  	struct nh_info *nhi; -	if (nexthop_is_multipath(nh)) { -		nh = nexthop_mpath_select(nh, 0); +	if (nh->is_group) { +		struct nh_group *nh_grp; + +		nh_grp = rcu_dereference_rtnl(nh->nh_grp); +		nh = nexthop_mpath_select(nh_grp, 0);  		if (!nh)  			return NULL;  	} |