]> git.proxmox.com Git - mirror_frr.git/blobdiff - pbrd/pbr_map.c
Merge pull request #4765 from opensourcerouting/defaults-v2
[mirror_frr.git] / pbrd / pbr_map.c
index ea79320a712501a12bbd9adc61d3667b383366f6..7e34066b47b32861a428030df57e3e74a4dbc483 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);
 
@@ -71,8 +73,7 @@ static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1,
 
 static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms)
 {
-       if (pbrms->internal_nhg_name)
-               XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
+       XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
 
        XFREE(MTYPE_PBR_MAP_SEQNO, pbrms);
 }
@@ -99,9 +100,55 @@ static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi)
        }
 }
 
-static const char *pbr_map_reason_str[] = {
+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 *const 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)
@@ -121,6 +168,17 @@ void pbr_map_reason_string(unsigned int reason, char *buf, int size)
        }
 }
 
+void pbr_map_final_interface_deletion(struct pbr_map *pbrm,
+                                     struct pbr_map_interface *pmi)
+{
+       if (pmi->delete == true) {
+               listnode_delete(pbrm->incoming, pmi);
+               pmi->pbrm = NULL;
+
+               bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
+               XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
+       }
+}
 
 void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del)
 {
@@ -152,11 +210,99 @@ 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);
 }
 
+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;
@@ -193,30 +339,36 @@ 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);
        }
 }
 
-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;
-       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)
+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)
 {
        struct pbr_map_sequence *pbrms;
        struct listnode *snode, *inode;
@@ -228,6 +380,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",
@@ -268,7 +423,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
        pbrm = pbrm_find(name);
        if (!pbrm) {
                pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
-               strcpy(pbrm->name, name);
+               snprintf(pbrm->name, sizeof(pbrm->name), "%s", name);
 
                pbrm->seqnumbers = list_new();
                pbrm->seqnumbers->cmp =
@@ -284,6 +439,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);
        }
 
@@ -300,13 +456,12 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
                pbrms->ruleno = pbr_nht_get_next_rule(seqno);
                pbrms->parent = pbrm;
                pbrms->reason =
-                       PBR_MAP_INVALID_SRCDST |
+                       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);
-
-               pbrm->installed = false;
        }
 
        return pbrms;
@@ -315,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;
 
@@ -336,10 +515,10 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
        }
 }
 
-static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence *pbrms)
+static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
 {
-       if (!pbrms->src && !pbrms->dst)
-               pbrms->reason |= PBR_MAP_INVALID_SRCDST;
+       if (!pbrms->src && !pbrms->dst && !pbrms->mark)
+               pbrms->reason |= PBR_MAP_INVALID_EMPTY;
 }
 
 /*
@@ -350,7 +529,7 @@ static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
 {
        pbr_map_sequence_check_nexthops_valid(pbrms);
 
-       pbr_map_sequence_check_src_dst_valid(pbrms);
+       pbr_map_sequence_check_not_empty(pbrms);
 }
 
 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm)
@@ -405,7 +584,8 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group)
                       pbrm->name);
                for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
                        DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s",
-                              pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL");
+                              pbrms->nhgrp_name ?
+                              pbrms->nhgrp_name : pbrms->internal_nhg_name);
 
                        if (pbrms->nhgrp_name
                            && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
@@ -443,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);
                }
        }
 }
@@ -461,9 +643,7 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
        for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
                pbr_send_pbr_map(pbrms, pmi, false);
 
-       listnode_delete(pbrm->incoming, pmi);
-       pmi->pbrm = NULL;
-       XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
+       pmi->delete = true;
 }
 
 /*
@@ -512,20 +692,15 @@ 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;
        DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__,
               pbrm->name, pbrms->seqno);
        if (pbr_map_check_valid(pbrm->name))
-               DEBUGD(&pbr_dbg_map, "We are totally valid %s\n",
+               DEBUGD(&pbr_dbg_map, "We are totally valid %s",
                       pbrm->name);
 
-       DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
-              __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, pbrms->reason);
-
        if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
                install = true;
                DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
@@ -541,24 +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);
-
-       pbrm->installed = true;
+               pbr_map_pbrms_install(pbrms);
 }
 
 void pbr_map_init(void)