]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd, zebra: auto assign labels from label pool to regular prefixes in BGP labeled...
authorAnton Degtyarev <adeg47@gmail.com>
Wed, 14 Nov 2018 03:14:04 +0000 (06:14 +0300)
committerAnton Degtyarev <adeg47@gmail.com>
Thu, 20 Dec 2018 12:28:52 +0000 (15:28 +0300)
This commit is the last missing piece to complete BGP LU support in bgpd. To this moment, bgpd (and zebra) supported auto label assignment only for prefixes leaked from VRFs to vpn and for MPLS SR prefixes. This adds auto label assignment to other routes types in bgpd. The following enhancements have been made:
* bgp_route.c:bgp_process_main_one() now sets implicit-null local_label to all local, aggregate and redistributed routes.
* bgp_route.c:bgp_process_main_one() now will request a label from the label pool for any prefix that loses the label for some reason (for example, when the static label assignment config is removed)
* bgp_label.c:bgp_reg_dereg_for_label() now requests labels from label pool for routes which have no associated label index
* zebra_mpls.c:zebra_mpls_fec_register() now expects both label and label_index from the calling function, one of which must be set to MPLS_INVALID_LABEL or MPLS_INVALID_LABEL_INDEX, based on this it will decide how to register the provided FEC.

Signed-off-by: Anton Degtyarev <anton@cumulusnetworks.com>
bgpd/bgp_label.c
bgpd/bgp_label.h
bgpd/bgp_labelpool.h
bgpd/bgp_route.c
lib/zclient.h
lib/zebra.h
zebra/zapi_msg.c
zebra/zebra_errors.c
zebra/zebra_errors.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h

index dcaaea6868c7fd89d2e32659278e9f33a6931328..a219c407dabd861f71b68aae00dc0cab95bce357 100644 (file)
@@ -120,20 +120,141 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,
        return rn->local_label;
 }
 
+/**
+ * This is passed as the callback function to bgp_labelpool.c:bgp_lp_get()
+ * by bgp_reg_dereg_for_label() when a label needs to be obtained from
+ * label pool.
+ * Note that it will reject the allocated label if a label index is found,
+ * because the label index supposes predictable labels
+ */
+int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
+                              bool allocated)
+{
+       struct bgp_path_info *pi = (struct bgp_path_info *)labelid;
+       struct bgp_node *rn = (struct bgp_node *)pi->net;
+       char addr[PREFIX_STRLEN];
+
+       prefix2str(&rn->p, addr, PREFIX_STRLEN);
+
+       if (BGP_DEBUG(labelpool, LABELPOOL))
+               zlog_debug("%s: FEC %s label=%u, allocated=%d", __func__, addr,
+                          new_label, allocated);
+
+       if (!allocated) {
+               /*
+                * previously-allocated label is now invalid
+                */
+               if (pi->attr->label_index == MPLS_INVALID_LABEL_INDEX
+                   && pi->attr->label != MPLS_LABEL_NONE
+                   && CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
+                       bgp_unregister_for_label(rn);
+                       label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1,
+                                  &rn->local_label);
+                       bgp_set_valid_label(&rn->local_label);
+               }
+               return 0;
+       }
+
+       /*
+        * label index is assigned, this should be handled by SR-related code,
+        * so retry FEC registration and then reject label allocation for
+        * it to be released to label pool
+        */
+       if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) {
+               flog_err(
+                       EC_BGP_LABEL,
+                       "%s: FEC %s Rejecting allocated label %u as Label Index is %u",
+                       __func__, addr, new_label, pi->attr->label_index);
+
+               bgp_register_for_label(pi->net, pi);
+
+               return -1;
+       }
+
+       if (pi->attr->label != MPLS_INVALID_LABEL) {
+               if (new_label == pi->attr->label) {
+                       /* already have same label, accept but do nothing */
+                       return 0;
+               }
+               /* Shouldn't happen: different label allocation */
+               flog_err(EC_BGP_LABEL,
+                        "%s: %s had label %u but got new assignment %u",
+                        __func__, addr, pi->attr->label, new_label);
+               /* continue means use new one */
+       }
+
+       label_ntop(new_label, 1, &rn->local_label);
+       bgp_set_valid_label(&rn->local_label);
+
+       /*
+        * Get back to registering the FEC
+        */
+       bgp_register_for_label(pi->net, pi);
+
+       return 0;
+}
+
 void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,
