]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pbrd: Add `set vrf NAME` and `set vrf unchanged`
authorStephen Worley <sworley@cumulusnetworks.com>
Fri, 27 Sep 2019 20:38:31 +0000 (16:38 -0400)
committerStephen Worley <sworley@cumulusnetworks.com>
Thu, 21 Nov 2019 21:59:42 +0000 (16:59 -0500)
`set vrf NAME` allows the pbr map to point to an arbitrary vrf table.

`set vrf unchanged` will use the interface's vrf for table lookup.

Further, add functionality for pbr to respond to interface events
such as interface vrf changes & interface creation/deletion.

Ex)
ubuntu_nh# show pbr map
  pbr-map TEST valid: 1
    Seq: 1 rule: 300 Installed: 3(1) Reason: Valid
        SRC Match: 3.3.3.3/32
        VRF Unchanged (use interface vrf)
  pbr-map TEST2 valid: 1
    Seq: 2 rule: 301 Installed: 3(2) Reason: Valid
        SRC Match: 4.4.4.4/32
        VRF Lookup: vrf-red

root@ubuntu_nh:/home# ip rule show
0:      from all lookup local
300:    from 3.3.3.3 iif dummy2 lookup main
300:    from 3.3.3.3 iif dummyVRF lookup 1111
301:    from 4.4.4.4 iif dummy1 lookup 1111
301:    from 4.4.4.4 iif dummy3 lookup 1111

Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com-
doc/user/pbr.rst
pbrd/pbr_main.c
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_nht.c
pbrd/pbr_vrf.c [new file with mode: 0644]
pbrd/pbr_vrf.h [new file with mode: 0644]
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
pbrd/subdir.am

index fab4343f50802d99d38238e4e6a9926ac8b205c8..68e460748c0e12ca4007a5778472d207a2041aad 100644 (file)
@@ -107,6 +107,14 @@ end destination.
    Use this individual nexthop as the place to forward packets when the match
    commands have matched a packet.
 
+.. clicmd:: set vrf unchanged|NAME
+
+   If unchanged is set, the rule will use the vrf table the interface is in
+   as its lookup. If NAME is specified, the rule will use that vrf table as
+   its lookup.
+
+   Not supported with NETNS VRF backend.
+
 .. _pbr-policy:
 
 PBR Policy
index bb92703ae48e2cb69f7d85d1197acee7b7847989..faa3de42f268718012078f110a9bea31324ae8e8 100644 (file)
@@ -48,6 +48,7 @@
 #include "pbr_zebra.h"
 #include "pbr_vty.h"
 #include "pbr_debug.h"
+#include "pbr_vrf.h"
 
 zebra_capabilities_t _caps_p[] = {
        ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@@ -153,7 +154,6 @@ int main(int argc, char **argv, char **envp)
 
        pbr_debug_init();
 
-       vrf_init(NULL, NULL, NULL, NULL, NULL);
        nexthop_group_init(pbr_nhgroup_add_cb,
                           pbr_nhgroup_add_nexthop_cb,
                           pbr_nhgroup_del_nexthop_cb,
@@ -169,6 +169,7 @@ int main(int argc, char **argv, char **envp)
        if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up,
                          pbr_ifp_down, pbr_ifp_destroy);
        pbr_zebra_init();
+       pbr_vrf_init();
        pbr_vty_init();
 
        frr_config_fork();
index 1a8461c6c13be85a8774957e0bdc767aaa7040aa..4df0c790b11ae77dffe92b8123ccfba933cfa811 100644 (file)
@@ -35,6 +35,7 @@
 #include "pbr_zebra.h"
 #include "pbr_memory.h"
 #include "pbr_debug.h"
+#include "pbr_vrf.h"
 
 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map")
 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence")
@@ -42,6 +43,7 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface")
 
 static uint32_t pbr_map_sequence_unique;
 
+static bool pbr_map_check_valid_internal(struct pbr_map *pbrm);
 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
                                  const struct pbr_map *pbrmap2);
 
@@ -98,9 +100,55 @@ static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi)
        }
 }
 
