]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: deduplicate nexthops
authorDavid Lamparter <equinox@opensourcerouting.org>
Tue, 30 May 2017 14:14:42 +0000 (16:14 +0200)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 12 Sep 2017 14:05:07 +0000 (10:05 -0400)
There exists situations where it is possible to have duplicate
nexthops passed from a higher level protocol into zebra.

This code notices this duplication of nexthops and marks
the duplicates as DUPLICATE so we don't attempt to install
it into the kernel.

This is important on *BSD as I understand it because passing
duplicate nexthops will cause the route to be rejected.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
lib/nexthop.c
lib/nexthop.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zebra_rib.c

index 2dba412f452b1140b2fbba5280ab56d1a74a8a2f..ea6a310a4a139ac554a45d19ef392dc5bee61340 100644 (file)
@@ -71,6 +71,39 @@ int nexthop_same_no_recurse(const struct nexthop *next1,
        return 1;
 }
 
+int
+nexthop_same_firsthop (struct nexthop *next1, struct nexthop *next2)
+{
+       int type1 = NEXTHOP_FIRSTHOPTYPE(next1->type);
+       int type2 = NEXTHOP_FIRSTHOPTYPE(next2->type);
+
+       if (type1 != type2)
+               return 0;
+       switch (type1)
+       {
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+               if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
+                       return 0;
+               if (next1->ifindex != next2->ifindex)
+                       return 0;
+               break;
+       case NEXTHOP_TYPE_IFINDEX:
+               if (next1->ifindex != next2->ifindex)
+                       return 0;
+               break;
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+                       return 0;
+               if (next1->ifindex != next2->ifindex)
+                       return 0;
+               break;
+       default:
+               /* do nothing */
+               break;
+       }
+       return 1;
+}
+
 /*
  * nexthop_type_to_str
  */
index 781eb9341349eca685e1550409b937545bfcd205..20b0cd522773b96760b980c75fb0ceb9794d1476 100644 (file)
@@ -50,6 +50,11 @@ enum blackhole_type {
        BLACKHOLE_ADMINPROHIB,
 };
 
+/* IPV[46] -> IPV[46]_IFINDEX */
+#define NEXTHOP_FIRSTHOPTYPE(type) \
+       ((type) == NEXTHOP_TYPE_IFINDEX || (type) == NEXTHOP_TYPE_BLACKHOLE) \
+               ? (type) : ((type) | 1)
+
 /* Nexthop label structure. */
 struct nexthop_label {
        u_int8_t num_labels;
@@ -74,6 +79,10 @@ struct nexthop {
 #define NEXTHOP_FLAG_ONLINK     (1 << 3) /* Nexthop should be installed onlink. */
 #define NEXTHOP_FLAG_MATCHED    (1 << 4) /* Already matched vs a nexthop */
 #define NEXTHOP_FLAG_FILTERED   (1 << 5) /* rmap filtered, used by static only */
+#define NEXTHOP_FLAG_DUPLICATE  (1 << 6) /* nexthop duplicates another active one */
+#define NEXTHOP_IS_ACTIVE(flags) \
+       (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
+               && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
 
        /* Nexthop address */
        union {
@@ -141,6 +150,7 @@ extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type);
 extern int nexthop_same_no_recurse(const struct nexthop *next1,
                                   const struct nexthop *next2);
 extern int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2);
+extern int nexthop_same_firsthop (struct nexthop *next1, struct nexthop *next2);
 
 extern const char *nexthop2str(struct nexthop *nexthop, char *str, int size);
 extern struct nexthop *nexthop_next(struct nexthop *nexthop);
index 12b61853957a2011afc4cee113bc2c43d6ce0e52..e59d5f00fbb917f1821eab68ec30af0e0f83eedc 100644 (file)
@@ -1383,7 +1383,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
                if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
                        continue;
                if (cmd == RTM_NEWROUTE
-                   && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                   && !NEXTHOP_IS_ACTIVE(nexthop->flags))
                        continue;
                if (cmd == RTM_DELROUTE
                    && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
@@ -1438,7 +1438,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
                        }
 
                        if ((cmd == RTM_NEWROUTE
-                            && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                            && NEXTHOP_IS_ACTIVE(nexthop->flags))
                            || (cmd == RTM_DELROUTE
                                && CHECK_FLAG(nexthop->flags,
                                              NEXTHOP_FLAG_FIB))) {
@@ -1521,7 +1521,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
                        }
 
                        if ((cmd == RTM_NEWROUTE
-                            && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                            && NEXTHOP_IS_ACTIVE(nexthop->flags))
                            || (cmd == RTM_DELROUTE
                                && CHECK_FLAG(nexthop->flags,
                                              NEXTHOP_FLAG_FIB))) {
index d8e37a10c310ef2b19300b9bc9b15ee8eb5c9a40..75207a2dde40be0d1ca7954c0bae9edbf2d8c956 100644 (file)
@@ -136,7 +136,7 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re)
                 * other than ADD and DELETE?
                 */
                if ((cmd == RTM_ADD
-                    && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                    && NEXTHOP_IS_ACTIVE(nexthop->flags))
                    || (cmd == RTM_DELETE
                        && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) {
                        if (nexthop->type == NEXTHOP_TYPE_IPV4
@@ -314,7 +314,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re)
                gate = 0;
 
                if ((cmd == RTM_ADD
-                    && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                    && NEXTHOP_IS_ACTIVE(nexthop->flags))
                    || (cmd == RTM_DELETE
 #if 0
              && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
index c4c80b156b796c9c0188b5e027c6ade99feab422..f88e594a990de6ebcd21f94e3c35d5d0b1a9de86 100644 (file)
@@ -1000,8 +1000,24 @@ int rib_install_kernel(struct route_node *rn, struct route_entry *re,
                for (ALL_NEXTHOPS(re->nexthop, nexthop))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
                return ret;
+       } else {
+               struct nexthop *prev;
+
+               for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
+                       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
+                       for (ALL_NEXTHOPS(re->nexthop, prev)) {
+                               if (prev == nexthop)
+                                       break;
+                               if (nexthop_same_firsthop (nexthop, prev))
+                               {
+                                       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
+                                       break;
+                               }
+                       }
+               }
        }
 
+
        /*
         * Make sure we update the FPM any time we send new information to
         * the kernel.