-                            int reg)
+                            bool reg)
 {
+       bool with_label_index = false;
        struct stream *s;
        struct prefix *p;
+       mpls_label_t *local_label;
        int command;
        uint16_t flags = 0;
        size_t flags_pos = 0;
+       char addr[PREFIX_STRLEN];
+
+       p = &(rn->p);
+       local_label = &(rn->local_label);
+       /* this prevents the loop when we're called by
+        * bgp_reg_for_label_callback()
+        */
+       bool have_label_to_reg = bgp_is_valid_label(local_label)
+                       && label_pton(local_label) != MPLS_LABEL_IMPLICIT_NULL;
+
+       if (reg) {
+               assert(pi);
+               /*
+                * Determine if we will let zebra should derive label from
+                * label index instead of bgpd requesting from label pool
+                */
+               if (CHECK_FLAG(pi->attr->flag,
+                           ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))
+                       && pi->attr->label_index != BGP_INVALID_LABEL_INDEX) {
+                       with_label_index = true;
+               } else {
+                       /*
+                        * If no label index was provided -- assume any label
+                        * from label pool will do. This means that label index
+                        * always takes precedence over auto-assigned labels.
+                        */
+                       if (!have_label_to_reg) {
+                               if (BGP_DEBUG(labelpool, LABELPOOL)) {
+                                       prefix2str(p, addr, PREFIX_STRLEN);
+                                       zlog_debug("%s: Requesting label from LP for %s",
+                                                __func__, addr);
+                               }
+                               /* bgp_reg_for_label_callback() will call back
+                                * __func__ when it gets a label from the pool.
+                                * This means we'll never register FECs without
+                                * valid labels.
+                                */
+                               bgp_lp_get(LP_TYPE_BGP_LU, pi,
+                                   bgp_reg_for_label_callback);
+                               return;
+                       }
+               }
+       }
 
        /* Check socket. */
        if (!zclient || zclient->sock < 0)
                return;
 
-       p = &(rn->p);
+       /* If the route node has a local_label assigned or the
+        * path node has an MPLS SR label index allowing zebra to
+        * derive the label, proceed with registration. */
        s = zclient->obuf;
        stream_reset(s);
        command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
@@ -143,12 +264,12 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,
        stream_putw(s, PREFIX_FAMILY(p));
        stream_put_prefix(s, p);
        if (reg) {
-               assert(pi);
-               if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
-                       if (pi->attr->label_index != BGP_INVALID_LABEL_INDEX) {
-                               flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
-                               stream_putl(s, pi->attr->label_index);
-                       }
+               if (have_label_to_reg) {
+                       flags |= ZEBRA_FEC_REGISTER_LABEL;
+                       stream_putl(s, label_pton(local_label));
+               } else if (with_label_index) {
+                       flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+                       stream_putl(s, pi->attr->label_index);
                }
                SET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
        } else
index b0fc07e5477060ed8b06a4247ec8c4af4c518852..89bc9aabb03b18c8efdbdb1a18480be63d3c97f2 100644 (file)
@@ -30,8 +30,10 @@ struct bgp_node;
 struct bgp_path_info;
 struct peer;
 
+extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
+                                   bool allocated);
 extern void bgp_reg_dereg_for_label(struct bgp_node *rn,
-                                   struct bgp_path_info *pi, int reg);
+                                   struct bgp_path_info *pi, bool reg);
 extern int bgp_parse_fec_update(void);
 extern mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,
                                  struct peer *to, afi_t afi, safi_t safi);
