Message ID | 1489651700-3586-2-git-send-email-jiri@resnulli.us |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
On 3/16/17 2:08 AM, Jiri Pirko wrote: > From: Ido Schimmel <idosch@mellanox.com> > > Currently, when non-default (custom) FIB rules are used, devices capable > of layer 3 offloading flush their tables and let the kernel do the > forwarding instead. > > When these devices' drivers are loaded they register to the FIB > notification chain, which lets them know about the existence of any > custom FIB rules. This is done by sending a RULE_ADD notification based > on the value of 'net->ipv4.fib_has_custom_rules'. > > This approach is problematic when VRF offload is taken into account, as > upon the creation of the first VRF netdev, a l3mdev rule is programmed > to direct skbs to the VRF's table. > > Instead of merely reading the above value and sending a single RULE_ADD > notification, we should iterate over all the FIB rules and send a > detailed notification for each, thereby allowing offloading drivers to > sanitize the rules they don't support and potentially flush their > tables. > > While l3mdev rules are uniquely marked, the default rules are not. > Therefore, when they are being notified they might invoke offloading > drivers to unnecessarily flush their tables. > > Solve this by adding an helper to check if a FIB rule is a default rule. > Namely, its selector should match all packets and its action should > point to the local, main or default tables. > > As noted by David Ahern, uniquely marking the default rules is > insufficient. When using VRFs, it's common to avoid false hits by moving > the rule for the local table to just before the main table: > > Default configuration: > $ ip rule show > 0: from all lookup local > 32766: from all lookup main > 32767: from all lookup default > > Common configuration with VRFs: > $ ip rule show > 1000: from all lookup [l3mdev-table] > 32765: from all lookup local > 32766: from all lookup main > 32767: from all lookup default > > Signed-off-by: Ido Schimmel <idosch@mellanox.com> > Signed-off-by: Jiri Pirko <jiri@mellanox.com> > --- > include/net/fib_rules.h | 1 + > include/net/ip_fib.h | 7 +++++++ > net/core/fib_rules.c | 14 ++++++++++++++ > net/ipv4/fib_rules.c | 21 +++++++++++++++++++++ > 4 files changed, 43 insertions(+) > Acked-by: David Ahern <dsa@cumulusnetworks.com>
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 8dbfdf7..1243b9c 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -141,6 +141,7 @@ int fib_rules_lookup(struct fib_rules_ops *, struct flowi *, int flags, struct fib_lookup_arg *); int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table, u32 flags); +bool fib_rule_matchall(const struct fib_rule *rule); int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh); int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh); diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index d9cee96..da6fa7b 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -311,6 +311,11 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp, return err; } +static inline bool fib4_rule_default(const struct fib_rule *rule) +{ + return true; +} + #else /* CONFIG_IP_MULTIPLE_TABLES */ int __net_init fib4_rules_init(struct net *net); void __net_exit fib4_rules_exit(struct net *net); @@ -355,6 +360,8 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp, return err; } +bool fib4_rule_default(const struct fib_rule *rule); + #endif /* CONFIG_IP_MULTIPLE_TABLES */ /* Exported by fib_frontend.c */ diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index b6791d9..816e3cc 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -23,6 +23,20 @@ static const struct fib_kuid_range fib_kuid_range_unset = { KUIDT_INIT(~0), }; +bool fib_rule_matchall(const struct fib_rule *rule) +{ + if (rule->iifindex || rule->oifindex || rule->mark || rule->tun_id || + rule->flags) + return false; + if (rule->suppress_ifgroup != -1 || rule->suppress_prefixlen != -1) + return false; + if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) || + !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end)) + return false; + return true; +} +EXPORT_SYMBOL_GPL(fib_rule_matchall); + int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) { diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 2892109..d531bc9 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -47,6 +47,27 @@ struct fib4_rule { #endif }; +static bool fib4_rule_matchall(const struct fib_rule *rule) +{ + struct fib4_rule *r = container_of(rule, struct fib4_rule, common); + + if (r->dst_len || r->src_len || r->tos) + return false; + return fib_rule_matchall(rule); +} + +bool fib4_rule_default(const struct fib_rule *rule) +{ + if (!fib4_rule_matchall(rule) || rule->action != FR_ACT_TO_TBL || + rule->l3mdev) + return false; + if (rule->table != RT_TABLE_LOCAL && rule->table != RT_TABLE_MAIN && + rule->table != RT_TABLE_DEFAULT) + return false; + return true; +} +EXPORT_SYMBOL_GPL(fib4_rule_default); + int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res, unsigned int flags) {