]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2051 from donaldsharp/PBRD_EXTRA
authorRuss White <russ@riw.us>
Fri, 20 Apr 2018 11:54:30 +0000 (07:54 -0400)
committerGitHub <noreply@github.com>
Fri, 20 Apr 2018 11:54:30 +0000 (07:54 -0400)
Pbrd extra

13 files changed:
lib/nexthop_group.c
lib/nexthop_group.h
lib/vrf.c
lib/zclient.c
pbrd/pbr_debug.c
pbrd/pbr_debug.h
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_nht.c
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
zebra/zebra_pbr.c
zebra/zebra_rnh.c

index 1ec49c2a02766a384c4d60d47c0a6bfa20c9ae83..5ac38d66853cc91a09aa4ebca1ff008c8ba00ad5 100644 (file)
@@ -20,6 +20,7 @@
 #include <zebra.h>
 
 #include <vrf.h>
+#include <sockunion.h>
 #include <nexthop.h>
 #include <nexthop_group.h>
 #include <vty.h>
@@ -112,6 +113,9 @@ void nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
 
        if (nexthop->next)
                nexthop->next->prev = nexthop->prev;
+
+       nh->prev = NULL;
+       nh->next = NULL;
 }
 
 void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
@@ -151,6 +155,7 @@ static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
        while (nexthop) {
                struct nexthop *next = nexthop_next(nexthop);
 
+               nexthop_del(&nhgc->nhg, nexthop);
                if (nhg_hooks.del_nexthop)
                        nhg_hooks.del_nexthop(nhgc, nexthop);
 
@@ -169,6 +174,46 @@ struct nexthop_group_cmd *nhgc_find(const char *name)
        return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
 }
 
+static int nhgc_cmp_helper(const char *a, const char *b)
+{
+       if (!a && !b)
+               return 0;
+
+       if (a && !b)
+               return -1;
+
+       if (!a && b)
+               return 1;
+
+       return strcmp(a, b);
+}
+
+static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
+{
+       int ret;
+
+       ret = sockunion_cmp(&nh1->addr, &nh2->addr);
+       if (ret)
+               return ret;
+
+       ret = nhgc_cmp_helper(nh1->intf, nh2->intf);
+       if (ret)
+               return ret;
+
+       return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+}
+
+static void nhgl_delete(struct nexthop_hold *nh)
+{
+       if (nh->intf)
+               XFREE(MTYPE_TMP, nh->intf);
+
+       if (nh->nhvrf_name)
+               XFREE(MTYPE_TMP, nh->nhvrf_name);
+
+       XFREE(MTYPE_TMP, nh);
+}
+
 static struct nexthop_group_cmd *nhgc_get(const char *name)
 {
        struct nexthop_group_cmd *nhgc;
@@ -181,6 +226,10 @@ static struct nexthop_group_cmd *nhgc_get(const char *name)
                QOBJ_REG(nhgc, nexthop_group_cmd);
                RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
 
+               nhgc->nhg_list = list_new();
+               nhgc->nhg_list->cmp = (int (*)(void *, void *))nhgl_cmp;
+               nhgc->nhg_list->del = (void (*)(void *))nhgl_delete;
+
                if (nhg_hooks.new)
                        nhg_hooks.new(name);
        }
@@ -196,6 +245,10 @@ static void nhgc_delete(struct nexthop_group_cmd *nhgc)
                nhg_hooks.delete(nhgc->name);
 
        RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
+
+       list_delete_and_null(&nhgc->nhg_list);
+
+       XFREE(MTYPE_TMP, nhgc);
 }
 
 DEFINE_QOBJ_TYPE(nexthop_group_cmd)
@@ -228,65 +281,125 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NAME",
        return CMD_SUCCESS;
 }
 