+static bool pbr_map_interface_is_valid(const struct pbr_map_interface *pmi)
+{
+       /* Don't install rules without a real ifindex on the incoming interface.
+        *
+        * This can happen when we have config for an interface that does not
+        * exist or when an interface is changing vrfs.
+        */
+       if (pmi->ifp && pmi->ifp->ifindex != IFINDEX_INTERNAL)
+               return true;
+
+       return false;
+}
+
+static void pbr_map_pbrms_update_common(struct pbr_map_sequence *pbrms,
+                                       bool install)
+{
+       struct pbr_map *pbrm;
+       struct listnode *node;
+       struct pbr_map_interface *pmi;
+
+       pbrm = pbrms->parent;
+
+       if (pbrms->nhs_installed && pbrm->incoming->count) {
+               for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
+                       if (!pmi->ifp)
+                               continue;
+
+                       if (install && !pbr_map_interface_is_valid(pmi))
+                               continue;
+
+                       pbr_send_pbr_map(pbrms, pmi, install);
+               }
+       }
+}
+
+static void pbr_map_pbrms_install(struct pbr_map_sequence *pbrms)
+{
+       pbr_map_pbrms_update_common(pbrms, true);
+}
+
+static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms)
+{
+       pbr_map_pbrms_update_common(pbrms, false);
+}
+
 static const char *pbr_map_reason_str[] = {
        "Invalid NH-group",     "Invalid NH",    "No Nexthops",
-       "Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence",
+       "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
+       "Deleting Sequence",
 };
 
 void pbr_map_reason_string(unsigned int reason, char *buf, int size)
@@ -168,6 +216,93 @@ void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
                pbr_map_install(pbrm);
 }
 
+static int
+pbr_map_policy_interface_update_common(const struct interface *ifp,
+                                      struct pbr_interface **pbr_ifp,
+                                      struct pbr_map **pbrm)
+{
+       if (!ifp->info) {
+               DEBUGD(&pbr_dbg_map, "%s: %s has no pbr_interface info",
+                      __func__, ifp->name);
+               return -1;
+       }
+
+       *pbr_ifp = ifp->info;
+
+       *pbrm = pbrm_find((*pbr_ifp)->mapname);
+
+       if (!*pbrm) {
+               DEBUGD(&pbr_dbg_map, "%s: applied PBR-MAP(%s) does not exist?",
+                      __func__, (*pbr_ifp)->mapname);
+               return -1;
+       }
+
+       return 0;
+}
+
+void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up)
+{
+       struct pbr_interface *pbr_ifp;
+       struct pbr_map_sequence *pbrms;
+       struct pbr_map *pbrm;
+       struct listnode *node, *inode;
+       struct pbr_map_interface *pmi;
+
+       if (pbr_map_policy_interface_update_common(ifp, &pbr_ifp, &pbrm))
+               return;
+
+       DEBUGD(&pbr_dbg_map, "%s: %s %s rules on interface %s", __func__,
+              pbr_ifp->mapname, (state_up ? "installing" : "removing"),
+              ifp->name);
+
+       /*
+        * Walk the list and install/remove maps on the interface.
+        */
+       for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
+               for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
+                       if (pmi->ifp == ifp && pbr_map_interface_is_valid(pmi))
+                               pbr_send_pbr_map(pbrms, pmi, state_up);
+}
+
+static void pbrms_vrf_update(struct pbr_map_sequence *pbrms,
+                            const struct pbr_vrf *pbr_vrf)
+{
+       const char *vrf_name = pbr_vrf_name(pbr_vrf);
+
+       if (pbrms->vrf_lookup
+           && (strncmp(vrf_name, pbrms->vrf_name, sizeof(pbrms->vrf_name))
+               == 0)) {
+               DEBUGD(&pbr_dbg_map, "\tSeq %u uses vrf %s (%u), updating map",
+                      pbrms->seqno, vrf_name, pbr_vrf_id(pbr_vrf));
+
+               pbr_map_check(pbrms);
+       }
+}
+
+/* Vrf enabled/disabled */
+void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf)
+{
+       struct pbr_map *pbrm;
+       struct pbr_map_sequence *pbrms;
+       struct listnode *node;
+
+       if (!pbr_vrf)
+               return;
+
+       bool enabled = pbr_vrf_is_enabled(pbr_vrf);
+
+       DEBUGD(&pbr_dbg_map, "%s: %s (%u) %s, updating pbr maps", __func__,
+              pbr_vrf_name(pbr_vrf), pbr_vrf_id(pbr_vrf),
+              enabled ? "enabled" : "disabled");
+
+       RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
+               DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __PRETTY_FUNCTION__,
+                      pbrm->name);
+               for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
+                       pbrms_vrf_update(pbrms, pbr_vrf);
+       }
+}
+
 void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp)
 {
        struct pbr_interface *pbr_ifp = ifp->info;
@@ -210,16 +345,11 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
        }
 }
 
