]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: implement recursive MPLS labels
authorRenato Westphal <renato@opensourcerouting.org>
Wed, 20 Sep 2017 03:05:25 +0000 (00:05 -0300)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 19 Feb 2018 18:22:57 +0000 (13:22 -0500)
When a BGP-labeled route is resolved into an LDP-labeled IGP route,
zebra would install it with no labels in the kernel. This patch implements
recursive MPLS labels, i.e. make zebra install all labels from the route's
nexthop chain (the labels from the top-level nexthop being installed in
the top of the MPLS label stack). Multiple recursion levels are supported.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
zebra/rt_netlink.c

index d7789901419535b337546176f94002b4f0afcfde..a80ab9d83494305679108440afb9ca09d6389bab 100644 (file)
@@ -840,6 +840,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
 {
        struct mpls_label_stack *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
+       int num_labels = 0;
        char label_buf[256];
 
        /*
@@ -849,56 +850,54 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
         * you fix this assumption
         */
        label_buf[0] = '\0';
-       /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
-        * (in the case of LER)
-        */
-       nh_label = nexthop->nh_label;
-       if (rtmsg->rtm_family == AF_MPLS) {
-               assert(nh_label);
-               assert(nh_label->num_labels == 1);
-       }
 
-       if (nh_label && nh_label->num_labels) {
-               int i, num_labels = 0;
-               u_int32_t bos;
+       assert(nexthop);
+       for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
                char label_buf1[20];
 
-               for (i = 0; i < nh_label->num_labels; i++) {
-                       if (nh_label->label[i] != MPLS_LABEL_IMPLICIT_NULL) {
-                               bos = ((i == (nh_label->num_labels - 1)) ? 1
-                                                                        : 0);
-                               out_lse[i] = mpls_lse_encode(nh_label->label[i],
-                                                            0, 0, bos);
-                               if (IS_ZEBRA_DEBUG_KERNEL) {
-                                       if (!num_labels)
-                                               sprintf(label_buf, "label %u",
-                                                       nh_label->label[i]);
-                                       else {
-                                               sprintf(label_buf1, "/%u",
-                                                       nh_label->label[i]);
-                                               strlcat(label_buf, label_buf1,
-                                                       sizeof(label_buf));
-                                       }
+               nh_label = nh->nh_label;
+               if (!nh_label || !nh_label->num_labels)
+                       continue;
+
+               for (int i = 0; i < nh_label->num_labels; i++) {
+                       if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+                               continue;
+
+                       if (IS_ZEBRA_DEBUG_KERNEL) {
+                               if (!num_labels)
+                                       sprintf(label_buf, "label %u",
+                                               nh_label->label[i]);
+                               else {
+                                       sprintf(label_buf1, "/%u",
+                                               nh_label->label[i]);
+                                       strlcat(label_buf, label_buf1,
+                                               sizeof(label_buf));
                                }
-                               num_labels++;
                        }
+
+                       out_lse[num_labels] =
+                               mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+                       num_labels++;
                }
-               if (num_labels) {
-                       if (rtmsg->rtm_family == AF_MPLS)
-                               addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse,
-                                         num_labels * sizeof(mpls_lse_t));
-                       else {
-                               struct rtattr *nest;
-                               u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
-
-                               addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE,
-                                         &encap, sizeof(u_int16_t));
-                               nest = addattr_nest(nlmsg, req_size, RTA_ENCAP);
-                               addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST,
-                                         &out_lse,
-                                         num_labels * sizeof(mpls_lse_t));
-                               addattr_nest_end(nlmsg, nest);
-                       }
+       }
+
+       if (num_labels) {
+               /* Set the BoS bit */
+               out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
+
+               if (rtmsg->rtm_family == AF_MPLS)
+                       addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse,
+                                 num_labels * sizeof(mpls_lse_t));
+               else {
+                       struct rtattr *nest;
+                       u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
+
+                       addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
+                                 sizeof(u_int16_t));
+                       nest = addattr_nest(nlmsg, req_size, RTA_ENCAP);
+                       addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, &out_lse,
+                                 num_labels * sizeof(mpls_lse_t));
+                       addattr_nest_end(nlmsg, nest);
                }
        }
 
