zebra: implement recursive MPLS labels

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>
This commit is contained in:
Renato Westphal 2017-09-20 00:05:25 -03:00 committed by Donald Sharp
parent 97133f7f9f
commit fa71296396

View File

@ -840,6 +840,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
{ {
struct mpls_label_stack *nh_label; struct mpls_label_stack *nh_label;
mpls_lse_t out_lse[MPLS_MAX_LABELS]; mpls_lse_t out_lse[MPLS_MAX_LABELS];
int num_labels = 0;
char label_buf[256]; char label_buf[256];
/* /*
@ -849,26 +850,19 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
* you fix this assumption * you fix this assumption
*/ */
label_buf[0] = '\0'; 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) { assert(nexthop);
int i, num_labels = 0; for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
u_int32_t bos;
char label_buf1[20]; char label_buf1[20];
for (i = 0; i < nh_label->num_labels; i++) { nh_label = nh->nh_label;
if (nh_label->label[i] != MPLS_LABEL_IMPLICIT_NULL) { if (!nh_label || !nh_label->num_labels)
bos = ((i == (nh_label->num_labels - 1)) ? 1 continue;
: 0);
out_lse[i] = mpls_lse_encode(nh_label->label[i], for (int i = 0; i < nh_label->num_labels; i++) {
0, 0, bos); if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
continue;
if (IS_ZEBRA_DEBUG_KERNEL) { if (IS_ZEBRA_DEBUG_KERNEL) {
if (!num_labels) if (!num_labels)
sprintf(label_buf, "label %u", sprintf(label_buf, "label %u",
@ -880,10 +874,17 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
sizeof(label_buf)); sizeof(label_buf));
} }
} }
out_lse[num_labels] =
mpls_lse_encode(nh_label->label[i], 0, 0, 0);
num_labels++; num_labels++;
} }
} }
if (num_labels) { if (num_labels) {
/* Set the BoS bit */
out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
if (rtmsg->rtm_family == AF_MPLS) if (rtmsg->rtm_family == AF_MPLS)
addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse, addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse,
num_labels * sizeof(mpls_lse_t)); num_labels * sizeof(mpls_lse_t));
@ -891,16 +892,14 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
struct rtattr *nest; struct rtattr *nest;
u_int16_t encap = LWTUNNEL_ENCAP_MPLS; u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
&encap, sizeof(u_int16_t)); sizeof(u_int16_t));
nest = addattr_nest(nlmsg, req_size, RTA_ENCAP); nest = addattr_nest(nlmsg, req_size, RTA_ENCAP);
addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, &out_lse,
&out_lse,
num_labels * sizeof(mpls_lse_t)); num_labels * sizeof(mpls_lse_t));
addattr_nest_end(nlmsg, nest); addattr_nest_end(nlmsg, nest);
} }
} }
}
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
rtmsg->rtm_flags |= RTNH_F_ONLINK; rtmsg->rtm_flags |= RTNH_F_ONLINK;
@ -1045,6 +1044,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
{ {
struct mpls_label_stack *nh_label; struct mpls_label_stack *nh_label;
mpls_lse_t out_lse[MPLS_MAX_LABELS]; mpls_lse_t out_lse[MPLS_MAX_LABELS];
int num_labels = 0;
char label_buf[256]; char label_buf[256];
rtnh->rtnh_len = sizeof(*rtnh); rtnh->rtnh_len = sizeof(*rtnh);
@ -1059,26 +1059,19 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
* you fix this assumption * you fix this assumption
*/ */
label_buf[0] = '\0'; 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) { assert(nexthop);
int i, num_labels = 0; for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
u_int32_t bos;
char label_buf1[20]; char label_buf1[20];
for (i = 0; i < nh_label->num_labels; i++) { nh_label = nh->nh_label;
if (nh_label->label[i] != MPLS_LABEL_IMPLICIT_NULL) { if (!nh_label || !nh_label->num_labels)
bos = ((i == (nh_label->num_labels - 1)) ? 1 continue;
: 0);
out_lse[i] = mpls_lse_encode(nh_label->label[i], for (int i = 0; i < nh_label->num_labels; i++) {
0, 0, bos); if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
continue;
if (IS_ZEBRA_DEBUG_KERNEL) { if (IS_ZEBRA_DEBUG_KERNEL) {
if (!num_labels) if (!num_labels)
sprintf(label_buf, "label %u", sprintf(label_buf, "label %u",
@ -1090,34 +1083,38 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
sizeof(label_buf)); sizeof(label_buf));
} }
} }
out_lse[num_labels] =
mpls_lse_encode(nh_label->label[i], 0, 0, 0);
num_labels++; num_labels++;
} }
} }
if (num_labels) { if (num_labels) {
/* Set the BoS bit */
out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
if (rtmsg->rtm_family == AF_MPLS) { if (rtmsg->rtm_family == AF_MPLS) {
rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST, rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST,
&out_lse, &out_lse,
num_labels * sizeof(mpls_lse_t)); num_labels * sizeof(mpls_lse_t));
rtnh->rtnh_len += RTA_LENGTH( rtnh->rtnh_len +=
num_labels * sizeof(mpls_lse_t)); RTA_LENGTH(num_labels * sizeof(mpls_lse_t));
} else { } else {
struct rtattr *nest; struct rtattr *nest;
u_int16_t encap = LWTUNNEL_ENCAP_MPLS; u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
int len = rta->rta_len; int len = rta->rta_len;
rta_addattr_l(rta, NL_PKT_BUF_SIZE, rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE,
RTA_ENCAP_TYPE, &encap, &encap, sizeof(u_int16_t));
sizeof(u_int16_t)); nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP);
nest = rta_nest(rta, NL_PKT_BUF_SIZE, rta_addattr_l(rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST,
RTA_ENCAP); &out_lse,
rta_addattr_l(rta, NL_PKT_BUF_SIZE,
MPLS_IPTUNNEL_DST, &out_lse,
num_labels * sizeof(mpls_lse_t)); num_labels * sizeof(mpls_lse_t));
rta_nest_end(rta, nest); rta_nest_end(rta, nest);
rtnh->rtnh_len += rta->rta_len - len; rtnh->rtnh_len += rta->rta_len - len;
} }
} }
}
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
rtnh->rtnh_flags |= RTNH_F_ONLINK; rtnh->rtnh_flags |= RTNH_F_ONLINK;