-void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
+static void pbr_map_delete_common(struct pbr_map_sequence *pbrms)
 {
        struct pbr_map *pbrm = pbrms->parent;
-       struct listnode *node;
-       struct pbr_map_interface *pmi;
 
-       if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
-               for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
-                       pbr_send_pbr_map(pbrms, pmi, false);
-       }
+       pbr_map_pbrms_uninstall(pbrms);
 
        pbrm->valid = false;
        pbrms->nhs_installed = false;
@@ -227,6 +357,16 @@ void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
        pbrms->nhgrp_name = NULL;
 }
 
+void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms)
+{
+       pbr_map_delete_common(pbrms);
+}
+
+void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms)
+{
+       pbr_map_delete_common(pbrms);
+}
+
 struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
                                             struct pbr_map_interface **ppmi)
 {
@@ -318,6 +458,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
                pbrms->reason =
                        PBR_MAP_INVALID_EMPTY |
                        PBR_MAP_INVALID_NO_NEXTHOPS;
+               pbrms->vrf_name[0] = '\0';
 
                QOBJ_REG(pbrms, pbr_map_sequence);
                listnode_add_sort(pbrm->seqnumbers, pbrms);
@@ -329,12 +470,36 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
 static void
 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
 {
+       /* Check if any are present first */
+       if (!pbrms->vrf_unchanged && !pbrms->vrf_lookup && !pbrms->nhg
+           && !pbrms->nhgrp_name) {
+               pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
+               return;
+       }
+
+       /*
+        * Check validness of vrf.
+        */
+
+       /* This one can be considered always valid */
+       if (pbrms->vrf_unchanged)
+               pbrms->nhs_installed = true;
+
+       if (pbrms->vrf_lookup) {
+               struct pbr_vrf *pbr_vrf =
+                       pbr_vrf_lookup_by_name(pbrms->vrf_name);
+
+               if (pbr_vrf && pbr_vrf_is_valid(pbr_vrf))
+                       pbrms->nhs_installed = true;
+               else
+                       pbrms->reason |= PBR_MAP_INVALID_VRF;
+       }
+
        /*
         * Check validness of the nexthop or nexthop-group
         */
-       if (!pbrms->nhg && !pbrms->nhgrp_name)
-               pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
 
+       /* Only nexthop or nexthop group allowed */
        if (pbrms->nhg && pbrms->nhgrp_name)
                pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP;
 
@@ -458,11 +623,13 @@ void pbr_map_policy_install(const char *name)
                       __PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid,
                       pbrms->nhs_installed);
 
-               if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
-                       DEBUGD(&pbr_dbg_map, "\tInstalling %s %u",
-                              pbrm->name, pbrms->seqno);
+               if (pbrm->valid && pbrms->nhs_installed
+                   && pbrm->incoming->count) {
+                       DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", pbrm->name,
+                              pbrms->seqno);
                        for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
-                               pbr_send_pbr_map(pbrms, pmi, true);
+                               if (pbr_map_interface_is_valid(pmi))
+                                       pbr_send_pbr_map(pbrms, pmi, true);
                }
        }
 }
@@ -525,8 +692,6 @@ void pbr_map_check_nh_group_change(const char *nh_group)
 void pbr_map_check(struct pbr_map_sequence *pbrms)
 {
        struct pbr_map *pbrm;
-       struct listnode *inode;
-       struct pbr_map_interface *pmi;
        bool install;
 
        pbrm = pbrms->parent;
@@ -551,23 +716,22 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
                       pbrms->seqno, pbrms->reason);
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
-               pbr_send_pbr_map(pbrms, pmi, install);
-       }
+       if (install)
+               pbr_map_pbrms_install(pbrms);
+       else
+               pbr_map_pbrms_uninstall(pbrms);
 }
 
 void pbr_map_install(struct pbr_map *pbrm)
 {
-       struct listnode *node, *inode;
        struct pbr_map_sequence *pbrms;
-       struct pbr_map_interface *pmi;
+       struct listnode *node;
 
        if (!pbrm->incoming->count)
                return;
 
        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);