-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 void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
+                                   const char *nhvrf_name,
+                                   const union sockunion *addr,
+                                   const char *intf)
+{
+       struct nexthop_hold *nh;
+
+       nh = XCALLOC(MTYPE_TMP, sizeof(*nh));
+
+       if (nhvrf_name)
+               nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
+       if (intf)
+               nh->intf = XSTRDUP(MTYPE_TMP, intf);
+
+       nh->addr = *addr;
+
+       listnode_add_sort(nhgc->nhg_list, nh);
+}
+
+static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
+                                     const char *nhvrf_name,
+                                     const union sockunion *addr,
+                                     const char *intf)
+{
+       struct nexthop_hold *nh;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
+               if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
+                   sockunion_cmp(addr, &nh->addr) == 0 &&
+                   nhgc_cmp_helper(intf, nh->intf) == 0)
+                       break;
+       }
+
+       /*
+        * Something has gone seriously wrong, fail gracefully
+        */
+       if (!nh)
+               return;
+
+       list_delete_node(nhgc->nhg_list, node);
+
+       if (nh->nhvrf_name)
+               XFREE(MTYPE_TMP, nh->nhvrf_name);
+       if (nh->intf)
+               XFREE(MTYPE_TMP, nh->intf);
+
+       XFREE(MTYPE_TMP, nh);
+}
+
+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;
-                       }
+                       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;
+                       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);
 
@@ -297,12 +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);
        }
 
@@ -353,17 +470,37 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
        vty_out(vty, "\n");
 }
 
