]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ipv4: nexthop version of fib_info_nh_uses_dev
authorDavid Ahern <dsahern@gmail.com>
Tue, 26 May 2020 18:56:18 +0000 (12:56 -0600)
committerDavid S. Miller <davem@davemloft.net>
Tue, 26 May 2020 23:06:07 +0000 (16:06 -0700)
Similar to the last path, need to fix fib_info_nh_uses_dev for
external nexthops to avoid referencing multiple nh_grp structs.
Move the device check in fib_info_nh_uses_dev to a helper and
create a nexthop version that is called if the fib_info uses an
external nexthop.

Fixes: f770d5650da8 ("nexthop: Add support for nexthop groups")
Signed-off-by: David Ahern <dsahern@gmail.com>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip_fib.h
include/net/nexthop.h
net/ipv4/fib_frontend.c

index 771ce068bc966e5602601f002f25204475b1e5e1..2ec062aaa9782b71cfd75279c8347d90cff14e81 100644 (file)
@@ -447,6 +447,16 @@ static inline int fib_num_tclassid_users(struct net *net)
 #endif
 int fib_unmerge(struct net *net);
 
+static inline bool nhc_l3mdev_matches_dev(const struct fib_nh_common *nhc,
+const struct net_device *dev)
+{
+       if (nhc->nhc_dev == dev ||
+           l3mdev_master_ifindex_rcu(nhc->nhc_dev) == dev->ifindex)
+               return true;
+
+       return false;
+}
+
 /* Exported by fib_semantics.c */
 int ip_fib_check_default(__be32 gw, struct net_device *dev);
 int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force);
index 9414ae46fc1c0f41bc803ecf4a9650cc78f55880..8c9f1a7188591327710c112c0c8db8bbb9ca19fb 100644 (file)
@@ -266,6 +266,31 @@ struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
        return NULL;
 }
 
+static inline bool nexthop_uses_dev(const struct nexthop *nh,
+                                   const struct net_device *dev)
+{
+       struct nh_info *nhi;
+
+       if (nh->is_group) {
+               struct nh_group *nhg = rcu_dereference(nh->nh_grp);
+               int i;
+
+               for (i = 0; i < nhg->num_nh; i++) {
+                       struct nexthop *nhe = nhg->nh_entries[i].nh;
+
+                       nhi = rcu_dereference(nhe->nh_info);
+                       if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
+                               return true;
+               }
+       } else {
+               nhi = rcu_dereference(nh->nh_info);
+               if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
+                       return true;
+       }
+
+       return false;
+}
+
 static inline unsigned int fib_info_num_path(const struct fib_info *fi)
 {
        if (unlikely(fi->nh))
index 1bf9da3a75f921738b28f17cc1543fbf84993845..41079490a118162e992e44e272b72f3b688093c9 100644 (file)
@@ -309,17 +309,18 @@ bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev)
 {
        bool dev_match = false;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-       int ret;
+       if (unlikely(fi->nh)) {
+               dev_match = nexthop_uses_dev(fi->nh, dev);
+       } else {
+               int ret;
 
-       for (ret = 0; ret < fib_info_num_path(fi); ret++) {
-               const struct fib_nh_common *nhc = fib_info_nhc(fi, ret);
+               for (ret = 0; ret < fib_info_num_path(fi); ret++) {
+                       const struct fib_nh_common *nhc = fib_info_nhc(fi, ret);
 
-               if (nhc->nhc_dev == dev) {
-                       dev_match = true;
-                       break;
-               } else if (l3mdev_master_ifindex_rcu(nhc->nhc_dev) == dev->ifindex) {
-                       dev_match = true;
-                       break;
+                       if (nhc_l3mdev_matches_dev(nhc, dev)) {
+                               dev_match = true;
+                               break;
+                       }
                }
        }
 #else