+               pbr_map_pbrms_install(pbrms);
 }
 
 void pbr_map_init(void)
index 112acfe44e9fc4471ee4e9f55649221fee6ecb1d..8bd22cbf2a5bc8492d9ab1c437f4aa99ab02c0f6 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <bitfield.h>
 
+#include "pbr_vrf.h"
+
 struct pbr_map {
        /*
         * RB Tree of the pbr_maps
@@ -94,6 +96,21 @@ struct pbr_map_sequence {
         */
        unsigned char family;
 
+       /*
+        * Use interface's vrf.
+        */
+       bool vrf_unchanged;
+
+       /*
+        * The vrf to lookup in was directly configured.
+        */
+       bool vrf_lookup;
+
+       /*
+        * VRF to lookup.
+        */
+       char vrf_name[VRF_NAMSIZ + 1];
+
        /*
         * The nexthop group we auto create
         * for when the user specifies a individual
@@ -122,12 +139,13 @@ struct pbr_map_sequence {
         * A reason of 0 means we think the pbr_map_sequence is good to go
         * We can accumuluate multiple failure states
         */
-#define PBR_MAP_VALID_SEQUENCE_NUMBER  0
-#define PBR_MAP_INVALID_NEXTHOP_GROUP  (1 << 0)
-#define PBR_MAP_INVALID_NEXTHOP        (1 << 1)
-#define PBR_MAP_INVALID_NO_NEXTHOPS    (1 << 2)
-#define PBR_MAP_INVALID_BOTH_NHANDGRP  (1 << 3)
-#define PBR_MAP_INVALID_EMPTY          (1 << 4)
+#define PBR_MAP_VALID_SEQUENCE_NUMBER    0
+#define PBR_MAP_INVALID_NEXTHOP_GROUP    (1 << 0)
+#define PBR_MAP_INVALID_NEXTHOP          (1 << 1)
+#define PBR_MAP_INVALID_NO_NEXTHOPS      (1 << 2)
+#define PBR_MAP_INVALID_BOTH_NHANDGRP    (1 << 3)
+#define PBR_MAP_INVALID_EMPTY            (1 << 4)
+#define PBR_MAP_INVALID_VRF              (1 << 5)
        uint64_t reason;
 
        QOBJ_FIELDS
@@ -144,12 +162,21 @@ pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
 
 extern struct pbr_map *pbrm_find(const char *name);
 extern void pbr_map_delete(struct pbr_map_sequence *pbrms);
-extern void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms);
+extern void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms);
+extern void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms);
 extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp);
 extern void pbr_map_interface_delete(struct pbr_map *pbrm,
                                     struct interface *ifp);
+
+/* Update maps installed on interface */
+extern void pbr_map_policy_interface_update(const struct interface *ifp,
+                                           bool state_up);
+
 extern void pbr_map_final_interface_deletion(struct pbr_map *pbrm,
                                             struct pbr_map_interface *pmi);
+
+extern void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf);
+
 extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp);
 extern void pbr_map_init(void);
 
index 7ccd14d1f1b7d31a7ac33ad35994ae1e0f68f6ef..5ab714e617d458cd131a53516af1b62ec9ebaae6 100644 (file)
@@ -548,20 +548,10 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
        struct pbr_nexthop_group_cache find;
        struct pbr_nexthop_cache *pnhc;
        struct pbr_nexthop_cache lup;
-       struct pbr_map *pbrm = pbrms->parent;
-       struct listnode *node;
-       struct pbr_map_interface *pmi;
        struct nexthop *nh;
        enum nexthop_types_t nh_type = 0;
 
-       if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
-               for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
-                       pbr_send_pbr_map(pbrms, pmi, false);
-       }
-
-       pbrm->valid = false;
-       pbrms->nhs_installed = false;
-       pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
+       pbr_map_delete_nexthops(pbrms);
 
        memset(&find, 0, sizeof(find));
        snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c