+static void nexthop_group_write_nexthop_internal(struct vty *vty,
+                                                struct nexthop_hold *nh)
+{
+       char buf[100];
+
+       vty_out(vty, "nexthop ");
+
+       vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
+
+       if (nh->intf)
+               vty_out(vty, " %s", nh->intf);
+
+       if (nh->nhvrf_name)
+               vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
+
+       vty_out(vty, "\n");
+}
+
 static int nexthop_group_write(struct vty *vty)
 {
        struct nexthop_group_cmd *nhgc;
-       struct nexthop *nh;
+       struct nexthop_hold *nh;
 
        RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+
                vty_out(vty, "nexthop-group %s\n", nhgc->name);
 
-               for (nh = nhgc->nhg.nexthop; nh; nh = nh->next) {
+               for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
                        vty_out(vty, "  ");
-                       nexthop_group_write_nexthop(vty, nh);
+                       nexthop_group_write_nexthop_internal(vty, nh);
                }
 
                vty_out(vty, "!\n");
@@ -372,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 c2e4c4d7573cc46998fc2cc94398f2bb7bb312e1..a44f4e35426e65f21b072d0347975d7a3fa43af5 100644 (file)
@@ -56,6 +56,13 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
        (nhop);                                                         \
        (nhop) = nexthop_next(nhop)
 
+
+struct nexthop_hold {
+       char *nhvrf_name;
+       union sockunion addr;
+       char *intf;
+};
+
 struct nexthop_group_cmd {
 
        RB_ENTRY(nexthop_group_cmd) nhgc_entry;
@@ -64,6 +71,8 @@ struct nexthop_group_cmd {
 
        struct nexthop_group nhg;
 
+       struct list *nhg_list;
+
        QOBJ_FIELDS
 };
 RB_HEAD(nhgc_entry_head, nexthp_group_cmd);
@@ -85,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,
index e9b4a52955899d4c7d12cfac74019a3ea4ceb6ca..82f045c4624ca1bd06b9eaddb7f8f6ac82a19412 100644 (file)
@@ -43,16 +43,7 @@ const char *pbr_debugs_conflines[] = {
        "debug pbr events",
 };
 
-/*
- * Set or unset flags on all debugs for pbrd.
- *
- * flags
- *    The flags to set
- *
- * set
- *    Whether to set or unset the specified flags
- */
-static void pbr_debug_set_all(uint32_t flags, bool set)
+void pbr_debug_set_all(uint32_t flags, bool set)
 {
        for (unsigned int i = 0; i < array_size(pbr_debugs); i++) {
                DEBUG_FLAGS_SET(pbr_debugs[i], flags, set);
@@ -63,36 +54,13 @@ static void pbr_debug_set_all(uint32_t flags, bool set)
        }
 }
 
-/*
- * Check flags on all debugs for pbrd.
- *
- * flags
- *    The flags to set
- *
- * Returns:
- *    The subset of the given flags that were set in all pbrd debugs
- */
-static uint32_t pbr_debug_check_all(uint32_t flags)
-{
-       uint32_t mode = DEBUG_MODE_ALL;
-
-       for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
-               mode &= DEBUG_MODE_CHECK(pbr_debugs[i], flags);
-       return mode;
-}
-
-static int pbr_debug_config_write_helper(struct vty *vty, bool config)
+int pbr_debug_config_write_helper(struct vty *vty, bool config)
 {
        uint32_t mode = DEBUG_MODE_ALL;
 
        if (config)
                mode = DEBUG_MODE_CONF;
 
-       if (pbr_debug_check_all(DEBUG_MODE_CONF) == mode) {
-               vty_out(vty, "debug pbr\n");
-               return 0;
-       }
-
        for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
                if (DEBUG_MODE_CHECK(pbr_debugs[i], mode))
                        vty_out(vty, "%s\n", pbr_debugs_conflines[i]);
@@ -104,70 +72,9 @@ int pbr_debug_config_write(struct vty *vty)
        return pbr_debug_config_write_helper(vty, true);
 }
 
-/* PBR debugging CLI ------------------------------------------------------- */
-/* clang-format off */
-
-DEFPY(debug_pbr,
-      debug_pbr_cmd,
-      "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
-      NO_STR
-      DEBUG_STR
-      "Policy Based Routing\n"
-      "Policy maps\n"
-      "PBRD <-> Zebra communications\n"
-      "Nexthop tracking\n"
-      "Events\n")
-{
-       uint32_t mode = DEBUG_NODE2MODE(vty->node);
-
-       if (map)
-               DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
-       if (zebra)
-               DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
-       if (nht)
-               DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
-       if (events)
-               DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
-
-       /* no specific debug --> act on all of them */
-       if (strmatch(argv[argc - 1]->text, "pbr"))
-               pbr_debug_set_all(mode, !no);
-
-       return CMD_SUCCESS;
-}
-
-DEFUN_NOSH(show_debugging_pbr,
-          show_debugging_pbr_cmd,
-          "show debugging [pbr]",
-          SHOW_STR
-          DEBUG_STR
-          "Policy Based Routing\n")
-{
-       vty_out(vty, "PBR debugging status:\n");
-
-       pbr_debug_config_write_helper(vty, false);
-
-       return CMD_SUCCESS;
-}
-
-/* clang-format on */
-/* ------------------------------------------------------------------------- */
-
-static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
-
 struct debug_callbacks pbr_dbg_cbs = {.debug_set_all = pbr_debug_set_all};
 
 void pbr_debug_init(void)
 {
        debug_init(&pbr_dbg_cbs);
 }
-
-void pbr_debug_init_vty(void)
-{
-       install_node(&debug_node, pbr_debug_config_write);
-
-       install_element(VIEW_NODE, &debug_pbr_cmd);
-       install_element(CONFIG_NODE, &debug_pbr_cmd);
-
-       install_element(VIEW_NODE, &show_debugging_pbr_cmd);
-}
index 27447246291339837896f185611ac06f18ff99f3..e72fb88bebcc613e3a4015226ce976d78bf1016b 100644 (file)
@@ -38,9 +38,29 @@ extern struct debug pbr_dbg_event;
 void pbr_debug_init(void);
 
 /*
- * Install PBR debugging VTY commands.
+ * Set or unset flags on all debugs for pbrd.
+ *
+ * flags
+ *    The flags to set
+ *
+ * set
+ *    Whether to set or unset the specified flags
+ */
+void pbr_debug_set_all(uint32_t flags, bool set);
+
+/*
+ * Config write helper.
+ *
+ * vty
+ *    Vty to write to
+ *
+ * config
+ *    Whether we are writing to show run or saving config file
+ *
+ * Returns:
+ *    0 for convenience
  */
-void pbr_debug_init_vty(void);
+int pbr_debug_config_write_helper(struct vty *vty, bool config);
 
 /*
  * Print PBR debugging configuration.
index 10940e1548608cddcbade3d59172473a10c8e1b4..eb2c082fb927651b7ad13c26f649405586e18656 100644 (file)
@@ -152,8 +152,9 @@ void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
        pmi->pbrm = pbrm;
        listnode_add_sort(pbrm->incoming, pmi);
 
+       bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit);
        pbr_map_check_valid(pbrm->name);
-       if (pbrm->valid && !pbrm->installed)
+       if (pbrm->valid)
                pbr_map_install(pbrm);
 }
 
@@ -193,6 +194,8 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
 
        if (pbrm->seqnumbers->count == 0) {
                RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
+
+               bf_free(pbrm->ifi_bitfield);
                XFREE(MTYPE_PBR_MAP, pbrm);
        }
 }
@@ -210,13 +213,12 @@ void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
 
        pbrm->valid = false;
        pbrms->nhs_installed = false;
-       pbrms->installed = false;
        pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
        pbrms->nhgrp_name = NULL;
 }
 
-struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
-                                            ifindex_t ifindex)
+struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+                                            struct pbr_map_interface **ppmi)
 {
        struct pbr_map_sequence *pbrms;
        struct listnode *snode, *inode;
@@ -228,6 +230,9 @@ struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
                        if (pmi->ifp->ifindex != ifindex)
                                continue;
 
+                       if (ppmi)
+                               *ppmi = pmi;
+
                        for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
                                                  pbrms)) {
                                DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
@@ -284,6 +289,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
 
                RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
 
+               bf_init(pbrm->ifi_bitfield, 64);
                pbr_map_add_interfaces(pbrm);
        }
 
@@ -305,8 +311,6 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
 
                QOBJ_REG(pbrms, pbr_map_sequence);
                listnode_add_sort(pbrm->seqnumbers, pbrms);
-
-               pbrm->installed = false;
        }
 
        return pbrms;
@@ -463,6 +467,8 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
 
        listnode_delete(pbrm->incoming, pmi);
        pmi->pbrm = NULL;
+
+       bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
        XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
 }
 
@@ -541,8 +547,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
                       pbrms->seqno, pbrms->reason);
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
+       for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
                pbr_send_pbr_map(pbrms, pmi, install);
+       }
 }
 
 void pbr_map_install(struct pbr_map *pbrm)
@@ -557,8 +564,6 @@ void pbr_map_install(struct pbr_map *pbrm)
        for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
                for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
                        pbr_send_pbr_map(pbrms, pmi, true);
-
-       pbrm->installed = true;
 }
 
 void pbr_map_init(void)
index 5cb22d7429ebb3a4acf2198e441d98dc09f243bb..7cd079d169aa50de4bc84532011ac159c7f86f2e 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __PBR_MAP_H__
 #define __PBR_MAP_H__
 
+#include <bitfield.h>
+
 struct pbr_map {
        /*
         * RB Tree of the pbr_maps
@@ -40,20 +42,21 @@ struct pbr_map {
         */
        struct list *incoming;
 
+       bitfield_t ifi_bitfield;
        /*
         * If valid is true we think the pbr_map is valid,
         * If false, look in individual pbrms to see
         * what we think is the invalid reason
         */
        bool valid;
-
-       bool installed;
 };
 
 RB_HEAD(pbr_map_entry_head, pbr_map);
 RB_PROTOTYPE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
 
 struct pbr_map_interface {
+       uint32_t install_bit;
+
        struct interface *ifp;
 
        struct pbr_map *pbrm;
@@ -112,7 +115,7 @@ struct pbr_map_sequence {
        /*
         * Are we installed
         */
-       bool installed;
+       uint64_t installed;
 
        /*
         * A reason of 0 means we think the pbr_map_sequence is good to go
@@ -134,8 +137,9 @@ DECLARE_QOBJ_TYPE(pbr_map_sequence)
 extern struct pbr_map_entry_head pbr_maps;
 
 extern struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno);
-extern struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
-                                                   ifindex_t ifindex);
+extern struct pbr_map_sequence *
+pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+                   struct pbr_map_interface **ppmi);
 
 extern struct pbr_map *pbrm_find(const char *name);
 extern void pbr_map_delete(struct pbr_map_sequence *pbrms);
index 19bc1804de0b421889be36d5a6888631155dc5c8..1ccf3ebffac8255377905d617f644703efbcf71f 100644 (file)
@@ -319,8 +319,16 @@ static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b,
        if (pnhgc->table_id == *table_id) {
                DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
                       __PRETTY_FUNCTION__, *table_id, pnhgc->name);
-               pnhgc->installed = true;
-               pbr_map_schedule_policy_from_nhg(pnhgc->name);
+
+               /*
+                * If the table has been re-handled by zebra
+                * and we are already installed no need to do
+                * anything here.
+                */
+               if (!pnhgc->installed) {
+                       pnhgc->installed = true;
+                       pbr_map_schedule_policy_from_nhg(pnhgc->name);
+               }
        }
 }
 
@@ -409,8 +417,6 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
 
        install_afi = pbr_nht_which_afi(nhg, nh_afi);
 
-       pnhgc->installed = false;
-
        route_add(pnhgc, nhg, install_afi);
 }
 
