Skip to content

Commit 277cc13

Browse files
committed
Merge branch 'fib_rules-fix-iif-oif-matching-on-l3-master-device'
Ido Schimmel says: ==================== fib_rules: Fix iif / oif matching on L3 master device Patch #1 fixes a recently reported regression regarding FIB rules that match on iif / oif being a VRF device. Patch #2 adds test cases to the FIB rules selftest. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 12f2d03 + f9c8759 commit 277cc13

File tree

6 files changed

+107
-9
lines changed

6 files changed

+107
-9
lines changed

include/net/fib_rules.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct fib_rule {
4545
struct fib_rule_port_range dport_range;
4646
u16 sport_mask;
4747
u16 dport_mask;
48+
u8 iif_is_l3_master;
49+
u8 oif_is_l3_master;
4850
struct rcu_head rcu;
4951
};
5052

include/net/flow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct flowi_common {
3838
__u8 flowic_flags;
3939
#define FLOWI_FLAG_ANYSRC 0x01
4040
#define FLOWI_FLAG_KNOWN_NH 0x02
41+
#define FLOWI_FLAG_L3MDEV_OIF 0x04
4142
__u32 flowic_secid;
4243
kuid_t flowic_uid;
4344
__u32 flowic_multipath_hash;

include/net/l3mdev.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net,
5959
int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
6060
struct fib_lookup_arg *arg);
6161

62+
static inline
63+
bool l3mdev_fib_rule_iif_match(const struct flowi *fl, int iifindex)
64+
{
65+
return !(fl->flowi_flags & FLOWI_FLAG_L3MDEV_OIF) &&
66+
fl->flowi_l3mdev == iifindex;
67+
}
68+
69+
static inline
70+
bool l3mdev_fib_rule_oif_match(const struct flowi *fl, int oifindex)
71+
{
72+
return fl->flowi_flags & FLOWI_FLAG_L3MDEV_OIF &&
73+
fl->flowi_l3mdev == oifindex;
74+
}
75+
6276
void l3mdev_update_flow(struct net *net, struct flowi *fl);
6377

6478
int l3mdev_master_ifindex_rcu(const struct net_device *dev);
@@ -327,6 +341,19 @@ int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
327341
{
328342
return 1;
329343
}
344+
345+
static inline
346+
bool l3mdev_fib_rule_iif_match(const struct flowi *fl, int iifindex)
347+
{
348+
return false;
349+
}
350+
351+
static inline
352+
bool l3mdev_fib_rule_oif_match(const struct flowi *fl, int oifindex)
353+
{
354+
return false;
355+
}
356+
330357
static inline
331358
void l3mdev_update_flow(struct net *net, struct flowi *fl)
332359
{

net/core/fib_rules.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -257,18 +257,36 @@ static int nla_put_port_range(struct sk_buff *skb, int attrtype,
257257
return nla_put(skb, attrtype, sizeof(*range), range);
258258
}
259259

260+
static bool fib_rule_iif_match(const struct fib_rule *rule, int iifindex,
261+
const struct flowi *fl)
262+
{
263+
u8 iif_is_l3_master = READ_ONCE(rule->iif_is_l3_master);
264+
265+
return iif_is_l3_master ? l3mdev_fib_rule_iif_match(fl, iifindex) :
266+
fl->flowi_iif == iifindex;
267+
}
268+
269+
static bool fib_rule_oif_match(const struct fib_rule *rule, int oifindex,
270+
const struct flowi *fl)
271+
{
272+
u8 oif_is_l3_master = READ_ONCE(rule->oif_is_l3_master);
273+
274+
return oif_is_l3_master ? l3mdev_fib_rule_oif_match(fl, oifindex) :
275+
fl->flowi_oif == oifindex;
276+
}
277+
260278
static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
261279
struct flowi *fl, int flags,
262280
struct fib_lookup_arg *arg)
263281
{
264282
int iifindex, oifindex, ret = 0;
265283

266284
iifindex = READ_ONCE(rule->iifindex);
267-
if (iifindex && (iifindex != fl->flowi_iif))
285+
if (iifindex && !fib_rule_iif_match(rule, iifindex, fl))
268286
goto out;
269287

270288
oifindex = READ_ONCE(rule->oifindex);
271-
if (oifindex && (oifindex != fl->flowi_oif))
289+
if (oifindex && !fib_rule_oif_match(rule, oifindex, fl))
272290
goto out;
273291

274292
if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask)
@@ -736,16 +754,20 @@ static int fib_nl2rule_rtnl(struct fib_rule *nlrule,
736754
struct net_device *dev;
737755

738756
dev = __dev_get_by_name(nlrule->fr_net, nlrule->iifname);
739-
if (dev)
757+
if (dev) {
740758
nlrule->iifindex = dev->ifindex;
759+
nlrule->iif_is_l3_master = netif_is_l3_master(dev);
760+
}
741761
}
742762