new file mode 100644 (file)
index 0000000..d5a2bd0
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * PBR - vrf code
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *               Stephen Worley
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "vrf.h"
+
+#include "pbr_vrf.h"
+#include "pbr_memory.h"
+#include "pbr_map.h"
+#include "pbr_debug.h"
+
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF")
+
+static struct pbr_vrf *pbr_vrf_alloc(void)
+{
+       struct pbr_vrf *pbr_vrf;
+
+       pbr_vrf = XCALLOC(MTYPE_PBR_MAP_VRF, sizeof(struct pbr_vrf));
+
+       return pbr_vrf;
+}
+
+static void pbr_vrf_free(struct pbr_vrf *pbr_vrf)
+{
+       XFREE(MTYPE_PBR_MAP_VRF, pbr_vrf);
+}
+
+static int pbr_vrf_new(struct vrf *vrf)
+{
+       struct pbr_vrf *pbr_vrf;
+
+       DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
+
+       pbr_vrf = pbr_vrf_alloc();
+       vrf->info = pbr_vrf;
+       pbr_vrf->vrf = vrf;
+
+       return 0;
+}
+
+static int pbr_vrf_enable(struct vrf *vrf)
+{
+       DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
+
+       pbr_map_vrf_update(vrf->info);
+
+       return 0;
+}
+
+static int pbr_vrf_disable(struct vrf *vrf)
+{
+       DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
+
+       pbr_map_vrf_update(vrf->info);
+
+       return 0;
+}
+
+static int pbr_vrf_delete(struct vrf *vrf)
+{
+       DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
+
+       /*
+        * Make sure vrf is always marked disabled first so we handle
+        * pbr rules using it.
+        */
+       assert(!vrf_is_enabled(vrf));
+
+       pbr_vrf_free(vrf->info);
+       vrf->info = NULL;
+
+       return 0;
+}
+
+struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id)
+{
+       struct vrf *vrf;
+
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (vrf)
+               return ((struct pbr_vrf *)vrf->info);
+
+       return NULL;
+}
+
+struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name)
+{
+       struct vrf *vrf;
+
+       if (!name)
+               name = VRF_DEFAULT_NAME;
+
+       vrf = vrf_lookup_by_name(name);
+       if (vrf)
+               return ((struct pbr_vrf *)vrf->info);
+
+       return NULL;
+}
+
+bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf)
+{
+       return vrf_is_enabled(pbr_vrf->vrf) ? true : false;
+}
+
+bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf)
+{
+       if (vrf_is_backend_netns())
+               return false;
+
+       if (!pbr_vrf->vrf)
+               return false;
+
+       return pbr_vrf_is_enabled(pbr_vrf);
+}
+
+void pbr_vrf_init(void)
+{
+       vrf_init(pbr_vrf_new, pbr_vrf_enable, pbr_vrf_disable, pbr_vrf_delete,
+                NULL);
+}
diff --git a/pbrd/pbr_vrf.h b/pbrd/pbr_vrf.h
new file mode 100644 (file)
index 0000000..c944876
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * VRF library for PBR
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *               Stephen Worley
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __PBR_VRF_H__
+#define __PBR_VRF_H__
+
+struct pbr_vrf {
+       struct vrf *vrf;
+};
+
+static inline const char *pbr_vrf_name(const struct pbr_vrf *pbr_vrf)
+{
+       return pbr_vrf->vrf->name;
+}
+
+static inline vrf_id_t pbr_vrf_id(const struct pbr_vrf *pbr_vrf)
+{
+       return pbr_vrf->vrf->vrf_id;
+}
+
+extern struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id);
+extern struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name);
+extern bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf);
+extern bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf);
+
+extern void pbr_vrf_init(void);
+#endif
index e0fd147b0e8dbdcf425e64ee2d537a1f5f5b2659..bc4aa947a9c07922566af576d3d0e9ddfff361ef 100644 (file)
@@ -193,14 +193,17 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
        pbr_map_check(pbrms);
 
        return CMD_SUCCESS;
- }
+}
+
+#define SET_VRF_EXISTS_STR                                                     \
+       "A `set vrf XX` command already exists, please remove that first\n"
 
 DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