@@ -87,12 +89,12 @@ static inline void bgp_unset_valid_label(mpls_label_t *label)
 static inline void bgp_register_for_label(struct bgp_node *rn,
                                          struct bgp_path_info *pi)
 {
-       bgp_reg_dereg_for_label(rn, pi, 1);
+       bgp_reg_dereg_for_label(rn, pi, true);
 }
 
 static inline void bgp_unregister_for_label(struct bgp_node *rn)
 {
-       bgp_reg_dereg_for_label(rn, NULL, 0);
+       bgp_reg_dereg_for_label(rn, NULL, false);
 }
 
 /* Label stream to value */
index fa35cde0e12616479f50e7d35c5d156d9a9976ed..0507e65489e4cd7405cd43329d775e140c7ec983 100644 (file)
@@ -29,6 +29,7 @@
  * Types used in bgp_lp_get for debug tracking; add more as needed
  */
 #define LP_TYPE_VRF    0x00000001
+#define LP_TYPE_BGP_LU 0x00000002
 
 struct labelpool {
        struct skiplist         *ledger;        /* all requests */
index 23002fb74ca842184fdb2a01ebbf788ba49b995d..2c361bef4d5b2693f85bd1289914d44da0a86176 100644 (file)
@@ -2265,20 +2265,26 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
 
        /* Do we need to allocate or free labels?
         * Right now, since we only deal with per-prefix labels, it is not
-        * necessary to do this upon changes to best path except if the label
-        * index changes
+        * necessary to do this upon changes to best path. Exceptions:
+        * - label index has changed -> recalculate resulting label
+        * - path_info sub_type changed -> switch to/from implicit-null
+        * - no valid label (due to removed static label binding) -> get new one
         */
        if (bgp->allocate_mpls_labels[afi][safi]) {
                if (new_select) {
                        if (!old_select
                            || bgp_label_index_differs(new_select, old_select)
-                           || new_select->sub_type != old_select->sub_type) {
+                           || new_select->sub_type != old_select->sub_type
+                           || !bgp_is_valid_label(&rn->local_label)) {
+                               /* Enforced penultimate hop popping:
+                                * implicit-null for local routes, aggregate
+                                * and redistributed routes
+                                */
                                if (new_select->sub_type == BGP_ROUTE_STATIC
-                                   && new_select->attr->flag
-                                              & ATTR_FLAG_BIT(
-                                                        BGP_ATTR_PREFIX_SID)
-                                   && new_select->attr->label_index
-                                              != BGP_INVALID_LABEL_INDEX) {
+                                   || new_select->sub_type
+                                               == BGP_ROUTE_AGGREGATE
+                                   || new_select->sub_type
+                                               == BGP_ROUTE_REDISTRIBUTE) {
                                        if (CHECK_FLAG(
                                                    rn->flags,
                                                    BGP_NODE_REGISTERED_FOR_LABEL))
index adb48b252a6973e692edbe7f77e40b4668cbc92d..8fe711f31044f24fe8126b247c143056031709c5 100644 (file)
 #define ZEBRA_IPTABLES_FORWARD 0
 #define ZEBRA_IPTABLES_DROP    1
 
+/* Zebra FEC register command flags. */
+#define ZEBRA_FEC_REGISTER_LABEL          0x1
+#define ZEBRA_FEC_REGISTER_LABEL_INDEX    0x2
+
 extern struct sockaddr_storage zclient_addr;
 extern socklen_t zclient_addr_len;
 
index 0f3f45f7ba1807a8344e47ba95c5f769c2ede43e..09115951e9b6028cced52107f2e9cc01b4fc8f60 100644 (file)
@@ -452,9 +452,6 @@ extern const char *zserv_command_string(unsigned int command);
  */
 #define ZEBRA_FLAG_ONLINK             0x80
 
-/* Zebra FEC flags. */
-#define ZEBRA_FEC_REGISTER_LABEL_INDEX        0x1
-
 #ifndef INADDR_LOOPBACK
 #define        INADDR_LOOPBACK 0x7f000001      /* Internet address 127.0.0.1.  */
 #endif
index 9b84a6e58a5c5f0ca0f8b7edcabe41f9109dc921..26a3cd5b42a03fca4dd06072525006c85cd3f5c9 100644 (file)
@@ -1187,6 +1187,7 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
        unsigned short l = 0;
        struct prefix p;
        uint16_t flags;
+       uint32_t label = MPLS_INVALID_LABEL;
        uint32_t label_index = MPLS_INVALID_LABEL_INDEX;
 
        s = msg;
@@ -1229,12 +1230,15 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
                l += 5;
                STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
                l += PSIZE(p.prefixlen);
-               if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) {
+               if (flags & ZEBRA_FEC_REGISTER_LABEL) {
+                       STREAM_GETL(s, label);
+                       l += 4;
+               } else if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) {
                        STREAM_GETL(s, label_index);
                        l += 4;
-               } else
-                       label_index = MPLS_INVALID_LABEL_INDEX;
-               zebra_mpls_fec_register(zvrf, &p, label_index, client);
+               }
+
+               zebra_mpls_fec_register(zvrf, &p, label, label_index, client);
        }
 
 stream_failure:
index 32f665383245268855546e4fb35703fd6e1066d8..d7c17829cdc61b61349fd1e91efceccf8af149c3 100644 (file)
@@ -85,6 +85,12 @@ static struct log_ref ferr_zebra_err[] = {
                .description = "A client requested a label binding for a new FEC, but Zebra was unable to add the FEC to its internal table.",
                .suggestion = "Notify a developer.",
        },
+       {
+               .code = EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
+               .title = "Refused to add FEC for MPLS client with both label index and label specified",
+               .description = "A client requested a label binding for a new FEC specifying a label index and a label at the same time.",
+               .suggestion = "Notify a developer.",
+       },
        {
                .code = EC_ZEBRA_FEC_RM_FAILED,
                .title = "Failed to remove FEC for MPLS client",
index cf2d6a7cf51ef0f5df5440041e1c56d165d9ebf3..c3cdc4ed421757e87df91e95d20d49565a0fe6a1 100644 (file)
@@ -37,6 +37,7 @@ enum zebra_log_refs {
        EC_ZEBRA_DP_INVALID_RC,
        EC_ZEBRA_WQ_NONEXISTENT,
        EC_ZEBRA_FEC_ADD_FAILED,
+       EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
        EC_ZEBRA_FEC_RM_FAILED,
        EC_ZEBRA_IRDP_LEN_MISMATCH,
        EC_ZEBRA_RNH_UNKNOWN_FAMILY,
index 5fe01161586c76fbd44b4a697aed718c26009d76..c0764cd4b8c6090226be791dac19a3d0af8ff7dc 100644 (file)
@@ -1813,17 +1813,22 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
  * NOTE: If there is a manually configured label binding, that is used.
  * Otherwise, if a label index is specified, it means we have to allocate the
  * label from a locally configured label block (SRGB), if one exists and index
- * is acceptable.
+ * is acceptable. If no label index then just register the specified label.
+ * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
+ * by the calling function. Register requests with both will be rejected.
  */
 int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
-                           uint32_t label_index, struct zserv *client)
+                           uint32_t label, uint32_t label_index,
+                           struct zserv *client)
 {
        struct route_table *table;
        zebra_fec_t *fec;
        char buf[BUFSIZ];
-       int new_client;
-       int label_change = 0;
+       bool new_client;
+       bool label_change = false;
        uint32_t old_label;
+       bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
+       bool is_configured_fec = false; /* indicate statically configured FEC */
 
        table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
        if (!table)
@@ -1832,12 +1837,20 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
        if (IS_ZEBRA_DEBUG_MPLS)
                prefix2str(p, buf, BUFSIZ);
 
+       if (label != MPLS_INVALID_LABEL && have_label_index) {
+               flog_err(
+                       EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
+                       "Rejecting FEC register for %s with both label %u and Label Index %u specified, client %s",
+                       buf, label, label_index,
+                       zebra_route_string(client->proto));
+               return -1;
+       }
+
        /* Locate FEC */
        fec = fec_find(table, p);
        if (!fec) {
-               fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index);
+               fec = fec_add(table, p, label, 0, label_index);
                if (!fec) {
-                       prefix2str(p, buf, BUFSIZ);
                        flog_err(
                                EC_ZEBRA_FEC_ADD_FAILED,
                                "Failed to add FEC %s upon register, client %s",
@@ -1846,16 +1859,19 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
                }
 
                old_label = MPLS_INVALID_LABEL;
-               new_client = 1;
+               new_client = true;
        } else {
+               /* Check if the FEC has been statically defined in the config */
+               is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
                /* Client may register same FEC with different label index. */
                new_client =
                        (listnode_lookup(fec->client_list, client) == NULL);
-               if (!new_client && fec->label_index == label_index)
+               if (!new_client && fec->label_index == label_index
+                   && fec->label == label)
                        /* Duplicate register */
                        return 0;
 
-               /* Save current label, update label index */
+               /* Save current label, update the FEC */
                old_label = fec->label;
                fec->label_index = label_index;
        }
@@ -1864,21 +1880,29 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
                listnode_add(fec->client_list, client);
 
        if (IS_ZEBRA_DEBUG_MPLS)
-               zlog_debug("FEC %s Label Index %u %s by client %s", buf,
-                          label_index, new_client ? "registered" : "updated",
-                          zebra_route_string(client->proto));
-
-       /* If not a configured FEC, derive the local label (from label index)
-        * or reset it.
+               zlog_debug("FEC %s label%s %u %s by client %s%s", buf,
+                          have_label_index ? " index" : "",
+                          have_label_index ? label_index : label,
+                          new_client ? "registered" : "updated",
+                          zebra_route_string(client->proto),
+                          is_configured_fec
+                                  ? ", but using statically configured label"
+                                  : "");
+
+       /* If not a statically configured FEC, derive the local label
+        * from label index or use the provided label
         */
-       if (!(fec->flags & FEC_FLAG_CONFIGURED)) {
-               fec_derive_label_from_index(zvrf, fec);
+       if (!is_configured_fec) {
+               if (have_label_index)
+                       fec_derive_label_from_index(zvrf, fec);
+               else
+                       fec->label = label;
 
                /* If no label change, exit. */
                if (fec->label == old_label)
                        return 0;
 
-               label_change = 1;
+               label_change = true;
        }
 
        /* If new client or label change, update client and install or uninstall
@@ -2106,8 +2130,8 @@ int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
 
        if (IS_ZEBRA_DEBUG_MPLS) {
                prefix2str(p, buf, BUFSIZ);
-               zlog_debug("Delete fec %s label index %u", buf,
-                          fec->label_index);
+               zlog_debug("Delete fec %s label %u label index %u", buf,
+                          fec->label, fec->label_index);
        }
 
        old_label = fec->label;
index 86bee129cfe51c68a89cc47a4ac5569e70399bdf..c250fc4058cc80b7e15db132e71a2648e0a76447 100644 (file)
@@ -191,16 +191,9 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
 int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
                             struct route_entry *re);
 
-/*
- * Registration from a client for the label binding for a FEC. If a binding
- * already exists, it is informed to the client.
- * NOTE: If there is a manually configured label binding, that is used.
- * Otherwise, if aa label index is specified, it means we have to allocate the
- * label from a locally configured label block (SRGB), if one exists and index
- * is acceptable.
- */
 int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
-                           uint32_t label_index, struct zserv *client);
+                           uint32_t label, uint32_t label_index,
+                           struct zserv *client);
 
 /*
  * Deregistration from a client for the label binding for a FEC. The FEC