]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: Handle if up/down and vrf enable/disable events
authorDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 10 Apr 2018 19:57:09 +0000 (15:57 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 17 Apr 2018 22:44:33 +0000 (18:44 -0400)
Properly notice when we get if up/down and vrf enable/disable
events and attempt to properly install nexthops as they
come in.

Ticket: CM20489
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
lib/nexthop_group.c
lib/nexthop_group.h
lib/vrf.c
lib/zclient.c

index dc234bc45d67d6abfb957fb960d9a190fc59ad7b..5ac38d66853cc91a09aa4ebca1ff008c8ba00ad5 100644 (file)
@@ -331,75 +331,78 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
        XFREE(MTYPE_TMP, nh);
 }
 
-DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
-      "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
-      NO_STR
-      "Specify one of the nexthops in this ECMP group\n"
-      "v4 Address\n"
-      "v6 Address\n"
-      "Interface to use\n"
-      "If the nexthop is in a different vrf tell us\n"
-      "The nexthop-vrf Name\n")
+static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
+                                       const union sockunion *addr,
+                                       const char *intf, const char *name)
 {
-       VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
        struct vrf *vrf;
-       struct nexthop nhop;
-       struct nexthop *nh;
+
+       memset(nhop, 0, sizeof(*nhop));
 
        if (name)
                vrf = vrf_lookup_by_name(name);
        else
                vrf = vrf_lookup_by_id(VRF_DEFAULT);
 
-       if (!vrf) {
-               vty_out(vty, "Specified: %s is non-existent\n", name);
-               return CMD_WARNING;
-       }
+       if (!vrf)
+               return false;
 
-       memset(&nhop, 0, sizeof(nhop));
-       nhop.vrf_id = vrf->vrf_id;
+       nhop->vrf_id = vrf->vrf_id;
 
        if (addr->sa.sa_family == AF_INET) {
-               nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+               nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
                if (intf) {
-                       nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop.ifindex == IFINDEX_INTERNAL) {
-                               vty_out(vty,
-                                       "Specified Intf %s does not exist in vrf: %s\n",
-                                       intf, vrf->name);
-                               return CMD_WARNING;
-                       }
+                       nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+                       if (nhop->ifindex == IFINDEX_INTERNAL)
+                               return false;
                } else
-                       nhop.type = NEXTHOP_TYPE_IPV4;
+                       nhop->type = NEXTHOP_TYPE_IPV4;
        } else {
-               memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
+               memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
                if (intf) {
-                       nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop.ifindex == IFINDEX_INTERNAL) {
-                               vty_out(vty,
-                                       "Specified Intf %s does not exist in vrf: %s\n",
-                                       intf, vrf->name);
-                               return CMD_WARNING;
-                       }
-               } else {
-                       if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
-                               vty_out(vty,
-                                       "Specified a v6 LL with no interface, rejecting\n");
-                               return CMD_WARNING_CONFIG_FAILED;
-                       }
-                       nhop.type = NEXTHOP_TYPE_IPV6;
-               }
+                       nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+                       if (nhop->ifindex == IFINDEX_INTERNAL)
+                               return false;
+               } else
+                       nhop->type = NEXTHOP_TYPE_IPV6;
+       }
+
+       return true;
+}
+
+DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
+      "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+      NO_STR
+      "Specify one of the nexthops in this ECMP group\n"
+      "v4 Address\n"
+      "v6 Address\n"
+      "Interface to use\n"
+      "If the nexthop is in a different vrf tell us\n"
+      "The nexthop-vrf Name\n")
+{
+       VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+       struct nexthop nhop;
+       struct nexthop *nh;
+       bool legal;
+
+       legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
+
+       if (nhop.type == NEXTHOP_TYPE_IPV6
+           && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+               vty_out(vty,
+                       "Specified a v6 LL with no interface, rejecting\n");
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        nh = nexthop_exists(&nhgc->nhg, &nhop);
 
        if (no) {
+               nexthop_group_unsave_nhop(nhgc, name, addr, intf);
                if (nh) {
                        nexthop_del(&nhgc->nhg, nh);
 
-                       nexthop_group_unsave_nhop(nhgc, name, addr, intf);
                        if (nhg_hooks.del_nexthop)
                                nhg_hooks.del_nexthop(nhgc, nh);
 
@@ -407,14 +410,16 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
                }
        } else if (!nh) {
                /* must be adding new nexthop since !no and !nexthop_exists */
-               nh = nexthop_new();
+               if (legal) {
+                       nh = nexthop_new();
 
-               memcpy(nh, &nhop, sizeof(nhop));
-               nexthop_add(&nhgc->nhg.nexthop, nh);
+                       memcpy(nh, &nhop, sizeof(nhop));
+                       nexthop_add(&nhgc->nhg.nexthop, nh);
+               }
 
                nexthop_group_save_nhop(nhgc, name, addr, intf);
 
-               if (nhg_hooks.add_nexthop)
+               if (legal && nhg_hooks.add_nexthop)
                        nhg_hooks.add_nexthop(nhgc, nh);
        }
 
@@ -504,6 +509,152 @@ static int nexthop_group_write(struct vty *vty)
        return 1;
 }
 
+void nexthop_group_enable_vrf(struct vrf *vrf)
+{
+       struct nexthop_group_cmd *nhgc;
+       struct nexthop_hold *nhh;
+
+       RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+
+               for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+                       struct nexthop nhop;
+                       struct nexthop *nh;
+
+                       if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+                                                        nhh->intf,
+                                                        nhh->nhvrf_name))
+                               continue;
+
+                       nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+                       if (nh)
+                               continue;
+
+                       if (nhop.vrf_id != vrf->vrf_id)
+                               continue;
+
+                       nh = nexthop_new();
+
+                       memcpy(nh, &nhop, sizeof(nhop));
+                       nexthop_add(&nhgc->nhg.nexthop, nh);
+
+                       if (nhg_hooks.add_nexthop)
+                               nhg_hooks.add_nexthop(nhgc, nh);
+               }
+       }
+}
+
+void nexthop_group_disable_vrf(struct vrf *vrf)
+{
+       struct nexthop_group_cmd *nhgc;
+       struct nexthop_hold *nhh;
+
+       RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+
+               for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+                       struct nexthop nhop;
+                       struct nexthop *nh;
+
+                       if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+                                                        nhh->intf,
+                                                        nhh->nhvrf_name))
+                               continue;
+
+                       nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+                       if (!nh)
+                               continue;
+
+                       if (nh->vrf_id != vrf->vrf_id)
+                               continue;
+
+                       nexthop_del(&nhgc->nhg, nh);
+
+                       if (nhg_hooks.del_nexthop)
+                               nhg_hooks.del_nexthop(nhgc, nh);
+
+                       nexthop_free(nh);
+               }
+       }
+}
+
+void nexthop_group_interface_state_change(struct interface *ifp,
+                                         ifindex_t oldifindex)
+{
+       struct nexthop_group_cmd *nhgc;
+       struct nexthop_hold *nhh;
+
+       RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+               struct nexthop *nh;
+
+               if (if_is_up(ifp)) {
+                       for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+                               struct nexthop nhop;
+
+                               if (!nexthop_group_parse_nexthop(
+                                           &nhop, &nhh->addr, nhh->intf,
+                                           nhh->nhvrf_name))
+                                       continue;
+
+                               switch (nhop.type) {
+                               case NEXTHOP_TYPE_IPV4:
+                               case NEXTHOP_TYPE_IPV6:
+                               case NEXTHOP_TYPE_BLACKHOLE:
+                                       continue;
+                               case NEXTHOP_TYPE_IFINDEX:
+                               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                                       break;
+                               }
+                               nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+                               if (nh)
+                                       continue;
+
+                               if (ifp->ifindex != nhop.ifindex)
+                                       continue;
+
+                               nh = nexthop_new();
+
+                               memcpy(nh, &nhop, sizeof(nhop));
+                               nexthop_add(&nhgc->nhg.nexthop, nh);
+
+                               if (nhg_hooks.add_nexthop)
+                                       nhg_hooks.add_nexthop(nhgc, nh);
+                       }
+               } else {
+                       struct nexthop *next_nh;
+
+                       for (nh = nhgc->nhg.nexthop; nh; nh = next_nh) {
+                               next_nh = nh->next;
+                               switch (nh->type) {
+                               case NEXTHOP_TYPE_IPV4:
+                               case NEXTHOP_TYPE_IPV6:
+                               case NEXTHOP_TYPE_BLACKHOLE:
+                                       continue;
+                               case NEXTHOP_TYPE_IFINDEX:
+                               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                                       break;
+                               }
+
+                               if (oldifindex != nh->ifindex)
+                                       continue;
+
+                               nexthop_del(&nhgc->nhg, nh);
+
+                               if (nhg_hooks.del_nexthop)
+                                       nhg_hooks.del_nexthop(nhgc, nh);
+
+                               nexthop_free(nh);
+                       }
+               }
+       }
+}
+
 void nexthop_group_init(void (*new)(const char *name),
                        void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
                                            const struct nexthop *nhop),