-       "[no] set nexthop-group NHGNAME$name",
-       NO_STR
-       "Set for the PBR-MAP\n"
-       "nexthop-group to use\n"
-       "The name of the nexthop-group\n")
+      "[no] set nexthop-group NHGNAME$name",
+      NO_STR
+      "Set for the PBR-MAP\n"
+      "nexthop-group to use\n"
+      "The name of the nexthop-group\n")
 {
        struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
        struct nexthop_group_cmd *nhgc;
@@ -211,16 +214,22 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
+               vty_out(vty, SET_VRF_EXISTS_STR);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        nhgc = nhgc_find(name);
        if (!nhgc) {
                vty_out(vty, "Specified nexthop-group %s does not exist\n",
                        name);
-               vty_out(vty, "PBR-MAP will not be applied until it is created\n");
+               vty_out(vty,
+                       "PBR-MAP will not be applied until it is created\n");
        }
 
        if (no) {
                if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
-                       pbr_map_delete_nexthop_group(pbrms);
+                       pbr_map_delete_nexthops(pbrms);
                else {
                        vty_out(vty,
                                "Nexthop Group specified: %s does not exist to remove",
@@ -272,6 +281,11 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
+               vty_out(vty, SET_VRF_EXISTS_STR);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        if (vrf_name)
                vrf = vrf_lookup_by_name(vrf_name);
        else
@@ -372,6 +386,61 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
        return CMD_SUCCESS;
 }
 
+DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
+      "[no] set vrf <NAME$vrf_name|unchanged>",
+      NO_STR
+      "Set for the PBR-MAP\n"
+      "Specify the VRF for this map\n"
+      "The VRF Name\n"
+      "Use the interface's VRF for lookup\n")
+{
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+       int ret = CMD_SUCCESS;
+
+       if (no) {
+               pbr_map_delete_vrf(pbrms);
+
+               /* Reset all data */
+               pbrms->nhs_installed = false;
+               pbrms->vrf_name[0] = '\0';
+               pbrms->vrf_lookup = false;
+               pbrms->vrf_unchanged = false;
+
+               goto done;
+       }
+
+       if (pbrms->nhgrp_name || pbrms->nhg) {
+               vty_out(vty,
+                       "A `set nexthop/nexthop-group XX` command already exits, please remove that first\n");
+               ret = CMD_WARNING_CONFIG_FAILED;
+               goto done;
+       }
+
+       if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
+               vty_out(vty, SET_VRF_EXISTS_STR);
+               ret = CMD_WARNING_CONFIG_FAILED;
+               goto done;
+       }
+
+       if (vrf_name) {
+               if (!pbr_vrf_lookup_by_name(vrf_name)) {
+                       vty_out(vty, "Specified: %s is non-existent\n",
+                               vrf_name);
+                       ret = CMD_WARNING_CONFIG_FAILED;
+                       goto done;
+               }
+
+               pbrms->vrf_lookup = true;
+               strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
+       } else
+               pbrms->vrf_unchanged = true;
+
+       pbr_map_check(pbrms);
+
+done:
+       return ret;
+}
+
 DEFPY (pbr_policy,
        pbr_policy_cmd,
        "[no] pbr-policy PBRMAP$mapname",
@@ -500,6 +569,12 @@ DEFPY (show_pbr_map,
                                                pbrms->internal_nhg_name),
                                        pbr_nht_get_table(
                                                pbrms->internal_nhg_name));
+                       } else if (pbrms->vrf_unchanged) {
+                               vty_out(vty,
+                                       "\tVRF Unchanged (use interface vrf)\n");
+                       } else if (pbrms->vrf_lookup) {
+                               vty_out(vty, "\tVRF Lookup: %s\n",
+                                       pbrms->vrf_name);
                        } else {
                                vty_out(vty,
                                        "\tNexthop-Group: Unknown Installed: 0(0)\n");
@@ -662,6 +737,12 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
        if (pbrms->mark)
                vty_out(vty, " match mark %u\n", pbrms->mark);
 
+       if (pbrms->vrf_unchanged)
+               vty_out(vty, " set vrf unchanged\n");
+
+       if (pbrms->vrf_lookup)
+               vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
+
        if (pbrms->nhgrp_name)
                vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
 
@@ -737,6 +818,7 @@ void pbr_vty_init(void)
        install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
        install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
        install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
        install_element(VIEW_NODE, &show_pbr_cmd);
        install_element(VIEW_NODE, &show_pbr_map_cmd);
        install_element(VIEW_NODE, &show_pbr_interface_cmd);
index 719374e3b9e0c20e86f6c43d5188174a8c9e0373..b0a689a7e4b428edeb3ba075e3bcce6cff5c9bb8 100644 (file)
@@ -39,6 +39,7 @@
 #include "pbr_memory.h"
 #include "pbr_zebra.h"
 #include "pbr_debug.h"
+#include "pbr_vrf.h"
 
 DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
 
@@ -67,8 +68,11 @@ int pbr_ifp_create(struct interface *ifp)
        if (!ifp->info)
                pbr_if_new(ifp);
 
+       /* Update nexthops tracked from a `set nexthop` command */
        pbr_nht_nexthop_interface_update(ifp);
 
+       pbr_map_policy_interface_update(ifp, true);
+
        return 0;
 }
 
