mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
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/20250414172022.242991-1-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
277cc13a5d
@ -45,6 +45,8 @@ struct fib_rule {
|
||||
struct fib_rule_port_range dport_range;
|
||||
u16 sport_mask;
|
||||
u16 dport_mask;
|
||||
u8 iif_is_l3_master;
|
||||
u8 oif_is_l3_master;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,7 @@ struct flowi_common {
|
||||
__u8 flowic_flags;
|
||||
#define FLOWI_FLAG_ANYSRC 0x01
|
||||
#define FLOWI_FLAG_KNOWN_NH 0x02
|
||||
#define FLOWI_FLAG_L3MDEV_OIF 0x04
|
||||
__u32 flowic_secid;
|
||||
kuid_t flowic_uid;
|
||||
__u32 flowic_multipath_hash;
|
||||
|
@ -59,6 +59,20 @@ int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net,
|
||||
int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
|
||||
struct fib_lookup_arg *arg);
|
||||
|
||||
static inline
|
||||
bool l3mdev_fib_rule_iif_match(const struct flowi *fl, int iifindex)
|
||||
{
|
||||
return !(fl->flowi_flags & FLOWI_FLAG_L3MDEV_OIF) &&
|
||||
fl->flowi_l3mdev == iifindex;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool l3mdev_fib_rule_oif_match(const struct flowi *fl, int oifindex)
|
||||
{
|
||||
return fl->flowi_flags & FLOWI_FLAG_L3MDEV_OIF &&
|
||||
fl->flowi_l3mdev == oifindex;
|
||||
}
|
||||
|
||||
void l3mdev_update_flow(struct net *net, struct flowi *fl);
|
||||
|
||||
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,
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool l3mdev_fib_rule_iif_match(const struct flowi *fl, int iifindex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool l3mdev_fib_rule_oif_match(const struct flowi *fl, int oifindex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline
|
||||
void l3mdev_update_flow(struct net *net, struct flowi *fl)
|
||||
{
|
||||
|
@ -257,6 +257,24 @@ static int nla_put_port_range(struct sk_buff *skb, int attrtype,
|
||||
return nla_put(skb, attrtype, sizeof(*range), range);
|
||||
}
|
||||
|
||||
static bool fib_rule_iif_match(const struct fib_rule *rule, int iifindex,
|
||||
const struct flowi *fl)
|
||||
{
|
||||
u8 iif_is_l3_master = READ_ONCE(rule->iif_is_l3_master);
|
||||
|
||||
return iif_is_l3_master ? l3mdev_fib_rule_iif_match(fl, iifindex) :
|
||||
fl->flowi_iif == iifindex;
|
||||
}
|
||||
|
||||
static bool fib_rule_oif_match(const struct fib_rule *rule, int oifindex,
|
||||
const struct flowi *fl)
|
||||
{
|
||||
u8 oif_is_l3_master = READ_ONCE(rule->oif_is_l3_master);
|
||||
|
||||
return oif_is_l3_master ? l3mdev_fib_rule_oif_match(fl, oifindex) :
|
||||
fl->flowi_oif == oifindex;
|
||||
}
|
||||
|
||||
static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
|
||||
struct flowi *fl, int flags,
|
||||
struct fib_lookup_arg *arg)
|
||||
@ -264,11 +282,11 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
|
||||
int iifindex, oifindex, ret = 0;
|
||||
|
||||
iifindex = READ_ONCE(rule->iifindex);
|
||||
if (iifindex && (iifindex != fl->flowi_iif))
|
||||
if (iifindex && !fib_rule_iif_match(rule, iifindex, fl))
|
||||
goto out;
|
||||
|
||||
oifindex = READ_ONCE(rule->oifindex);
|
||||
if (oifindex && (oifindex != fl->flowi_oif))
|
||||
if (oifindex && !fib_rule_oif_match(rule, oifindex, fl))
|
||||
goto out;
|
||||
|
||||
if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask)
|
||||
@ -736,16 +754,20 @@ static int fib_nl2rule_rtnl(struct fib_rule *nlrule,
|
||||
struct net_device *dev;
|
||||
|
||||
dev = __dev_get_by_name(nlrule->fr_net, nlrule->iifname);
|
||||
if (dev)
|
||||
if (dev) {
|
||||
nlrule->iifindex = dev->ifindex;
|
||||
nlrule->iif_is_l3_master = netif_is_l3_master(dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[FRA_OIFNAME]) {
|
||||
struct net_device *dev;
|
||||
|
||||
dev = __dev_get_by_name(nlrule->fr_net, nlrule->oifname);
|
||||
if (dev)
|
||||
if (dev) {
|
||||
nlrule->oifindex = dev->ifindex;
|
||||
nlrule->oif_is_l3_master = netif_is_l3_master(dev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1336,11 +1358,17 @@ static void attach_rules(struct list_head *rules, struct net_device *dev)
|
||||
|
||||
list_for_each_entry(rule, rules, list) {
|
||||
if (rule->iifindex == -1 &&
|
||||
strcmp(dev->name, rule->iifname) == 0)
|
||||
strcmp(dev->name, rule->iifname) == 0) {
|
||||
WRITE_ONCE(rule->iifindex, dev->ifindex);
|
||||
WRITE_ONCE(rule->iif_is_l3_master,
|
||||
netif_is_l3_master(dev));
|
||||
}
|
||||
if (rule->oifindex == -1 &&
|
||||
strcmp(dev->name, rule->oifname) == 0)
|
||||
strcmp(dev->name, rule->oifname) == 0) {
|
||||
WRITE_ONCE(rule->oifindex, dev->ifindex);
|
||||
WRITE_ONCE(rule->oif_is_l3_master,
|
||||
netif_is_l3_master(dev));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1349,10 +1377,14 @@ static void detach_rules(struct list_head *rules, struct net_device *dev)
|
||||
struct fib_rule *rule;
|
||||
|
||||
list_for_each_entry(rule, rules, list) {
|
||||
if (rule->iifindex == dev->ifindex)
|
||||
if (rule->iifindex == dev->ifindex) {
|
||||
WRITE_ONCE(rule->iifindex, -1);
|
||||
if (rule->oifindex == dev->ifindex)
|
||||
WRITE_ONCE(rule->iif_is_l3_master, false);
|
||||
}
|
||||
if (rule->oifindex == dev->ifindex) {
|
||||
WRITE_ONCE(rule->oifindex, -1);
|
||||
WRITE_ONCE(rule->oif_is_l3_master, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,8 +277,10 @@ void l3mdev_update_flow(struct net *net, struct flowi *fl)
|
||||
if (fl->flowi_oif) {
|
||||
dev = dev_get_by_index_rcu(net, fl->flowi_oif);
|
||||
if (dev) {
|
||||
if (!fl->flowi_l3mdev)
|
||||
if (!fl->flowi_l3mdev) {
|
||||
fl->flowi_l3mdev = l3mdev_master_ifindex_rcu(dev);
|
||||
fl->flowi_flags |= FLOWI_FLAG_L3MDEV_OIF;
|
||||
}
|
||||
|
||||
/* oif set to L3mdev directs lookup to its table;
|
||||
* reset to avoid oif match in fib_lookup
|
||||
|
@ -359,6 +359,23 @@ fib_rule6_test()
|
||||
"$getnomatch" "iif flowlabel masked redirect to table" \
|
||||
"iif flowlabel masked no redirect to table"
|
||||
fi
|
||||
|
||||
$IP link show dev $DEV | grep -q vrf0
|
||||
if [ $? -eq 0 ]; then
|
||||
match="oif vrf0"
|
||||
getmatch="oif $DEV"
|
||||
getnomatch="oif lo"
|
||||
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
|
||||
"$getnomatch" "VRF oif redirect to table" \
|
||||
"VRF oif no redirect to table"
|
||||
|
||||
match="from $SRC_IP6 iif vrf0"
|
||||
getmatch="from $SRC_IP6 iif $DEV"
|
||||
getnomatch="from $SRC_IP6 iif lo"
|
||||
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
|
||||
"$getnomatch" "VRF iif redirect to table" \
|
||||
"VRF iif no redirect to table"
|
||||
fi
|
||||
}
|
||||
|
||||
fib_rule6_vrf_test()
|
||||
@ -635,6 +652,23 @@ fib_rule4_test()
|
||||
"$getnomatch" "iif dscp masked redirect to table" \
|
||||
"iif dscp masked no redirect to table"
|
||||
fi
|
||||
|
||||
$IP link show dev $DEV | grep -q vrf0
|
||||
if [ $? -eq 0 ]; then
|
||||
match="oif vrf0"
|
||||
getmatch="oif $DEV"
|
||||
getnomatch="oif lo"
|
||||
fib_rule4_test_match_n_redirect "$match" "$getmatch" \
|
||||
"$getnomatch" "VRF oif redirect to table" \
|
||||
"VRF oif no redirect to table"
|
||||
|
||||
match="from $SRC_IP iif vrf0"
|
||||
getmatch="from $SRC_IP iif $DEV"
|
||||
getnomatch="from $SRC_IP iif lo"
|
||||
fib_rule4_test_match_n_redirect "$match" "$getmatch" \
|
||||
"$getnomatch" "VRF iif redirect to table" \
|
||||
"VRF iif no redirect to table"
|
||||
fi
|
||||
}
|
||||
|
||||
fib_rule4_vrf_test()
|
||||
|
Loading…
x
Reference in New Issue
Block a user