index e9b670d5372a0e11d06a27f1b624620b9363cd9d..a44f4e35426e65f21b072d0347975d7a3fa43af5 100644 (file)
@@ -94,6 +94,11 @@ void nexthop_group_init(
                            const struct nexthop *nhop),
        void (*delete)(const char *name));
 
+void nexthop_group_enable_vrf(struct vrf *vrf);
+void nexthop_group_disable_vrf(struct vrf *vrf);
+void nexthop_group_interface_state_change(struct interface *ifp,
+                                         ifindex_t oldifindex);
+
 extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
                                      struct nexthop *nh);
 
index b493f832f3383cc14b79ec2244f5fe8332df54a9..db539d375dda73bb015363528af9ec10116c0565 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -34,6 +34,7 @@
 #include "command.h"
 #include "ns.h"
 #include "privs.h"
+#include "nexthop_group.h"
 
 /* default VRF ID value used when VRF backend is not NETNS */
 #define VRF_DEFAULT_INTERNAL 0
@@ -269,6 +270,13 @@ int vrf_enable(struct vrf *vrf)
        if (vrf_master.vrf_enable_hook)
                (*vrf_master.vrf_enable_hook)(vrf);
 
+       /*
+        * If we have any nexthop group entries that
+        * are awaiting vrf initialization then
+        * let's let people know about it
+        */
+       nexthop_group_enable_vrf(vrf);
+
        return 1;
 }
 
index e1ce40ce70ca5d7dcbf4c440d2469535bf4f4642..48182d6b2c515652e8c176a30eb1f501a2058a96 100644 (file)
@@ -37,6 +37,7 @@
 #include "mpls.h"
 #include "sockopt.h"
 #include "pbr.h"
+#include "nexthop_group.h"
 
 DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
 DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -1697,7 +1698,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s)
 void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
 {
        uint8_t link_params_status = 0;
+       ifindex_t old_ifindex;
 
+       old_ifindex = ifp->ifindex;
        /* Read interface's index. */
        if_set_index(ifp, stream_getl(s));
        ifp->status = stream_getc(s);
@@ -1724,6 +1727,8 @@ void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
                struct if_link_params *iflp = if_link_params_get(ifp);
                link_params_set_value(s, iflp);
        }
+
+       nexthop_group_interface_state_change(ifp, old_ifindex);
 }
 
 size_t zebra_interface_link_params_write(struct stream *s,