@@ -33,6 +33,7 @@ static const struct nla_policy rtm_nh_policy[NHA_MAX + 1] = {
33
33
[NHA_ENCAP ] = { .type = NLA_NESTED },
34
34
[NHA_GROUPS ] = { .type = NLA_FLAG },
35
35
[NHA_MASTER ] = { .type = NLA_U32 },
36
+ [NHA_FDB ] = { .type = NLA_FLAG },
36
37
};
37
38
38
39
static unsigned int nh_dev_hashfn (unsigned int val )
@@ -107,6 +108,7 @@ static struct nexthop *nexthop_alloc(void)
107
108
INIT_LIST_HEAD (& nh -> fi_list );
108
109
INIT_LIST_HEAD (& nh -> f6i_list );
109
110
INIT_LIST_HEAD (& nh -> grp_list );
111
+ INIT_LIST_HEAD (& nh -> fdb_list );
110
112
}
111
113
return nh ;
112
114
}
@@ -227,6 +229,9 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
227
229
if (nla_put_u32 (skb , NHA_ID , nh -> id ))
228
230
goto nla_put_failure ;
229
231
232
+ if (nh -> is_fdb_nh && nla_put_flag (skb , NHA_FDB ))
233
+ goto nla_put_failure ;
234
+
230
235
if (nh -> is_group ) {
231
236
struct nh_group * nhg = rtnl_dereference (nh -> nh_grp );
232
237
@@ -241,7 +246,7 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
241
246
if (nla_put_flag (skb , NHA_BLACKHOLE ))
242
247
goto nla_put_failure ;
243
248
goto out ;
244
- } else {
249
+ } else if (! nh -> is_fdb_nh ) {
245
250
const struct net_device * dev ;
246
251
247
252
dev = nhi -> fib_nhc .nhc_dev ;
@@ -387,12 +392,35 @@ static bool valid_group_nh(struct nexthop *nh, unsigned int npaths,
387
392
return true;
388
393
}
389
394
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
+
390
416
static int nh_check_attr_group (struct net * net , struct nlattr * tb [],
391
417
struct netlink_ext_ack * extack )
392
418
{
393
419
unsigned int len = nla_len (tb [NHA_GROUP ]);
420
+ u8 nh_family = AF_UNSPEC ;
394
421
struct nexthop_grp * nhg ;
395
422
unsigned int i , j ;
423
+ u8 nhg_fdb = 0 ;
396
424
397
425
if (len & (sizeof (struct nexthop_grp ) - 1 )) {
398
426
NL_SET_ERR_MSG (extack ,
@@ -421,6 +449,8 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
421
449
}
422
450
}
423
451
452
+ if (tb [NHA_FDB ])
453
+ nhg_fdb = 1 ;
424
454
nhg = nla_data (tb [NHA_GROUP ]);
425
455
for (i = 0 ; i < len ; ++ i ) {
426
456
struct nexthop * nh ;
@@ -432,11 +462,20 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
432
462
}
433
463
if (!valid_group_nh (nh , len , extack ))
434
464
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
+ }
435
473
}
436
474
for (i = NHA_GROUP + 1 ; i < __NHA_MAX ; ++ i ) {
437
475
if (!tb [i ])
438
476
continue ;
439
-
477
+ if (tb [NHA_FDB ])
478
+ continue ;
440
479
NL_SET_ERR_MSG (extack ,
441
480
"No other attributes can be set in nexthop groups" );
442
481
return - EINVAL ;
@@ -495,6 +534,9 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
495
534
if (hash > atomic_read (& nhge -> upper_bound ))
496
535
continue ;
497
536
537
+ if (nhge -> nh -> is_fdb_nh )
538
+ return nhge -> nh ;
539
+
498
540
/* nexthops always check if it is good and does
499
541
* not rely on a sysctl for this behavior
500
542
*/
@@ -564,6 +606,11 @@ int fib6_check_nexthop(struct nexthop *nh, struct fib6_config *cfg,
564
606
{
565
607
struct nh_info * nhi ;
566
608
609
+ if (nh -> is_fdb_nh ) {
610
+ NL_SET_ERR_MSG (extack , "Route cannot point to a fdb nexthop" );
611
+ return - EINVAL ;
612
+ }
613
+
567
614
/* fib6_src is unique to a fib6_info and limits the ability to cache
568
615
* routes in fib6_nh within a nexthop that is potentially shared
569
616
* across multiple fib entries. If the config wants to use source
@@ -640,6 +687,12 @@ int fib_check_nexthop(struct nexthop *nh, u8 scope,
640
687
{
641
688
int err = 0 ;
642
689
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
+
643
696
if (nh -> is_group ) {
644
697
struct nh_group * nhg ;
645
698
@@ -1125,6 +1178,9 @@ static struct nexthop *nexthop_create_group(struct net *net,
1125
1178
nh_group_rebalance (nhg );
1126
1179
}
1127
1180
1181
+ if (cfg -> nh_fdb )
1182
+ nh -> is_fdb_nh = 1 ;
1183
+
1128
1184
rcu_assign_pointer (nh -> nh_grp , nhg );
1129
1185
1130
1186
return nh ;
@@ -1152,7 +1208,7 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
1152
1208
.fc_encap = cfg -> nh_encap ,
1153
1209
.fc_encap_type = cfg -> nh_encap_type ,
1154
1210
};
1155
- u32 tb_id = l3mdev_fib_table (cfg -> dev );
1211
+ u32 tb_id = ( cfg -> dev ? l3mdev_fib_table (cfg -> dev ) : RT_TABLE_MAIN );
1156
1212
int err ;
1157
1213
1158
1214
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,
1161
1217
goto out ;
1162
1218
}
1163
1219
1220
+ if (nh -> is_fdb_nh )
1221
+ goto out ;
1222
+
1164
1223
/* sets nh_dev if successful */
1165
1224
err = fib_check_nh (net , fib_nh , tb_id , 0 , extack );
1166
1225
if (!err ) {
@@ -1186,6 +1245,7 @@ static int nh_create_ipv6(struct net *net, struct nexthop *nh,
1186
1245
.fc_flags = cfg -> nh_flags ,
1187
1246
.fc_encap = cfg -> nh_encap ,
1188
1247
.fc_encap_type = cfg -> nh_encap_type ,
1248
+ .fc_is_fdb = cfg -> nh_fdb ,
1189
1249
};
1190
1250
int err ;
1191
1251
@@ -1227,6 +1287,9 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
1227
1287
nhi -> family = cfg -> nh_family ;
1228
1288
nhi -> fib_nhc .nhc_scope = RT_SCOPE_LINK ;
1229
1289
1290
+ if (cfg -> nh_fdb )
1291
+ nh -> is_fdb_nh = 1 ;
1292
+
1230
1293
if (cfg -> nh_blackhole ) {
1231
1294
nhi -> reject_nh = 1 ;
1232
1295
cfg -> nh_ifindex = net -> loopback_dev -> ifindex ;
@@ -1248,7 +1311,8 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
1248
1311
}
1249
1312
1250
1313
/* 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 );
1252
1316
1253
1317
rcu_assign_pointer (nh -> nh_info , nhi );
1254
1318
@@ -1352,6 +1416,19 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
1352
1416
if (tb [NHA_ID ])
1353
1417
cfg -> nh_id = nla_get_u32 (tb [NHA_ID ]);
1354
1418
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
+
1355
1432
if (tb [NHA_GROUP ]) {
1356
1433
if (nhm -> nh_family != AF_UNSPEC ) {
1357
1434
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,
1375
1452
1376
1453
if (tb [NHA_BLACKHOLE ]) {
1377
1454
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 " );
1380
1457
goto out ;
1381
1458
}
1382
1459
@@ -1385,26 +1462,28 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
1385
1462
goto out ;
1386
1463
}
1387
1464
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" );
1390
1467
goto out ;
1391
1468
}
1392
1469
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 );
1396
1474
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
+ }
1408
1487
}
1409
1488
1410
1489
err = - EINVAL ;
@@ -1633,7 +1712,7 @@ static bool nh_dump_filtered(struct nexthop *nh, int dev_idx, int master_idx,
1633
1712
1634
1713
static int nh_valid_dump_req (const struct nlmsghdr * nlh , int * dev_idx ,
1635
1714
int * master_idx , bool * group_filter ,
1636
- struct netlink_callback * cb )
1715
+ bool * fdb_filter , struct netlink_callback * cb )
1637
1716
{
1638
1717
struct netlink_ext_ack * extack = cb -> extack ;
1639
1718
struct nlattr * tb [NHA_MAX + 1 ];
@@ -1670,6 +1749,9 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
1670
1749
case NHA_GROUPS :
1671
1750
* group_filter = true;
1672
1751
break ;
1752
+ case NHA_FDB :
1753
+ * fdb_filter = true;
1754
+ break ;
1673
1755
default :
1674
1756
NL_SET_ERR_MSG (extack , "Unsupported attribute in dump request" );
1675
1757
return - EINVAL ;
@@ -1688,17 +1770,17 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
1688
1770
/* rtnl */
1689
1771
static int rtm_dump_nexthop (struct sk_buff * skb , struct netlink_callback * cb )
1690
1772
{
1773
+ bool group_filter = false, fdb_filter = false;
1691
1774
struct nhmsg * nhm = nlmsg_data (cb -> nlh );
1692
1775
int dev_filter_idx = 0 , master_idx = 0 ;
1693
1776
struct net * net = sock_net (skb -> sk );
1694
1777
struct rb_root * root = & net -> nexthop .rb_root ;
1695
- bool group_filter = false;
1696
1778
struct rb_node * node ;
1697
1779
int idx = 0 , s_idx ;
1698
1780
int err ;
1699
1781
1700
1782
err = nh_valid_dump_req (cb -> nlh , & dev_filter_idx , & master_idx ,
1701
- & group_filter , cb );
1783
+ & group_filter , & fdb_filter , cb );
1702
1784
if (err < 0 )
1703
1785
return err ;
1704
1786
0 commit comments