743763
if (tb[FRA_OIFNAME]) {
744764
struct net_device *dev;
745765

746766
dev = __dev_get_by_name(nlrule->fr_net, nlrule->oifname);
747-
if (dev)
767+
if (dev) {
748768
nlrule->oifindex = dev->ifindex;
769+
nlrule->oif_is_l3_master = netif_is_l3_master(dev);
770+
}
749771
}
750772

751773
return 0;
@@ -1336,11 +1358,17 @@ static void attach_rules(struct list_head *rules, struct net_device *dev)
13361358

13371359
list_for_each_entry(rule, rules, list) {
13381360
if (rule->iifindex == -1 &&
1339-
strcmp(dev->name, rule->iifname) == 0)
1361+
strcmp(dev->name, rule->iifname) == 0) {
13401362
WRITE_ONCE(rule->iifindex, dev->ifindex);
1363+
WRITE_ONCE(rule->iif_is_l3_master,
1364+
netif_is_l3_master(dev));
1365+
}
13411366
if (rule->oifindex == -1 &&
1342-
strcmp(dev->name, rule->oifname) == 0)
1367+
strcmp(dev->name, rule->oifname) == 0) {
13431368
WRITE_ONCE(rule->oifindex, dev->ifindex);
1369+
WRITE_ONCE(rule->oif_is_l3_master,
1370+
netif_is_l3_master(dev));
1371+
}
13441372
}
13451373
}
13461374

@@ -1349,10 +1377,14 @@ static void detach_rules(struct list_head *rules, struct net_device *dev)
13491377
struct fib_rule *rule;
13501378

13511379
list_for_each_entry(rule, rules, list) {
1352-
if (rule->iifindex == dev->ifindex)
1380+
if (rule->iifindex == dev->ifindex) {
13531381
WRITE_ONCE(rule->iifindex, -1);
1354-
if (rule->oifindex == dev->ifindex)
1382+
WRITE_ONCE(rule->iif_is_l3_master, false);
1383+
}
1384+
if (rule->oifindex == dev->ifindex) {
13551385
WRITE_ONCE(rule->oifindex, -1);
1386+
WRITE_ONCE(rule->oif_is_l3_master, false);
1387+
}
13561388
}
13571389
}
13581390

net/l3mdev/l3mdev.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,10 @@ void l3mdev_update_flow(struct net *net, struct flowi *fl)
277277
if (fl->flowi_oif) {
278278
dev = dev_get_by_index_rcu(net, fl->flowi_oif);
279279
if (dev) {
280-
if (!fl->flowi_l3mdev)
280+
if (!fl->flowi_l3mdev) {
281281
fl->flowi_l3mdev = l3mdev_master_ifindex_rcu(dev);
282+
fl->flowi_flags |= FLOWI_FLAG_L3MDEV_OIF;
283+
}
282284

283285
/* oif set to L3mdev directs lookup to its table;
284286
* reset to avoid oif match in fib_lookup

tools/testing/selftests/net/fib_rule_tests.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,23 @@ fib_rule6_test()
359359
"$getnomatch" "iif flowlabel masked redirect to table" \
360360
"iif flowlabel masked no redirect to table"
361361
fi
362+
363+
$IP link show dev $DEV | grep -q vrf0
364+
if [ $? -eq 0 ]; then
365+
match="oif vrf0"
366+
getmatch="oif $DEV"
367+
getnomatch="oif lo"
368+
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
369+
"$getnomatch" "VRF oif redirect to table" \
370+
"VRF oif no redirect to table"
371+
372+
match="from $SRC_IP6 iif vrf0"
373+
getmatch="from $SRC_IP6 iif $DEV"
374+
getnomatch="from $SRC_IP6 iif lo"
375+
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
376+
"$getnomatch" "VRF iif redirect to table" \
377+
"VRF iif no redirect to table"
378+
fi
362379
}
363380

364381
fib_rule6_vrf_test()
@@ -635,6 +652,23 @@ fib_rule4_test()
635652
"$getnomatch" "iif dscp masked redirect to table" \
636653
"iif dscp masked no redirect to table"
637654
fi
655+
656+
$IP link show dev $DEV | grep -q vrf0
657+
if [ $? -eq 0 ]; then
658+
match="oif vrf0"
659+
getmatch="oif $DEV"
660+
getnomatch="oif lo"
661+
fib_rule4_test_match_n_redirect "$match" "$getmatch" \
662+
"$getnomatch" "VRF oif redirect to table" \
663+
"VRF oif no redirect to table"
664+
665+
match="from $SRC_IP iif vrf0"
666+
getmatch="from $SRC_IP iif $DEV"
667+
getnomatch="from $SRC_IP iif lo"
668+
fib_rule4_test_match_n_redirect "$match" "$getmatch" \
669+
"$getnomatch" "VRF iif redirect to table" \
670+
"VRF iif no redirect to table"
671+
fi
638672
}
639673

640674
fib_rule4_vrf_test()

0 commit comments

Comments
 (0)