@@ -33,6 +33,7 @@ static const struct nla_policy rtm_nh_policy[NHA_MAX + 1] = {
3333	[NHA_ENCAP ]		=  { .type  =  NLA_NESTED  },
3434	[NHA_GROUPS ]		=  { .type  =  NLA_FLAG  },
3535	[NHA_MASTER ]		=  { .type  =  NLA_U32  },
36+ 	[NHA_FDB ]		=  { .type  =  NLA_FLAG  },
3637};
3738
3839static  unsigned int   nh_dev_hashfn (unsigned int   val )
@@ -107,6 +108,7 @@ static struct nexthop *nexthop_alloc(void)
107108		INIT_LIST_HEAD (& nh -> fi_list );
108109		INIT_LIST_HEAD (& nh -> f6i_list );
109110		INIT_LIST_HEAD (& nh -> grp_list );
111+ 		INIT_LIST_HEAD (& nh -> fdb_list );
110112	}
111113	return  nh ;
112114}
@@ -227,6 +229,9 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
227229	if  (nla_put_u32 (skb , NHA_ID , nh -> id ))
228230		goto nla_put_failure ;
229231
232+ 	if  (nh -> is_fdb_nh  &&  nla_put_flag (skb , NHA_FDB ))
233+ 		goto nla_put_failure ;
234+ 
230235	if  (nh -> is_group ) {
231236		struct  nh_group  * nhg  =  rtnl_dereference (nh -> nh_grp );
232237
@@ -241,7 +246,7 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
241246		if  (nla_put_flag (skb , NHA_BLACKHOLE ))
242247			goto nla_put_failure ;
243248		goto out ;
244- 	} else  {
249+ 	} else  if  (! nh -> is_fdb_nh )  {
245250		const  struct  net_device  * dev ;
246251
247252		dev  =  nhi -> fib_nhc .nhc_dev ;
@@ -387,12 +392,35 @@ static bool valid_group_nh(struct nexthop *nh, unsigned int npaths,
387392	return  true;
388393}
389394
395+ static  int  nh_check_attr_fdb_group (struct  nexthop  * nh , u8  * nh_family ,
396+ 				   struct  netlink_ext_ack  * extack )
397+ {
398+ 	struct  nh_info  * nhi ;
399+ 
400+ 	if  (!nh -> is_fdb_nh ) {
401+ 		NL_SET_ERR_MSG (extack , "FDB nexthop group can only have fdb nexthops" );
402+ 		return  - EINVAL ;
403+ 	}
404+ 
405+ 	nhi  =  rtnl_dereference (nh -> nh_info );
406+ 	if  (* nh_family  ==  AF_UNSPEC ) {
407+ 		* nh_family  =  nhi -> family ;
408+ 	} else  if  (* nh_family  !=  nhi -> family ) {
409+ 		NL_SET_ERR_MSG (extack , "FDB nexthop group cannot have mixed family nexthops" );
410+ 		return  - EINVAL ;
411+ 	}
412+ 
413+ 	return  0 ;
414+ }
415+ 
390416static  int  nh_check_attr_group (struct  net  * net , struct  nlattr  * tb [],
391417			       struct  netlink_ext_ack  * extack )
392418{
393419	unsigned int   len  =  nla_len (tb [NHA_GROUP ]);
420+ 	u8  nh_family  =  AF_UNSPEC ;
394421	struct  nexthop_grp  * nhg ;
395422	unsigned int   i , j ;
423+ 	u8  nhg_fdb  =  0 ;
396424
397425	if  (len  &  (sizeof (struct  nexthop_grp ) -  1 )) {
398426		NL_SET_ERR_MSG (extack ,
@@ -421,6 +449,8 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
421449		}
422450	}
423451
452+ 	if  (tb [NHA_FDB ])
453+ 		nhg_fdb  =  1 ;
424454	nhg  =  nla_data (tb [NHA_GROUP ]);
425455	for  (i  =  0 ; i  <  len ; ++ i ) {
426456		struct  nexthop  * nh ;
@@ -432,11 +462,20 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
432462		}
433463		if  (!valid_group_nh (nh , len , extack ))
434464			return  - EINVAL ;
465+ 
466+ 		if  (nhg_fdb  &&  nh_check_attr_fdb_group (nh , & nh_family , extack ))
467+ 			return  - EINVAL ;
468+ 
469+ 		if  (!nhg_fdb  &&  nh -> is_fdb_nh ) {
470+ 			NL_SET_ERR_MSG (extack , "Non FDB nexthop group cannot have fdb nexthops" );
471+ 			return  - EINVAL ;
472+ 		}
435473	}
436474	for  (i  =  NHA_GROUP  +  1 ; i  <  __NHA_MAX ; ++ i ) {
437475		if  (!tb [i ])
438476			continue ;
439- 
477+ 		if  (tb [NHA_FDB ])
478+ 			continue ;
440479		NL_SET_ERR_MSG (extack ,
441480			       "No other attributes can be set in nexthop groups" );
442481		return  - EINVAL ;
@@ -495,6 +534,9 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
495534		if  (hash  >  atomic_read (& nhge -> upper_bound ))
496535			continue ;
497536
537+ 		if  (nhge -> nh -> is_fdb_nh )
538+ 			return  nhge -> nh ;
539+ 
498540		/* nexthops always check if it is good and does 
499541		 * not rely on a sysctl for this behavior 
500542		 */ 
@@ -564,6 +606,11 @@ int fib6_check_nexthop(struct nexthop *nh, struct fib6_config *cfg,
564606{
565607	struct  nh_info  * nhi ;
566608
609+ 	if  (nh -> is_fdb_nh ) {
610+ 		NL_SET_ERR_MSG (extack , "Route cannot point to a fdb nexthop" );
611+ 		return  - EINVAL ;
612+ 	}
613+ 
567614	/* fib6_src is unique to a fib6_info and limits the ability to cache 
568615	 * routes in fib6_nh within a nexthop that is potentially shared 
569616	 * across multiple fib entries. If the config wants to use source 
@@ -640,6 +687,12 @@ int fib_check_nexthop(struct nexthop *nh, u8 scope,
640687{
641688	int  err  =  0 ;
642689
690+ 	if  (nh -> is_fdb_nh ) {
691+ 		NL_SET_ERR_MSG (extack , "Route cannot point to a fdb nexthop" );
692+ 		err  =  - EINVAL ;
693+ 		goto out ;
694+ 	}
695+ 
643696	if  (nh -> is_group ) {
644697		struct  nh_group  * nhg ;
645698
@@ -1125,6 +1178,9 @@ static struct nexthop *nexthop_create_group(struct net *net,
11251178		nh_group_rebalance (nhg );
11261179	}
11271180
1181+ 	if  (cfg -> nh_fdb )
1182+ 		nh -> is_fdb_nh  =  1 ;
1183+ 
11281184	rcu_assign_pointer (nh -> nh_grp , nhg );
11291185
11301186	return  nh ;
@@ -1152,7 +1208,7 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
11521208		.fc_encap  =  cfg -> nh_encap ,
11531209		.fc_encap_type  =  cfg -> nh_encap_type ,
11541210	};
1155- 	u32  tb_id  =  l3mdev_fib_table (cfg -> dev );
1211+ 	u32  tb_id  =  ( cfg -> dev  ?  l3mdev_fib_table (cfg -> dev ) :  RT_TABLE_MAIN );
11561212	int  err ;
11571213
11581214	err  =  fib_nh_init (net , fib_nh , & fib_cfg , 1 , extack );
@@ -1161,6 +1217,9 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
11611217		goto out ;
11621218	}
11631219
1220+ 	if  (nh -> is_fdb_nh )
1221+ 		goto out ;
1222+ 
11641223	/* sets nh_dev if successful */ 
11651224	err  =  fib_check_nh (net , fib_nh , tb_id , 0 , extack );
11661225	if  (!err ) {
@@ -1186,6 +1245,7 @@ static int nh_create_ipv6(struct net *net,  struct nexthop *nh,
11861245		.fc_flags  =  cfg -> nh_flags ,
11871246		.fc_encap  =  cfg -> nh_encap ,
11881247		.fc_encap_type  =  cfg -> nh_encap_type ,
1248+ 		.fc_is_fdb  =  cfg -> nh_fdb ,
11891249	};
11901250	int  err ;
11911251
@@ -1227,6 +1287,9 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
12271287	nhi -> family  =  cfg -> nh_family ;
12281288	nhi -> fib_nhc .nhc_scope  =  RT_SCOPE_LINK ;
12291289
1290+ 	if  (cfg -> nh_fdb )
1291+ 		nh -> is_fdb_nh  =  1 ;
1292+ 
12301293	if  (cfg -> nh_blackhole ) {
12311294		nhi -> reject_nh  =  1 ;
12321295		cfg -> nh_ifindex  =  net -> loopback_dev -> ifindex ;
@@ -1248,7 +1311,8 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
12481311	}
12491312
12501313	/* add the entry to the device based hash */ 
1251- 	nexthop_devhash_add (net , nhi );
1314+ 	if  (!nh -> is_fdb_nh )
1315+ 		nexthop_devhash_add (net , nhi );
12521316
12531317	rcu_assign_pointer (nh -> nh_info , nhi );
12541318
@@ -1352,6 +1416,19 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
13521416	if  (tb [NHA_ID ])
13531417		cfg -> nh_id  =  nla_get_u32 (tb [NHA_ID ]);
13541418
1419+ 	if  (tb [NHA_FDB ]) {
1420+ 		if  (tb [NHA_OIF ] ||  tb [NHA_BLACKHOLE ] || 
1421+ 		    tb [NHA_ENCAP ]   ||  tb [NHA_ENCAP_TYPE ]) {
1422+ 			NL_SET_ERR_MSG (extack , "Fdb attribute can not be used with encap, oif or blackhole" );
1423+ 			goto out ;
1424+ 		}
1425+ 		if  (nhm -> nh_flags ) {
1426+ 			NL_SET_ERR_MSG (extack , "Unsupported nexthop flags in ancillary header" );
1427+ 			goto out ;
1428+ 		}
1429+ 		cfg -> nh_fdb  =  nla_get_flag (tb [NHA_FDB ]);
1430+ 	}
1431+ 
13551432	if  (tb [NHA_GROUP ]) {
13561433		if  (nhm -> nh_family  !=  AF_UNSPEC ) {
13571434			NL_SET_ERR_MSG (extack , "Invalid family for group" );
@@ -1375,8 +1452,8 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
13751452
13761453	if  (tb [NHA_BLACKHOLE ]) {
13771454		if  (tb [NHA_GATEWAY ] ||  tb [NHA_OIF ] || 
1378- 		    tb [NHA_ENCAP ]   ||  tb [NHA_ENCAP_TYPE ]) {
1379- 			NL_SET_ERR_MSG (extack , "Blackhole attribute can not be used with gateway  or oif " );
1455+ 		    tb [NHA_ENCAP ]   ||  tb [NHA_ENCAP_TYPE ]  ||   tb [ NHA_FDB ] ) {
1456+ 			NL_SET_ERR_MSG (extack , "Blackhole attribute can not be used with gateway, oif, encap  or fdb " );
13801457			goto out ;
13811458		}
13821459
@@ -1385,26 +1462,28 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
13851462		goto out ;
13861463	}
13871464
1388- 	if  (!tb [NHA_OIF ]) {
1389- 		NL_SET_ERR_MSG (extack , "Device attribute required for non-blackhole nexthops" );
1465+ 	if  (!cfg -> nh_fdb   &&  ! tb [NHA_OIF ]) {
1466+ 		NL_SET_ERR_MSG (extack , "Device attribute required for non-blackhole and non-fdb  nexthops" );
13901467		goto out ;
13911468	}
13921469
1393- 	cfg -> nh_ifindex  =  nla_get_u32 (tb [NHA_OIF ]);
1394- 	if  (cfg -> nh_ifindex )
1395- 		cfg -> dev  =  __dev_get_by_index (net , cfg -> nh_ifindex );
1470+ 	if  (!cfg -> nh_fdb  &&  tb [NHA_OIF ]) {
1471+ 		cfg -> nh_ifindex  =  nla_get_u32 (tb [NHA_OIF ]);
1472+ 		if  (cfg -> nh_ifindex )
1473+ 			cfg -> dev  =  __dev_get_by_index (net , cfg -> nh_ifindex );
13961474
1397- 	if  (!cfg -> dev ) {
1398- 		NL_SET_ERR_MSG (extack , "Invalid device index" );
1399- 		goto out ;
1400- 	} else  if  (!(cfg -> dev -> flags  &  IFF_UP )) {
1401- 		NL_SET_ERR_MSG (extack , "Nexthop device is not up" );
1402- 		err  =  - ENETDOWN ;
1403- 		goto out ;
1404- 	} else  if  (!netif_carrier_ok (cfg -> dev )) {
1405- 		NL_SET_ERR_MSG (extack , "Carrier for nexthop device is down" );
1406- 		err  =  - ENETDOWN ;
1407- 		goto out ;
1475+ 		if  (!cfg -> dev ) {
1476+ 			NL_SET_ERR_MSG (extack , "Invalid device index" );
1477+ 			goto out ;
1478+ 		} else  if  (!(cfg -> dev -> flags  &  IFF_UP )) {
1479+ 			NL_SET_ERR_MSG (extack , "Nexthop device is not up" );
1480+ 			err  =  - ENETDOWN ;
1481+ 			goto out ;
1482+ 		} else  if  (!netif_carrier_ok (cfg -> dev )) {
1483+ 			NL_SET_ERR_MSG (extack , "Carrier for nexthop device is down" );
1484+ 			err  =  - ENETDOWN ;
1485+ 			goto out ;
1486+ 		}
14081487	}
14091488
14101489	err  =  - EINVAL ;
@@ -1633,7 +1712,7 @@ static bool nh_dump_filtered(struct nexthop *nh, int dev_idx, int master_idx,
16331712
16341713static  int  nh_valid_dump_req (const  struct  nlmsghdr  * nlh , int  * dev_idx ,
16351714			     int  * master_idx , bool  * group_filter ,
1636- 			     struct  netlink_callback  * cb )
1715+ 			     bool   * fdb_filter ,  struct  netlink_callback  * cb )
16371716{
16381717	struct  netlink_ext_ack  * extack  =  cb -> extack ;
16391718	struct  nlattr  * tb [NHA_MAX  +  1 ];
@@ -1670,6 +1749,9 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
16701749		case  NHA_GROUPS :
16711750			* group_filter  =  true;
16721751			break ;
1752+ 		case  NHA_FDB :
1753+ 			* fdb_filter  =  true;
1754+ 			break ;
16731755		default :
16741756			NL_SET_ERR_MSG (extack , "Unsupported attribute in dump request" );
16751757			return  - EINVAL ;
@@ -1688,17 +1770,17 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
16881770/* rtnl */ 
16891771static  int  rtm_dump_nexthop (struct  sk_buff  * skb , struct  netlink_callback  * cb )
16901772{
1773+ 	bool  group_filter  =  false, fdb_filter  =  false;
16911774	struct  nhmsg  * nhm  =  nlmsg_data (cb -> nlh );
16921775	int  dev_filter_idx  =  0 , master_idx  =  0 ;
16931776	struct  net  * net  =  sock_net (skb -> sk );
16941777	struct  rb_root  * root  =  & net -> nexthop .rb_root ;
1695- 	bool  group_filter  =  false;
16961778	struct  rb_node  * node ;
16971779	int  idx  =  0 , s_idx ;
16981780	int  err ;
16991781
17001782	err  =  nh_valid_dump_req (cb -> nlh , & dev_filter_idx , & master_idx ,
1701- 				& group_filter , cb );
1783+ 				& group_filter , & fdb_filter ,  cb );
17021784	if  (err  <  0 )
17031785		return  err ;
17041786
0 commit comments