@@ -511,7 +517,6 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
 
        pbrm->valid = false;
        pbrms->nhs_installed = false;
-       pbrms->installed = false;
        pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
 
        memset(&find, 0, sizeof(find));
index 16ae0ee2b3e8a0381cff95af0838a6b6ff516929..475ad86b5885b8a77cd13b4df0bdc207b8aee312 100644 (file)
@@ -251,8 +251,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
                                        intf, vrf->name);
                                return CMD_WARNING_CONFIG_FAILED;
                        }
-               } else
+               } 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;
+               }
        }
 
        if (pbrms->nhg)
@@ -383,7 +389,7 @@ DEFPY (show_pbr_map,
                                pbr_map_reason_string(pbrms->reason, rbuf,
                                                      sizeof(rbuf));
                        vty_out(vty,
-                               "    Seq: %u rule: %u Installed: %d(%u) Reason: %s\n",
+                               "    Seq: %u rule: %u Installed: %" PRIu64 "(%u) Reason: %s\n",
                                pbrms->seqno, pbrms->ruleno, pbrms->installed,
                                pbrms->unique, pbrms->reason ? rbuf : "Valid");
 
@@ -477,6 +483,58 @@ DEFPY (show_pbr_interface,
        return CMD_SUCCESS;
 }
 
+/* PBR debugging CLI ------------------------------------------------------- */
+/* clang-format off */
+
+static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
+
+DEFPY(debug_pbr,
+      debug_pbr_cmd,
+      "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
+      NO_STR
+      DEBUG_STR
+      "Policy Based Routing\n"
+      "Policy maps\n"
+      "PBRD <-> Zebra communications\n"
+      "Nexthop tracking\n"
+      "Events\n")
+{
+       uint32_t mode = DEBUG_NODE2MODE(vty->node);
+
+       if (map)
+               DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
+       if (zebra)
+               DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
+       if (nht)
+               DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
+       if (events)
+               DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
+
+       /* no specific debug --> act on all of them */
+       if (strmatch(argv[argc - 1]->text, "pbr"))
+               pbr_debug_set_all(mode, !no);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_NOSH(show_debugging_pbr,
+          show_debugging_pbr_cmd,
+          "show debugging [pbr]",
+          SHOW_STR
+          DEBUG_STR
+          "Policy Based Routing\n")
+{
+       vty_out(vty, "PBR debugging status:\n");
+
+       pbr_debug_config_write_helper(vty, false);
+
+       return CMD_SUCCESS;
+}
+
+/* clang-format on */
+/* ------------------------------------------------------------------------- */
+
+
 static struct cmd_node interface_node = {
        INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
 };
@@ -561,6 +619,12 @@ void pbr_vty_init(void)
        install_node(&pbr_map_node,
                     pbr_vty_map_config_write);
 
+       /* debug */
+       install_node(&debug_node, pbr_debug_config_write);
+       install_element(VIEW_NODE, &debug_pbr_cmd);
+       install_element(CONFIG_NODE, &debug_pbr_cmd);
+       install_element(VIEW_NODE, &show_debugging_pbr_cmd);
+
        install_default(PBRMAP_NODE);
 
        install_element(CONFIG_NODE, &pbr_map_cmd);
@@ -574,6 +638,4 @@ void pbr_vty_init(void)
        install_element(VIEW_NODE, &show_pbr_map_cmd);
        install_element(VIEW_NODE, &show_pbr_interface_cmd);
        install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
-
-       pbr_debug_init_vty();
 }
index a1a2d34ac1d8499d64e2f4604fdce407b44979fa..4e5b5f3dde90d1142a59935b77251190063f53b8 100644 (file)
@@ -45,17 +45,6 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
 /* Zebra structure to hold current status. */
 struct zclient *zclient;
 
-static struct interface *zebra_interface_if_lookup(struct stream *s)
-{
-       char ifname_tmp[INTERFACE_NAMSIZ];
-
-       /* Read interface name. */
-       stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
-       /* And look it up. */
-       return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
-}
-
 struct pbr_interface *pbr_if_new(struct interface *ifp)
 {
        struct pbr_interface *pbr_ifp;
@@ -140,7 +129,7 @@ static int interface_state_up(int command, struct zclient *zclient,
                              zebra_size_t length, vrf_id_t vrf_id)
 {
 
-       zebra_interface_if_lookup(zclient->ibuf);
+       zebra_interface_state_read(zclient->ibuf, vrf_id);
 
        return 0;
 }
@@ -206,13 +195,16 @@ static int rule_notify_owner(int command, struct zclient *zclient,
        uint32_t seqno, priority, unique;
        enum zapi_rule_notify_owner note;
        struct pbr_map_sequence *pbrms;
+       struct pbr_map_interface *pmi;
        ifindex_t ifi;
+       uint64_t installed;
 
        if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
                                     &ifi, &note))
                return -1;
 
-       pbrms = pbrms_lookup_unique(unique, ifi);
+       pmi = NULL;
+       pbrms = pbrms_lookup_unique(unique, ifi, &pmi);
        if (!pbrms) {
                DEBUGD(&pbr_dbg_zebra,
                       "%s: Failure to lookup pbrms based upon %u",
@@ -220,18 +212,21 @@ static int rule_notify_owner(int command, struct zclient *zclient,
                return 0;
        }
 
+       installed = 1 << pmi->install_bit;
+
        switch (note) {
        case ZAPI_RULE_FAIL_INSTALL:
                DEBUGD(&pbr_dbg_zebra, "%s: Recieved RULE_FAIL_INSTALL",
                       __PRETTY_FUNCTION__);
-               pbrms->installed = false;
+               pbrms->installed &= ~installed;
                break;
        case ZAPI_RULE_INSTALLED:
-               pbrms->installed = true;
+               pbrms->installed |= installed;
                DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
                       __PRETTY_FUNCTION__);
                break;
        case ZAPI_RULE_REMOVED:
+               pbrms->installed &= ~installed;
                DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
                       __PRETTY_FUNCTION__);
                break;
@@ -499,9 +494,23 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
 {
        struct pbr_map *pbrm = pbrms->parent;
        struct stream *s;
+       uint64_t is_installed = 1 << pmi->install_bit;
 
-       DEBUGD(&pbr_dbg_zebra, "%s: for %s %d", __PRETTY_FUNCTION__, pbrm->name,
-              install);
+       is_installed &= pbrms->installed;
+
+       DEBUGD(&pbr_dbg_zebra, "%s: for %s %d(%" PRIu64 ")",
+              __PRETTY_FUNCTION__, pbrm->name, install, is_installed);
+
+       /*
+        * If we are installed and asked to do so again
+        * just return.  If we are not installed and asked
+        * and asked to delete just return;
+        */
+       if (install && is_installed)
+               return;
+
+       if (!install && !is_installed)
+               return;
 
        s = zclient->obuf;
        stream_reset(s);
index 27daa2d807e43b4cc4bd55143def03d9ffd8b271..758365d716aab84a9e27067251fe7e936867646d 100644 (file)
@@ -111,6 +111,7 @@ int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
 struct pbr_rule_unique_lookup {
        struct zebra_pbr_rule *rule;
        uint32_t unique;
+       struct interface *ifp;
 };
 
 static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
@@ -118,7 +119,7 @@ static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
        struct pbr_rule_unique_lookup *pul = data;
        struct zebra_pbr_rule *rule = b->data;
 
-       if (pul->unique == rule->rule.unique) {
+       if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) {
                pul->rule = rule;
                return HASHWALK_ABORT;
        }
@@ -127,11 +128,13 @@ static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
 }
 
 static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
-                                                    uint32_t unique)
+                                                    uint32_t unique,
+                                                    struct interface *ifp)
 {
        struct pbr_rule_unique_lookup pul;
 
        pul.unique = unique;
+       pul.ifp = ifp;
        pul.rule = NULL;
        hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul);
 
@@ -275,7 +278,7 @@ static void *pbr_rule_alloc_intern(void *arg)
 void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
 {
        struct zebra_pbr_rule *unique =
-               pbr_rule_lookup_unique(zns, rule->rule.unique);
+               pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp);
 
        (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
        kernel_add_pbr_rule(rule);
@@ -493,8 +496,10 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
                zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
                break;
        case SOUTHBOUND_DELETE_SUCCESS:
+               zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
                break;
        case SOUTHBOUND_DELETE_FAILURE:
+               zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
                break;
        }
 }
index 879da092f0e199f92dce93f19f4af4ebe067f4c4..22a04ee23dfa6929ae4a9cb302f820e00d1241a7 100644 (file)
@@ -561,8 +561,10 @@ static void zebra_rnh_process_pbr_tables(int family,
                         * just rethink it.  Yes this is a hammer, but
                         * a small one
                         */
-                       if (o_re)
+                       if (o_re) {
+                               SET_FLAG(o_re->status, ROUTE_ENTRY_CHANGED);
                                rib_queue_add(o_rn);
+                       }
                }
        }
 }