summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/package-build/frr/patches/frr/0010-bgp-Support-multiple-labels-in-BGP-LU.patch662
1 files changed, 662 insertions, 0 deletions
diff --git a/scripts/package-build/frr/patches/frr/0010-bgp-Support-multiple-labels-in-BGP-LU.patch b/scripts/package-build/frr/patches/frr/0010-bgp-Support-multiple-labels-in-BGP-LU.patch
new file mode 100644
index 00000000..ba37123f
--- /dev/null
+++ b/scripts/package-build/frr/patches/frr/0010-bgp-Support-multiple-labels-in-BGP-LU.patch
@@ -0,0 +1,662 @@
+From 2fc836b3a2f7778d311e385966e3b2f00eebba1b Mon Sep 17 00:00:00 2001
+From: Kyrylo Yatsenko <hedrok@gmail.com>
+Date: Fri, 31 Oct 2025 21:20:20 +0200
+Subject: [PATCH] bgpd: Support multiple labels in BGP-LU
+
+Updated behaviour for SAFI_LABELED_UNICAST to support multiple labels:
+
+* Change BGP_MAX_LABELS 2 -> 10 (maximum possible number of labels for
+ BGP-LU), previously for SAFI_LABELED_UNICAST only one label was
+ supported
+* Save all labels when receiving an update event in
+ `bgp_nlri_get_labels`, send them all to zebra in
+ `bgp_zebra_announce_parse_nexthop`
+
+One of uses of multiple labels is SR-TE with BGP-LU.
+
+Resolves #19506
+
+cherry-picked-from: 17a082ee3a5d1295c27323773c523c945af12c3d
+
+Signed-off-by: Kyrylo Yatsenko <hedrok@gmail.com>
+---
+ bgpd/bgp_attr.c | 13 +++-
+ bgpd/bgp_debug.c | 6 +-
+ bgpd/bgp_label.c | 142 ++++++++++++++++++++++++++++++---------
+ bgpd/bgp_label.h | 30 +++++++--
+ bgpd/bgp_mplsvpn.c | 25 -------
+ bgpd/bgp_mplsvpn.h | 2 -
+ bgpd/bgp_route.c | 56 +++++++++------
+ bgpd/bgp_updgrp_packet.c | 14 ++--
+ bgpd/bgp_zebra.c | 47 +++++++++----
+ 9 files changed, 223 insertions(+), 112 deletions(-)
+
+diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
+index 1a2fa8318e..53e54b9c12 100644
+--- a/bgpd/bgp_attr.c
++++ b/bgpd/bgp_attr.c
+@@ -4280,6 +4280,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
+ uint8_t num_labels, bool addpath_capable,
+ uint32_t addpath_tx_id, struct attr *attr)
+ {
++ mpls_label_t restore_label;
++
+ switch (safi) {
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+@@ -4304,9 +4306,16 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
+ assert(!"Add encoding bits here for other AFI's");
+ break;
+ case SAFI_LABELED_UNICAST:
++ if (num_labels > 1) {
++ zlog_warn("%s: stream_put_labeled_prefix currently supports only one label, ignoring rest (num_labels=%d)",
++ __func__, num_labels);
++ restore_label = label[0];
++ label_set_bos(&label[0]);
++ }
+ /* Prefix write with label. */
+- stream_put_labeled_prefix(s, p, label, addpath_capable,
+- addpath_tx_id);
++ stream_put_labeled_prefix(s, p, label, addpath_capable, addpath_tx_id);
++ if (num_labels > 1)
++ label[0] = restore_label;
+ break;
+ case SAFI_FLOWSPEC:
+ stream_putc(s, p->u.prefix_flowspec.prefixlen);
+diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
+index 97c3e5740f..06b9543114 100644
+--- a/bgpd/bgp_debug.c
++++ b/bgpd/bgp_debug.c
+@@ -2767,11 +2767,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
+ snprintf(tag_buf, sizeof(tag_buf), " label %s",
+ tag_buf2);
+ } else {
+- uint32_t label_value;
+-
+- label_value = decode_label(label);
+- snprintf(tag_buf, sizeof(tag_buf), " label %u",
+- label_value);
++ mpls_labels2str(label, num_labels, " label ", tag_buf, sizeof(tag_buf));
+ }
+ }
+
+diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
+index 8ed9584b0a..fc2ab78371 100644
+--- a/bgpd/bgp_label.c
++++ b/bgpd/bgp_label.c
+@@ -198,19 +198,20 @@ int bgp_parse_fec_update(void)
+ return 1;
+ }
+
+-mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
+- struct peer *to, afi_t afi, safi_t safi)
++void bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi, struct peer *to, afi_t afi,
++ safi_t safi, mpls_label_t *labels, uint8_t *num_labels)
+ {
+ struct peer *from;
+- mpls_label_t remote_label;
+ int reflect;
++ uint8_t i;
++ bool use_local_label = true;
+
+- if (!dest || !pi || !to)
+- return MPLS_INVALID_LABEL;
++ labels[0] = MPLS_INVALID_LABEL;
++ if (!dest || !pi || !to) {
++ *num_labels = 0;
++ return;
++ }
+
+- remote_label = BGP_PATH_INFO_NUM_LABELS(pi)
+- ? pi->extra->labels->label[0]
+- : MPLS_INVALID_LABEL;
+ from = pi->peer;
+ reflect =
+ ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
+@@ -218,12 +219,19 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
+ if (reflect
+ && !CHECK_FLAG(to->af_flags[afi][safi],
+ PEER_FLAG_FORCE_NEXTHOP_SELF))
+- return remote_label;
++ use_local_label = false;
+
+ if (CHECK_FLAG(to->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))
+- return remote_label;
++ use_local_label = false;
+
+- return dest->local_label;
++ if (use_local_label) {
++ *num_labels = 1;
++ labels[0] = dest->local_label;
++ } else {
++ *num_labels = BGP_PATH_INFO_NUM_LABELS(pi);
++ for (i = 0; i < *num_labels; i++)
++ labels[i] = pi->extra->labels->label[i];
++ }
+ }
+
+ static void bgp_send_fec_register_label_msg(struct bgp_dest *dest, bool reg,
+@@ -414,35 +422,50 @@ void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi,
+ dest, reg, with_label_index ? pi->attr->label_index : 0);
+ }
+
+-static int bgp_nlri_get_labels(struct peer *peer, uint8_t *pnt, uint8_t plen,
+- mpls_label_t *label)
++/* Labels must have BGP_MAX_LABELS elements */
++static int bgp_nlri_get_labels(struct peer *peer, uint8_t *pnt, uint8_t plen, mpls_label_t *labels,
++ uint8_t *num_labels)
+ {
+ uint8_t *data = pnt;
+ uint8_t *lim = pnt + plen;
+ uint8_t llen = 0;
+ uint8_t label_depth = 0;
++ mpls_label_t *label_pnt;
++ mpls_label_t label;
+
+ if (plen < BGP_LABEL_BYTES)
+ return 0;
+
+- for (; data < lim; data += BGP_LABEL_BYTES) {
+- memcpy(label, data, BGP_LABEL_BYTES);
++ label_pnt = &labels[0];
++ for (; (data + BGP_LABEL_BYTES) <= lim; data += BGP_LABEL_BYTES, label_pnt++) {
++ /*
++ * Support only BGP_MAX_LABELS, read rest to local variable and
++ * discard, shouldn't be possible - see comment to BGP_MAX_LABELS
++ */
++ if (label_depth >= BGP_MAX_LABELS)
++ label_pnt = &label;
++
++ memcpy(label_pnt, data, BGP_LABEL_BYTES);
+ llen += BGP_LABEL_BYTES;
+
+- bgp_set_valid_label(label);
++ bgp_set_valid_label(label_pnt);
++
+ label_depth += 1;
+
+- if (bgp_is_withdraw_label(label) || label_bos(label))
++ if (bgp_is_withdraw_label(label_pnt) || label_bos(label_pnt))
+ break;
+ }
+
+- /* If we RX multiple labels we will end up keeping only the last
+- * one. We do not yet support a label stack greater than 1. */
+- if (label_depth > 1)
+- zlog_info("%pBP rcvd UPDATE with label stack %d deep", peer,
+- label_depth);
++ *num_labels = label_depth;
+
+- if (!(bgp_is_withdraw_label(label) || label_bos(label)))
++ if (label_depth > BGP_MAX_LABELS) {
++ *num_labels = BGP_MAX_LABELS;
++ label_set_bos(&labels[*num_labels - 1]);
++ zlog_info("%pBP rcvd UPDATE with label stack %d deep, using only first %d labels",
++ peer, label_depth, BGP_MAX_LABELS);
++ }
++
++ if (!(bgp_is_withdraw_label(label_pnt) || label_bos(label_pnt)))
+ flog_warn(
+ EC_BGP_INVALID_LABEL_STACK,
+ "%pBP rcvd UPDATE with invalid label stack - no bottom of stack",
+@@ -463,7 +486,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
+ safi_t safi;
+ bool addpath_capable;
+ uint32_t addpath_id;
+- mpls_label_t label = MPLS_INVALID_LABEL;
++ mpls_label_t labels[MPLS_MAX_LABELS] = { MPLS_INVALID_LABEL };
++ uint8_t num_labels = 0;
+ uint8_t llen;
+
+ pnt = packet->nlri;
+@@ -507,7 +531,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
+ }
+
+ /* Fill in the labels */
+- llen = bgp_nlri_get_labels(peer, pnt, psize, &label);
++ llen = bgp_nlri_get_labels(peer, pnt, psize, labels, &num_labels);
+ if (llen == 0) {
+ flog_err(
+ EC_BGP_UPDATE_RCV,
+@@ -574,13 +598,11 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
+ }
+
+ if (attr) {
+- bgp_update(peer, &p, addpath_id, attr, packet->afi,
+- safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
+- NULL, &label, 1, 0, NULL);
++ bgp_update(peer, &p, addpath_id, attr, packet->afi, safi, ZEBRA_ROUTE_BGP,
++ BGP_ROUTE_NORMAL, NULL, labels, num_labels, 0, NULL);
+ } else {
+- bgp_withdraw(peer, &p, addpath_id, packet->afi,
+- SAFI_UNICAST, ZEBRA_ROUTE_BGP,
+- BGP_ROUTE_NORMAL, NULL, &label, 1);
++ bgp_withdraw(peer, &p, addpath_id, packet->afi, SAFI_UNICAST,
++ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, labels, num_labels);
+ }
+ }
+
+@@ -596,6 +618,37 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
+ return BGP_NLRI_PARSE_OK;
+ }
+
++uint32_t decode_label(mpls_label_t *label_pnt)
++{
++ uint32_t l;
++ uint8_t *pnt = (uint8_t *)label_pnt;
++
++ l = ((uint32_t)*pnt++ << 12);
++ l |= (uint32_t)*pnt++ << 4;
++ l |= (uint32_t)((*pnt & 0xf0) >> 4);
++ return l;
++}
++
++void encode_label_bos(mpls_label_t label, mpls_label_t *label_pnt, bool bos)
++{
++ uint8_t *pnt = (uint8_t *)label_pnt;
++
++ if (pnt == NULL)
++ return;
++ if (label == BGP_PREVENT_VRF_2_VRF_LEAK) {
++ *label_pnt = label;
++ return;
++ }
++ *pnt++ = (label >> 12) & 0xff;
++ *pnt++ = (label >> 4) & 0xff;
++ *pnt++ = ((label << 4) + (bos ? 1 : 0)) & 0xff;
++}
++
++void encode_label(mpls_label_t label, mpls_label_t *label_pnt)
++{
++ encode_label_bos(label, label_pnt, true);
++}
++
+ bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a,
+ const mpls_label_t *tbl_b, const uint8_t num_labels_b)
+ {
+@@ -612,3 +665,30 @@ bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a,
+ }
+ return true;
+ }
++
++char *mpls_labels2str(mpls_label_t *labels, uint8_t num_labels, const char *prefix, char *buf,
++ int size)
++{
++ uint32_t label_value;
++ uint32_t len = 0;
++ uint8_t i;
++
++ buf[0] = '\0';
++ if (!num_labels)
++ return buf;
++
++ if (prefix) {
++ strlcat(buf + len, prefix, size - len);
++ len = strlen(buf);
++ }
++
++ label_value = decode_label(&labels[0]);
++ len += snprintf(buf + len, size - len, "%u", label_value);
++
++ for (i = 1; i < num_labels; i++) {
++ label_value = decode_label(&labels[i]);
++ len += snprintf(buf + len, size - len, "/%u", label_value);
++ }
++
++ return buf;
++}
+diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
+index 2ffd5b699d..ab972c4830 100644
+--- a/bgpd/bgp_label.h
++++ b/bgpd/bgp_label.h
+@@ -16,9 +16,15 @@ struct bgp_path_info;
+ struct peer;
+
+ /* Maximum number of labels we can process or send with a prefix. We
+- * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
++ * support 10 for MPLS (BGP-LU) and need only 2 for EVPN-VxLAN.
++ *
++ * According to RFC 3107/RFC 8277 label stack is distributed in NLRI, length is given in
++ * one byte in bits! (prefix length + whole number of label stack bits), so even if
++ * prefix is 0 length, (each label takes 3 bytes) floor(256/24) = 10
++ *
++ * It is impossible to pass more than 10 labels by BGP-LU
+ */
+-#define BGP_MAX_LABELS 2
++#define BGP_MAX_LABELS 10
+
+ /* MPLS label(s) - VNI(s) for EVPN-VxLAN */
+ struct bgp_labels {
+@@ -40,16 +46,21 @@ extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
+ extern void bgp_reg_dereg_for_label(struct bgp_dest *dest,
+ struct bgp_path_info *pi, bool reg);
+ extern int bgp_parse_fec_update(void);
+-extern mpls_label_t bgp_adv_label(struct bgp_dest *dest,
+- struct bgp_path_info *pi, struct peer *to,
+- afi_t afi, safi_t safi);
++extern void bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi, struct peer *to,
++ afi_t afi, safi_t safi, mpls_label_t *labels, uint8_t *num_labels);
+
+ extern int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet);
++extern uint32_t decode_label(mpls_label_t *label);
++extern void encode_label_bos(mpls_label_t label_in, mpls_label_t *label_out, bool bos);
++extern void encode_label(mpls_label_t label_in, mpls_label_t *label_out);
+ extern bool bgp_labels_same(const mpls_label_t *tbl_a,
+ const uint8_t num_labels_a,
+ const mpls_label_t *tbl_b,
+ const uint8_t num_labels_b);
++/* Write labels to str of format "prefixLABEL1/LABEL2/.../LABELN", prefix may be NULL */
++extern char *mpls_labels2str(mpls_label_t *labels, uint8_t num_labels, const char *prefix,
++ char *buf, int size);
+
+ static inline int bgp_labeled_safi(safi_t safi)
+ {
+@@ -114,4 +125,13 @@ static inline uint8_t label_bos(mpls_label_t *label)
+ return (t[2] & 0x01);
+ };
+
++/* Set BOS to 1 */
++static inline void label_set_bos(mpls_label_t *label)
++{
++ uint8_t *t = (uint8_t *)label;
++
++ if (t)
++ t[2] |= 0x01;
++}
++
+ #endif /* _BGP_LABEL_H */
+diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
+index a35b4037bb..057ecb318e 100644
+--- a/bgpd/bgp_mplsvpn.c
++++ b/bgpd/bgp_mplsvpn.c
+@@ -64,31 +64,6 @@ extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc,
+ return ret;
+ }
+
+-uint32_t decode_label(mpls_label_t *label_pnt)
+-{
+- uint32_t l;
+- uint8_t *pnt = (uint8_t *)label_pnt;
+-
+- l = ((uint32_t)*pnt++ << 12);
+- l |= (uint32_t)*pnt++ << 4;
+- l |= (uint32_t)((*pnt & 0xf0) >> 4);
+- return l;
+-}
+-
+-void encode_label(mpls_label_t label, mpls_label_t *label_pnt)
+-{
+- uint8_t *pnt = (uint8_t *)label_pnt;
+- if (pnt == NULL)
+- return;
+- if (label == BGP_PREVENT_VRF_2_VRF_LEAK) {
+- *label_pnt = label;
+- return;
+- }
+- *pnt++ = (label >> 12) & 0xff;
+- *pnt++ = (label >> 4) & 0xff;
+- *pnt++ = ((label << 4) + 1) & 0xff; /* S=1 */
+-}
+-
+ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet)
+ {
+diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
+index 3b036d2167..ab84cc2118 100644
+--- a/bgpd/bgp_mplsvpn.h
++++ b/bgpd/bgp_mplsvpn.h
+@@ -34,8 +34,6 @@
+ extern void bgp_mplsvpn_init(void);
+ extern void bgp_mplsvpn_path_nh_label_unlink(struct bgp_path_info *pi);
+ extern int bgp_nlri_parse_vpn(struct peer *, struct attr *, struct bgp_nlri *);
+-extern uint32_t decode_label(mpls_label_t *);
+-extern void encode_label(mpls_label_t, mpls_label_t *);
+
+ extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc,
+ int *index, afi_t *afi);
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index 85cad88979..867b4a7cea 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -2145,8 +2145,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
+ int samepeer_safe = 0; /* for synthetic mplsvpns routes */
+ bool nh_reset = false;
+ uint64_t cum_bw;
+- mpls_label_t label;
+ bool global_and_ll = false;
++ uint8_t num_labels;
++ mpls_label_t labels[BGP_MAX_LABELS] = { MPLS_INVALID_LABEL };
+
+ if (DISABLE_BGP_ANNOUNCE)
+ return false;
+@@ -2231,13 +2232,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
+
+ /* If it's labeled safi, make sure the route has a valid label. */
+ if (safi == SAFI_LABELED_UNICAST) {
+- label = bgp_adv_label(dest, pi, peer, afi, safi);
+- if (!bgp_is_valid_label(&label)) {
++ bgp_adv_label(dest, pi, peer, afi, safi, labels, &num_labels);
++ if (!bgp_is_valid_label(&labels[0])) {
+ if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
+- zlog_debug("u%" PRIu64 ":s%" PRIu64
+- " %pFX is filtered - no label (%p)",
+- subgrp->update_group->id, subgrp->id,
+- p, &label);
++ zlog_debug("u%" PRIu64 ":s%" PRIu64 " %pFX is filtered - no label",
++ subgrp->update_group->id, subgrp->id, p);
+ return false;
+ }
+ } else if (safi == SAFI_MPLS_VPN &&
+@@ -2254,8 +2253,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
+ * then get appropriate mpls local label
+ * and check its validity
+ */
+- label = bgp_mplsvpn_nh_label_bind_get_label(pi);
+- if (!bgp_is_valid_label(&label)) {
++ labels[0] = bgp_mplsvpn_nh_label_bind_get_label(pi);
++ if (!bgp_is_valid_label(&labels[0])) {
+ if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
+ zlog_debug("u%" PRIu64 ":s%" PRIu64
+ " %pFX is filtered - no valid label",
+@@ -10493,6 +10492,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
+ json_object *json_paths)
+ {
+ char buf[INET6_ADDRSTRLEN];
++ char labels_buf[9 * BGP_MAX_LABELS]; /* 8 per label + / or \0 for each */
+ char vni_buf[30] = {};
+ struct attr *attr = path->attr;
+ time_t tbuf;
+@@ -10500,6 +10500,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
+ json_object *json_bestpath = NULL;
+ json_object *json_cluster_list = NULL;
+ json_object *json_cluster_list_list = NULL;
++ json_object *json_labels = NULL;
+ json_object *json_ext_community = NULL;
+ json_object *json_ext_ipv6_community = NULL;
+ json_object *json_last_update = NULL;
+@@ -10510,6 +10511,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
+ json_object *json_path = NULL;
+ json_object *json_peer = NULL;
+ json_object *json_string = NULL;
++ json_object *json_int = NULL;
+ json_object *json_adv_to = NULL;
+ int first = 0;
+ struct listnode *node, *nnode;
+@@ -10520,12 +10522,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
+ bool nexthop_self =
+ CHECK_FLAG(path->flags, BGP_PATH_ANNC_NH_SELF) ? true : false;
+ int i;
+- char *nexthop_hostname =
+- bgp_nexthop_hostname(path->peer, path->nexthop);
+- uint32_t ttl = 0;
+- uint32_t bos = 0;
+- uint32_t exp = 0;
+- mpls_label_t label = MPLS_INVALID_LABEL;
++ char *nexthop_hostname = bgp_nexthop_hostname(path->peer, path->nexthop);
+ struct bgp_path_info *bpi_ultimate =
+ bgp_get_imported_bpi_ultimate(path);
+ struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
+@@ -11338,13 +11335,28 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
+ /* Remote Label */
+ if (bgp_path_info_has_valid_label(path) &&
+ (safi != SAFI_EVPN && !is_route_parent_evpn(path))) {
+- mpls_lse_decode(path->extra->labels->label[0], &label, &ttl,
+- &exp, &bos);
+-
+- if (json_paths)
+- json_object_int_add(json_path, "remoteLabel", label);
+- else
+- vty_out(vty, " Remote label: %d\n", label);
++ if (json_paths) {
++#if CONFDATE > 20261107
++ CPP_NOTICE("Remove 'remoteLabel' field");
++#endif
++ /* For backward compatibility write top label to remoteLabel */
++ json_object_int_add(json_path, "remoteLabel",
++ decode_label(&path->extra->labels->label[0]));
++
++ /* Write full stack to remoteLabels */
++ json_labels = json_object_new_array();
++ for (int label_index = 0; label_index < path->extra->labels->num_labels;
++ label_index++) {
++ json_int = json_object_new_int(
++ decode_label(&path->extra->labels->label[label_index]));
++ json_object_array_add(json_labels, json_int);
++ }
++ json_object_object_add(json_path, "remoteLabels", json_labels);
++ } else {
++ mpls_labels2str(path->extra->labels->label, path->extra->labels->num_labels,
++ NULL, labels_buf, sizeof(labels_buf));
++ vty_out(vty, " Remote labels: %s\n", labels_buf);
++ }
+ }
+
+ /* Remote SID */
+diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
+index 3ce136ef87..4e0702aeb4 100644
+--- a/bgpd/bgp_updgrp_packet.c
++++ b/bgpd/bgp_updgrp_packet.c
+@@ -664,7 +664,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
+ int addpath_overhead = 0;
+ uint32_t addpath_tx_id = 0;
+ struct prefix_rd *prd = NULL;
+- mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
++ mpls_label_t *label_pnt = NULL;
++ mpls_label_t labels[BGP_MAX_LABELS] = { MPLS_INVALID_LABEL };
+ uint8_t num_labels = 0;
+
+ if (!subgrp)
+@@ -785,10 +786,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
+ dest->pdest);
+
+ if (safi == SAFI_LABELED_UNICAST) {
+- label = bgp_adv_label(dest, path, peer, afi,
+- safi);
+- label_pnt = &label;
+- num_labels = 1;
++ bgp_adv_label(dest, path, peer, afi, safi, labels, &num_labels);
++ label_pnt = &labels[0];
+ } else if (safi == SAFI_MPLS_VPN && path &&
+ CHECK_FLAG(path->flags,
+ BGP_PATH_MPLSVPN_NH_LABEL_BIND) &&
+@@ -808,9 +807,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
+ * called here, 'get_label()' returns a valid
+ * label.
+ */
+- label = bgp_mplsvpn_nh_label_bind_get_label(
+- path);
+- label_pnt = &label;
++ labels[0] = bgp_mplsvpn_nh_label_bind_get_label(path);
++ label_pnt = &labels[0];
+ num_labels = 1;
+ } else {
+ num_labels = BGP_PATH_INFO_NUM_LABELS(path);
+diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
+index 51af57ac68..ecfc278f2c 100644
+--- a/bgpd/bgp_zebra.c
++++ b/bgpd/bgp_zebra.c
+@@ -1328,11 +1328,10 @@ static void bgp_zebra_announce_parse_nexthop(
+
+ if (bgp_debug_zebra(&api->prefix)) {
+ if (BGP_PATH_INFO_NUM_LABELS(mpinfo)) {
+- zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d",
++ zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d, num_labels: %d",
+ __func__, p,
+- bgp_is_valid_label(
+- &mpinfo->extra->labels
+- ->label[0]));
++ bgp_is_valid_label(&mpinfo->extra->labels->label[0]),
++ BGP_PATH_INFO_NUM_LABELS(mpinfo));
+ } else {
+ zlog_debug("%s: p=%pFX, no label", __func__, p);
+ }
+@@ -1411,15 +1410,28 @@ static void bgp_zebra_announce_parse_nexthop(
+ nh_label = *bgp_evpn_path_info_labels_get_l3vni(
+ labels, num_labels);
+ nh_label_type = ZEBRA_LSP_EVPN;
++
++ api_nh->label_num = 1;
++ api_nh->labels[0] = nh_label;
+ } else {
+- mpls_lse_decode(labels[0], &nh_label, &ttl,
+- &exp, &bos);
++ uint8_t i;
++ int max_elements = sizeof(api_nh->labels) /
++ sizeof(api_nh->labels[0]);
++
++ api_nh->label_num = num_labels;
++ if (api_nh->label_num > max_elements) {
++ zlog_warn("%s: too many labels provided for zebra (%d), copying first %d",
++ __func__, num_labels, max_elements);
++ api_nh->label_num = max_elements;
++ }
++ for (i = 0; i < api_nh->label_num; i++) {
++ mpls_lse_decode(labels[i], &api_nh->labels[i], &ttl, &exp,
++ &bos);
++ }
+ }
+
+ SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
+- api_nh->label_num = 1;
+ api_nh->label_type = nh_label_type;
+- api_nh->labels[0] = nh_label;
+ }
+
+ if (is_evpn && !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP))
+@@ -1475,7 +1487,8 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
+ char nh_buf[INET6_ADDRSTRLEN];
+ char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' };
+ char buf1[ETHER_ADDR_STRLEN];
+- char label_buf[20];
++ /* strlen("label ") + 8 chars per label + '/' or '\0' for each label */
++ char label_buf[6 + 9 * BGP_MAX_LABELS];
+ char sid_buf[20];
+ char segs_buf[256];
+ struct zapi_nexthop *api_nh;
+@@ -1513,9 +1526,19 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
+ eth_buf[0] = '\0';
+ segs_buf[0] = '\0';
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) &&
+- !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN))
+- snprintf(label_buf, sizeof(label_buf), "label %u",
+- api_nh->labels[0]);
++ !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
++ int label_len;
++ int j;
++
++ label_len = snprintf(label_buf, sizeof(label_buf), "label %u",
++ api_nh->labels[0]);
++
++ for (j = 1; j < api_nh->label_num; j++) {
++ label_len += snprintf(label_buf + label_len,
++ sizeof(label_buf) - label_len, "/%u",
++ api_nh->labels[j]);
++ }
++ }
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) &&
+ !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
+ inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf,
+--
+2.50.1
+