@@ -1045,6 +1044,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
 {
        struct mpls_label_stack *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
+       int num_labels = 0;
        char label_buf[256];
 
        rtnh->rtnh_len = sizeof(*rtnh);
@@ -1059,63 +1059,60 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
         * you fix this assumption
         */
        label_buf[0] = '\0';
-       /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
-        * (in the case of LER)
-        */
-       nh_label = nexthop->nh_label;
-       if (rtmsg->rtm_family == AF_MPLS) {
-               assert(nh_label);
-               assert(nh_label->num_labels == 1);
-       }
 
-       if (nh_label && nh_label->num_labels) {
-               int i, num_labels = 0;
-               u_int32_t bos;
+       assert(nexthop);
+       for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
                char label_buf1[20];
 
-               for (i = 0; i < nh_label->num_labels; i++) {
-                       if (nh_label->label[i] != MPLS_LABEL_IMPLICIT_NULL) {
-                               bos = ((i == (nh_label->num_labels - 1)) ? 1
-                                                                        : 0);
-                               out_lse[i] = mpls_lse_encode(nh_label->label[i],
-                                                            0, 0, bos);
-                               if (IS_ZEBRA_DEBUG_KERNEL) {
-                                       if (!num_labels)
-                                               sprintf(label_buf, "label %u",
-                                                       nh_label->label[i]);
-                                       else {
-                                               sprintf(label_buf1, "/%u",
-                                                       nh_label->label[i]);
-                                               strlcat(label_buf, label_buf1,
-                                                       sizeof(label_buf));
-                                       }
+               nh_label = nh->nh_label;
+               if (!nh_label || !nh_label->num_labels)
+                       continue;
+
+               for (int i = 0; i < nh_label->num_labels; i++) {
+                       if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+                               continue;
+
+                       if (IS_ZEBRA_DEBUG_KERNEL) {
+                               if (!num_labels)
+                                       sprintf(label_buf, "label %u",
+                                               nh_label->label[i]);
+                               else {
+                                       sprintf(label_buf1, "/%u",
+                                               nh_label->label[i]);
+                                       strlcat(label_buf, label_buf1,
+                                               sizeof(label_buf));
                                }
-                               num_labels++;
                        }
+
+                       out_lse[num_labels] =
+                               mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+                       num_labels++;
                }
-               if (num_labels) {
-                       if (rtmsg->rtm_family == AF_MPLS) {
-                               rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST,
-                                             &out_lse,
-                                             num_labels * sizeof(mpls_lse_t));
-                               rtnh->rtnh_len += RTA_LENGTH(
-                                       num_labels * sizeof(mpls_lse_t));
-                       } else {
-                               struct rtattr *nest;
-                               u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
-                               int len = rta->rta_len;
-
-                               rta_addattr_l(rta, NL_PKT_BUF_SIZE,
-                                             RTA_ENCAP_TYPE, &encap,
-                                             sizeof(u_int16_t));
-                               nest = rta_nest(rta, NL_PKT_BUF_SIZE,
-                                               RTA_ENCAP);
-                               rta_addattr_l(rta, NL_PKT_BUF_SIZE,
-                                             MPLS_IPTUNNEL_DST, &out_lse,
-                                             num_labels * sizeof(mpls_lse_t));
-                               rta_nest_end(rta, nest);
-                               rtnh->rtnh_len += rta->rta_len - len;
-                       }
+       }
+
+       if (num_labels) {
+               /* Set the BoS bit */
+               out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
+
+               if (rtmsg->rtm_family == AF_MPLS) {
+                       rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST,
+                                     &out_lse,
+                                     num_labels * sizeof(mpls_lse_t));
+                       rtnh->rtnh_len +=
+                               RTA_LENGTH(num_labels * sizeof(mpls_lse_t));
+               } else {
+                       struct rtattr *nest;
+                       u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
+                       int len = rta->rta_len;
+
+                       rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE,
+                                     &encap, sizeof(u_int16_t));
+                       nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP);
+                       rta_addattr_l(rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST,
+                                     &out_lse,
+                                     num_labels * sizeof(mpls_lse_t));
+                       rta_nest_end(rta, nest);
+                       rtnh->rtnh_len += rta->rta_len - len;
                }
        }