@@ -77,6 +81,8 @@ int pbr_ifp_destroy(struct interface *ifp)
        DEBUGD(&pbr_dbg_zebra,
               "%s: %s", __PRETTY_FUNCTION__, ifp->name);
 
+       pbr_map_policy_interface_update(ifp, false);
+
        return 0;
 }
 
@@ -133,6 +139,29 @@ int pbr_ifp_down(struct interface *ifp)
        return 0;
 }
 
+static int interface_vrf_update(ZAPI_CALLBACK_ARGS)
+{
+       struct interface *ifp;
+       vrf_id_t new_vrf_id;
+
+       ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
+                                             &new_vrf_id);
+
+       if (!ifp) {
+               DEBUGD(&pbr_dbg_zebra, "%s: VRF change interface not found",
+                      __func__);
+
+               return 0;
+       }
+
+       DEBUGD(&pbr_dbg_zebra, "%s: %s VRF change %u -> %u", __func__,
+              ifp->name, vrf_id, new_vrf_id);
+
+       if_update_to_new_vrf(ifp, new_vrf_id);
+
+       return 0;
+}
+
 static int route_notify_owner(ZAPI_CALLBACK_ARGS)
 {
        struct prefix p;
@@ -421,6 +450,7 @@ void pbr_zebra_init(void)
        zclient->zebra_connected = zebra_connected;
        zclient->interface_address_add = interface_address_add;
        zclient->interface_address_delete = interface_address_delete;
+       zclient->interface_vrf_update = interface_vrf_update;
        zclient->route_notify_owner = route_notify_owner;
        zclient->rule_notify_owner = rule_notify_owner;
        zclient->nexthop_update = pbr_zebra_nexthop_update;
@@ -483,6 +513,26 @@ static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
        stream_put(s, &p->u.prefix, prefix_blen(p));
 }
 
+static void
+pbr_encode_pbr_map_sequence_vrf(struct stream *s,
+                               const struct pbr_map_sequence *pbrms,
+                               const struct interface *ifp)
+{
+       struct pbr_vrf *pbr_vrf;
+
+       if (pbrms->vrf_unchanged)
+               pbr_vrf = pbr_vrf_lookup_by_id(ifp->vrf_id);
+       else
+               pbr_vrf = pbr_vrf_lookup_by_name(pbrms->vrf_name);
+
+       if (!pbr_vrf) {
+               DEBUGD(&pbr_dbg_zebra, "%s: VRF not found", __func__);
+               return;
+       }
+
+       stream_putl(s, pbr_vrf->vrf->data.l.table_id);
+}
+
 static void pbr_encode_pbr_map_sequence(struct stream *s,
                                        struct pbr_map_sequence *pbrms,
                                        struct interface *ifp)
@@ -501,7 +551,10 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
        pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
        stream_putw(s, 0);  /* dst port */
        stream_putl(s, pbrms->mark);
-       if (pbrms->nhgrp_name)
+
+       if (pbrms->vrf_unchanged || pbrms->vrf_lookup)
+               pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp);
+       else if (pbrms->nhgrp_name)
                stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
        else if (pbrms->nhg)
                stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
index 0f2e7ad8bdb6f7e27e15e95fa351b9c6b0541568..41d0e5a0b88b92ee73a1396bd35576d06fd2b224 100644 (file)
@@ -20,6 +20,7 @@ pbrd_libpbr_a_SOURCES = \
        pbrd/pbr_memory.c \
        pbrd/pbr_nht.c \
        pbrd/pbr_debug.c \
+       pbrd/pbr_vrf.c \
        # end
 
 noinst_HEADERS += \
@@ -29,6 +30,7 @@ noinst_HEADERS += \
        pbrd/pbr_vty.h \
        pbrd/pbr_zebra.h \
        pbrd/pbr_debug.h \
+       pbrd/pbr_vrf.h \
        # end
 
 pbrd/pbr_vty_clippy.c: $(CLIPPY_DEPS)