forked from mirrors/linux
		
	ipv4: Prepare for fib6_nh from a nexthop object
Convert more IPv4 code to use fib_nh_common over fib_nh to enable routes to use a fib6_nh based nexthop. In the end, only code not using a nexthop object in a fib_info should directly access fib_nh in a fib_info without checking the famiy and going through fib_nh_common. Those functions will be marked when it is not directly evident. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									5481d73f81
								
							
						
					
					
						commit
						dcb1ecb50e
					
				
					 7 changed files with 69 additions and 37 deletions
				
			
		| 
						 | 
					@ -195,8 +195,8 @@ struct fib_result_nl {
 | 
				
			||||||
#define FIB_TABLE_HASHSZ 2
 | 
					#define FIB_TABLE_HASHSZ 2
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
 | 
					__be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
 | 
				
			||||||
				unsigned char scope);
 | 
									 unsigned char scope);
 | 
				
			||||||
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res);
 | 
					__be32 fib_result_prefsrc(struct net *net, struct fib_result *res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FIB_RES_NHC(res)		((res).nhc)
 | 
					#define FIB_RES_NHC(res)		((res).nhc)
 | 
				
			||||||
| 
						 | 
					@ -455,11 +455,18 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_IP_ROUTE_CLASSID
 | 
					#ifdef CONFIG_IP_ROUTE_CLASSID
 | 
				
			||||||
	struct fib_nh_common *nhc = res->nhc;
 | 
						struct fib_nh_common *nhc = res->nhc;
 | 
				
			||||||
	struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
 | 
					 | 
				
			||||||
#ifdef CONFIG_IP_MULTIPLE_TABLES
 | 
					#ifdef CONFIG_IP_MULTIPLE_TABLES
 | 
				
			||||||
	u32 rtag;
 | 
						u32 rtag;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	*itag = nh->nh_tclassid << 16;
 | 
						if (nhc->nhc_family == AF_INET) {
 | 
				
			||||||
 | 
							struct fib_nh *nh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nh = container_of(nhc, struct fib_nh, nh_common);
 | 
				
			||||||
 | 
							*itag = nh->nh_tclassid << 16;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*itag = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_IP_MULTIPLE_TABLES
 | 
					#ifdef CONFIG_IP_MULTIPLE_TABLES
 | 
				
			||||||
	rtag = res->tclassid;
 | 
						rtag = res->tclassid;
 | 
				
			||||||
	if (*itag == 0)
 | 
						if (*itag == 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,9 +235,9 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
 | 
				
			||||||
	if (table) {
 | 
						if (table) {
 | 
				
			||||||
		ret = RTN_UNICAST;
 | 
							ret = RTN_UNICAST;
 | 
				
			||||||
		if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) {
 | 
							if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) {
 | 
				
			||||||
			struct fib_nh *nh = fib_info_nh(res.fi, 0);
 | 
								struct fib_nh_common *nhc = fib_info_nhc(res.fi, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!dev || dev == nh->fib_nh_dev)
 | 
								if (!dev || dev == nhc->nhc_dev)
 | 
				
			||||||
				ret = res.type;
 | 
									ret = res.type;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -325,18 +325,18 @@ bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev)
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (ret = 0; ret < fib_info_num_path(fi); ret++) {
 | 
						for (ret = 0; ret < fib_info_num_path(fi); ret++) {
 | 
				
			||||||
		const struct fib_nh *nh = fib_info_nh(fi, ret);
 | 
							const struct fib_nh_common *nhc = fib_info_nhc(fi, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (nh->fib_nh_dev == dev) {
 | 
							if (nhc->nhc_dev == dev) {
 | 
				
			||||||
			dev_match = true;
 | 
								dev_match = true;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		} else if (l3mdev_master_ifindex_rcu(nh->fib_nh_dev) == dev->ifindex) {
 | 
							} else if (l3mdev_master_ifindex_rcu(nhc->nhc_dev) == dev->ifindex) {
 | 
				
			||||||
			dev_match = true;
 | 
								dev_match = true;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	if (fib_info_nh(fi, 0)->fib_nh_dev == dev)
 | 
						if (fib_info_nhc(fi, 0)->nhc_dev == dev)
 | 
				
			||||||
		dev_match = true;
 | 
							dev_match = true;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,9 +147,9 @@ static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg
 | 
				
			||||||
	struct net_device *dev = NULL;
 | 
						struct net_device *dev = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (result->fi) {
 | 
						if (result->fi) {
 | 
				
			||||||
		struct fib_nh *nh = fib_info_nh(result->fi, 0);
 | 
							struct fib_nh_common *nhc = fib_info_nhc(result->fi, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dev = nh->fib_nh_dev;
 | 
							dev = nhc->nhc_dev;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* do not accept result if the route does
 | 
						/* do not accept result if the route does
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,9 @@ static unsigned int fib_info_cnt;
 | 
				
			||||||
#define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
 | 
					#define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
 | 
				
			||||||
static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE];
 | 
					static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* for_nexthops and change_nexthops only used when nexthop object
 | 
				
			||||||
 | 
					 * is not set in a fib_info. The logic within can reference fib_nh.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH
 | 
					#ifdef CONFIG_IP_ROUTE_MULTIPATH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define for_nexthops(fi) {						\
 | 
					#define for_nexthops(fi) {						\
 | 
				
			||||||
| 
						 | 
					@ -402,20 +405,23 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* each nexthop is packed in an attribute */
 | 
							/* each nexthop is packed in an attribute */
 | 
				
			||||||
		size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
 | 
							size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
 | 
				
			||||||
 | 
							unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* may contain flow and gateway attribute */
 | 
							/* may contain flow and gateway attribute */
 | 
				
			||||||
		nhsize += 2 * nla_total_size(4);
 | 
							nhsize += 2 * nla_total_size(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* grab encap info */
 | 
							/* grab encap info */
 | 
				
			||||||
		for_nexthops(fi) {
 | 
							for (i = 0; i < fib_info_num_path(fi); i++) {
 | 
				
			||||||
			if (nh->fib_nh_lws) {
 | 
								struct fib_nh_common *nhc = fib_info_nhc(fi, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (nhc->nhc_lwtstate) {
 | 
				
			||||||
				/* RTA_ENCAP_TYPE */
 | 
									/* RTA_ENCAP_TYPE */
 | 
				
			||||||
				nh_encapsize += lwtunnel_get_encap_size(
 | 
									nh_encapsize += lwtunnel_get_encap_size(
 | 
				
			||||||
						nh->fib_nh_lws);
 | 
											nhc->nhc_lwtstate);
 | 
				
			||||||
				/* RTA_ENCAP */
 | 
									/* RTA_ENCAP */
 | 
				
			||||||
				nh_encapsize +=  nla_total_size(2);
 | 
									nh_encapsize +=  nla_total_size(2);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} endfor_nexthops(fi);
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* all nexthops are packed in a nested attribute */
 | 
							/* all nexthops are packed in a nested attribute */
 | 
				
			||||||
		payload += nla_total_size((nhs * nhsize) + nh_encapsize);
 | 
							payload += nla_total_size((nhs * nhsize) + nh_encapsize);
 | 
				
			||||||
| 
						 | 
					@ -1194,9 +1200,15 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
 | 
				
			||||||
	fib_info_hash_free(old_laddrhash, bytes);
 | 
						fib_info_hash_free(old_laddrhash, bytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
 | 
					__be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
 | 
				
			||||||
				unsigned char scope)
 | 
									 unsigned char scope)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct fib_nh *nh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nhc->nhc_family != AF_INET)
 | 
				
			||||||
 | 
							return inet_select_addr(nhc->nhc_dev, 0, scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nh = container_of(nhc, struct fib_nh, nh_common);
 | 
				
			||||||
	nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
 | 
						nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
 | 
				
			||||||
	nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
 | 
						nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1206,16 +1218,19 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
 | 
				
			||||||
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
 | 
					__be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct fib_nh_common *nhc = res->nhc;
 | 
						struct fib_nh_common *nhc = res->nhc;
 | 
				
			||||||
	struct fib_nh *nh;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (res->fi->fib_prefsrc)
 | 
						if (res->fi->fib_prefsrc)
 | 
				
			||||||
		return res->fi->fib_prefsrc;
 | 
							return res->fi->fib_prefsrc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nh = container_of(nhc, struct fib_nh, nh_common);
 | 
						if (nhc->nhc_family == AF_INET) {
 | 
				
			||||||
	if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
 | 
							struct fib_nh *nh;
 | 
				
			||||||
		return nh->nh_saddr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fib_info_update_nh_saddr(net, nh, res->fi->fib_scope);
 | 
							nh = container_of(nhc, struct fib_nh, nh_common);
 | 
				
			||||||
 | 
							if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
 | 
				
			||||||
 | 
								return nh->nh_saddr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
 | 
					static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
 | 
				
			||||||
| 
						 | 
					@ -1397,7 +1412,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	change_nexthops(fi) {
 | 
						change_nexthops(fi) {
 | 
				
			||||||
		fib_info_update_nh_saddr(net, nexthop_nh, fi->fib_scope);
 | 
							fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common,
 | 
				
			||||||
 | 
										  fi->fib_scope);
 | 
				
			||||||
		if (nexthop_nh->fib_nh_gw_family == AF_INET6)
 | 
							if (nexthop_nh->fib_nh_gw_family == AF_INET6)
 | 
				
			||||||
			fi->fib_nh_is_v6 = true;
 | 
								fi->fib_nh_is_v6 = true;
 | 
				
			||||||
	} endfor_nexthops(fi)
 | 
						} endfor_nexthops(fi)
 | 
				
			||||||
| 
						 | 
					@ -1625,17 +1641,22 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
 | 
				
			||||||
	    nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))
 | 
						    nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))
 | 
				
			||||||
		goto nla_put_failure;
 | 
							goto nla_put_failure;
 | 
				
			||||||
	if (nhs == 1) {
 | 
						if (nhs == 1) {
 | 
				
			||||||
		const struct fib_nh *nh = fib_info_nh(fi, 0);
 | 
							const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
 | 
				
			||||||
		unsigned char flags = 0;
 | 
							unsigned char flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (fib_nexthop_info(skb, &nh->nh_common, &flags, false) < 0)
 | 
							if (fib_nexthop_info(skb, nhc, &flags, false) < 0)
 | 
				
			||||||
			goto nla_put_failure;
 | 
								goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rtm->rtm_flags = flags;
 | 
							rtm->rtm_flags = flags;
 | 
				
			||||||
#ifdef CONFIG_IP_ROUTE_CLASSID
 | 
					#ifdef CONFIG_IP_ROUTE_CLASSID
 | 
				
			||||||
		if (nh->nh_tclassid &&
 | 
							if (nhc->nhc_family == AF_INET) {
 | 
				
			||||||
		    nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
 | 
								struct fib_nh *nh;
 | 
				
			||||||
			goto nla_put_failure;
 | 
					
 | 
				
			||||||
 | 
								nh = container_of(nhc, struct fib_nh, nh_common);
 | 
				
			||||||
 | 
								if (nh->nh_tclassid &&
 | 
				
			||||||
 | 
								    nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
 | 
				
			||||||
 | 
									goto nla_put_failure;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (fib_add_multipath(skb, fi) < 0)
 | 
							if (fib_add_multipath(skb, fi) < 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2724,9 +2724,9 @@ static unsigned int fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
 | 
				
			||||||
	if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
 | 
						if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
 | 
				
			||||||
		flags = RTF_REJECT;
 | 
							flags = RTF_REJECT;
 | 
				
			||||||
	if (fi) {
 | 
						if (fi) {
 | 
				
			||||||
		const struct fib_nh *nh = fib_info_nh(fi, 0);
 | 
							const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (nh->fib_nh_gw4)
 | 
							if (nhc->nhc_gw.ipv4)
 | 
				
			||||||
			flags |= RTF_GATEWAY;
 | 
								flags |= RTF_GATEWAY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (mask == htonl(0xFFFFFFFF))
 | 
						if (mask == htonl(0xFFFFFFFF))
 | 
				
			||||||
| 
						 | 
					@ -2773,14 +2773,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 | 
				
			||||||
		seq_setwidth(seq, 127);
 | 
							seq_setwidth(seq, 127);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (fi) {
 | 
							if (fi) {
 | 
				
			||||||
			struct fib_nh *nh = fib_info_nh(fi, 0);
 | 
								struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
 | 
				
			||||||
 | 
								__be32 gw = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (nhc->nhc_gw_family == AF_INET)
 | 
				
			||||||
 | 
									gw = nhc->nhc_gw.ipv4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			seq_printf(seq,
 | 
								seq_printf(seq,
 | 
				
			||||||
				   "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
 | 
									   "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
 | 
				
			||||||
				   "%d\t%08X\t%d\t%u\t%u",
 | 
									   "%d\t%08X\t%d\t%u\t%u",
 | 
				
			||||||
				   nh->fib_nh_dev ? nh->fib_nh_dev->name : "*",
 | 
									   nhc->nhc_dev ? nhc->nhc_dev->name : "*",
 | 
				
			||||||
				   prefix,
 | 
									   prefix, gw, flags, 0, 0,
 | 
				
			||||||
				   nh->fib_nh_gw4, flags, 0, 0,
 | 
					 | 
				
			||||||
				   fi->fib_priority,
 | 
									   fi->fib_priority,
 | 
				
			||||||
				   mask,
 | 
									   mask,
 | 
				
			||||||
				   (fi->fib_advmss ?
 | 
									   (fi->fib_advmss ?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -815,7 +815,8 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
 | 
				
			||||||
	err = fib_check_nh(net, fib_nh, tb_id, 0, extack);
 | 
						err = fib_check_nh(net, fib_nh, tb_id, 0, extack);
 | 
				
			||||||
	if (!err) {
 | 
						if (!err) {
 | 
				
			||||||
		nh->nh_flags = fib_nh->fib_nh_flags;
 | 
							nh->nh_flags = fib_nh->fib_nh_flags;
 | 
				
			||||||
		fib_info_update_nh_saddr(net, fib_nh, fib_nh->fib_nh_scope);
 | 
							fib_info_update_nhc_saddr(net, &fib_nh->nh_common,
 | 
				
			||||||
 | 
										  fib_nh->fib_nh_scope);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		fib_nh_release(net, fib_nh);
 | 
							fib_nh_release(net, fib_nh);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1585,7 +1585,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 | 
				
			||||||
		ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
 | 
							ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_IP_ROUTE_CLASSID
 | 
					#ifdef CONFIG_IP_ROUTE_CLASSID
 | 
				
			||||||
		{
 | 
							if (nhc->nhc_family == AF_INET) {
 | 
				
			||||||
			struct fib_nh *nh;
 | 
								struct fib_nh *nh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			nh = container_of(nhc, struct fib_nh, nh_common);
 | 
								nh = container_of(nhc, struct fib_nh, nh_common);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue