]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: advertise mpls vpn routes with appropriate label
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 11 May 2023 13:26:50 +0000 (15:26 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 16 Jun 2023 08:54:58 +0000 (10:54 +0200)
The advertised label value from mpls vpn routes is not modified
when the advertised next-hop is modified to next-hop-self.

Actually, the original label value received is redistributed as
is, whereas the new_label value bound in the nexthop label
bind entry should be used.

Only the VPN entries that contain MPLS information, and that
are redistributed between distinct peers, will have a label
value to advertise.
- no SRv6 attribute
- no local prefix
- no exported VPN prefixes from a VRF

If the advertisement to a given peer has the next-hop modified,
then the new label value will be picked up. The considered cases
are peers configured with 'next-hop-self' option, or ebgp peerings
without the 'next-hop-unchanged' option.

Note that the the NLRI format will follow the rfc3107 format, as
multiple label values for MPLS VPN NLRIs are not supported (the
rfc8277 is not supported).
Note also that the case where an outgoing route-map is applied to
the outgoing neighbor is not considered in this commit.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_updgrp_packet.c

index cbb52c5f7f0749716c59baad5b9981a50016690e..1e932fe9c719de99d8bd0132e0bb2c53032e8e3e 100644 (file)
@@ -3954,6 +3954,24 @@ bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi)
        return true;
 }
 
+mpls_label_t bgp_mplsvpn_nh_label_bind_get_label(struct bgp_path_info *pi)
+{
+       mpls_label_t label;
+       struct bgp_mplsvpn_nh_label_bind_cache *bmnc;
+
+       bmnc = pi->mplsvpn.bmnc.nh_label_bind_cache;
+       if (!bmnc || bmnc->new_label == MPLS_INVALID_LABEL)
+               /* allocation in progress
+                * or path not eligible for local label
+                */
+               return MPLS_INVALID_LABEL;
+
+       label = mpls_lse_encode(bmnc->new_label, 0, 0, 1);
+       bgp_set_valid_label(&label);
+
+       return label;
+}
+
 /* Called upon reception of a ZAPI Message from zebra, about
  * a new available label.
  */
@@ -3962,6 +3980,8 @@ static int bgp_mplsvpn_nh_label_bind_get_local_label_cb(mpls_label_t label,
                                                        bool allocated)
 {
        struct bgp_mplsvpn_nh_label_bind_cache *bmnc = context;
+       struct bgp_table *table;
+       struct bgp_path_info *pi;
 
        if (BGP_DEBUG(labelpool, LABELPOOL))
                zlog_debug("%s: label=%u, allocated=%d, nexthop=%pFX, label %u",
@@ -3984,7 +4004,17 @@ static int bgp_mplsvpn_nh_label_bind_get_local_label_cb(mpls_label_t label,
        bmnc->allocation_in_progress = false;
 
        /* Create MPLS entry with new_label */
-       /* Trigger BGP process to re-advertise updates */
+       LIST_FOREACH (pi, &(bmnc->paths), mplsvpn.bmnc.nh_label_bind_thread) {
+               /* we can advertise it */
+               if (!pi->net)
+                       continue;
+               table = bgp_dest_table(pi->net);
+               if (!table)
+                       continue;
+               SET_FLAG(pi->net->flags, BGP_NODE_LABEL_CHANGED);
+               bgp_process(table->bgp, pi->net, table->afi, table->safi);
+       }
+
        return 0;
 }
 
index 132e96f0f26712c339dc6a34467fe0846237203e..6ff7a0a0206ed7b152872164cb33352992a2d819 100644 (file)
@@ -332,6 +332,7 @@ bgp_mplsvpn_nh_label_bind_cmp(const struct bgp_mplsvpn_nh_label_bind_cache *a,
 extern void bgp_mplsvpn_path_nh_label_bind_unlink(struct bgp_path_info *pi);
 extern void bgp_mplsvpn_nh_label_bind_register_local_label(
        struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi);
+mpls_label_t bgp_mplsvpn_nh_label_bind_get_label(struct bgp_path_info *pi);
 
 /* used to bind a local label to the (label, nexthop) values
  * from an incoming BGP mplsvpn update
index 223bcfde541b1774ee38167c3f8a637ed5aaf5bb..c2e554cddbceb77dcfdf6e59370372bd826a1b56 100644 (file)
@@ -298,6 +298,29 @@ struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path)
        return path;
 }
 
+bool bgp_path_info_nexthop_changed(struct bgp_path_info *pi, struct peer *to,
+                                  afi_t afi)
+{
+       if (pi->peer->sort == BGP_PEER_IBGP && to->sort == BGP_PEER_IBGP &&
+           !CHECK_FLAG(to->af_flags[afi][SAFI_MPLS_VPN],
+                       PEER_FLAG_FORCE_NEXTHOP_SELF))
+               /* IBGP RR with no nexthop self force configured */
+               return false;
+
+       if (to->sort == BGP_PEER_IBGP &&
+           !CHECK_FLAG(to->af_flags[afi][SAFI_MPLS_VPN],
+                       PEER_FLAG_NEXTHOP_SELF))
+               /* IBGP RR with no nexthop self configured */
+               return false;
+
+       if (CHECK_FLAG(to->af_flags[afi][SAFI_MPLS_VPN],
+                      PEER_FLAG_NEXTHOP_UNCHANGED))
+               /* IBGP or EBGP with nexthop attribute unchanged */
+               return false;
+
+       return true;
+}
+
 /* This function sets flag BGP_NODE_SELECT_DEFER based on condition */
 static int bgp_dest_set_defer_flag(struct bgp_dest *dest, bool delete)
 {
@@ -1996,6 +2019,7 @@ 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;
 
        if (DISABLE_BGP_ANNOUNCE)
                return false;
@@ -2081,7 +2105,7 @@ 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) {
-               mpls_label_t label = bgp_adv_label(dest, pi, peer, afi, safi);
+               label = bgp_adv_label(dest, pi, peer, afi, safi);
                if (!bgp_is_valid_label(&label)) {
                        if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
                                zlog_debug("u%" PRIu64 ":s%" PRIu64
@@ -2090,6 +2114,29 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
                                           p, &label);
                        return false;
                }
+       } else if (safi == SAFI_MPLS_VPN &&
+                  CHECK_FLAG(pi->flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND) &&
+                  pi->mplsvpn.bmnc.nh_label_bind_cache && from && peer &&
+                  pi->peer != peer && pi->sub_type != BGP_ROUTE_IMPORTED &&
+                  pi->sub_type != BGP_ROUTE_STATIC &&
+                  bgp_mplsvpn_path_uses_valid_mpls_label(pi) &&
+                  bgp_path_info_nexthop_changed(pi, peer, afi)) {
+               /* Redistributed mpls vpn route between distinct
+                * peers from 'pi->peer' to 'to',
+                * and an mpls label is used in this path,
+                * and there is a nh label bind entry,
+                * 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)) {
+                       if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
+                               zlog_debug("u%" PRIu64 ":s%" PRIu64
+                                          " %pFX is filtered - no valid label",
+                                          subgrp->update_group->id, subgrp->id,
+                                          p);
+                       return false;
+               }
        }
 
        /* Do not send back route to sender. */
index a67145a3ab245f733de82420f32b7a9e77bcf470..cf08bd1f9e38ef5bb0f289f882fb055aa338a2fc 100644 (file)
@@ -712,6 +712,8 @@ extern struct bgp_dest *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
                                         struct prefix_rd *prd);
 extern struct bgp_path_info *bgp_path_info_lock(struct bgp_path_info *path);
 extern struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path);
+extern bool bgp_path_info_nexthop_changed(struct bgp_path_info *pi,
+                                         struct peer *to, afi_t afi);
 extern struct bgp_path_info *
 bgp_get_imported_bpi_ultimate(struct bgp_path_info *info);
 extern void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi);
index e04d5ae245ca544fdbb9e0d4112e563d056baa13..49b7f51286d417c0344eb30c3718516f24a10626 100644 (file)
@@ -789,6 +789,29 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                                                      safi);
                                label_pnt = &label;
                                num_labels = 1;
+                       } else if (safi == SAFI_MPLS_VPN && path &&
+                                  CHECK_FLAG(path->flags,
+                                             BGP_PATH_MPLSVPN_NH_LABEL_BIND) &&
+                                  path->mplsvpn.bmnc.nh_label_bind_cache &&
+                                  path->peer && path->peer != peer &&
+                                  path->sub_type != BGP_ROUTE_IMPORTED &&
+                                  path->sub_type != BGP_ROUTE_STATIC &&
+                                  bgp_mplsvpn_path_uses_valid_mpls_label(
+                                          path) &&
+                                  bgp_path_info_nexthop_changed(path, peer,
+                                                                afi)) {
+                               /* Redistributed mpls vpn route between distinct
+                                * peers from 'pi->peer' to 'to',
+                                * and an mpls label is used in this path,
+                                * and there is a nh label bind entry,
+                                * then get appropriate mpls local label. When
+                                * called here, 'get_label()' returns a valid
+                                * label.
+                                */
+                               label = bgp_mplsvpn_nh_label_bind_get_label(
+                                       path);
+                               label_pnt = &label;
+                               num_labels = 1;
                        } else if (path && path->extra) {
                                label_pnt = &path->extra->label[0];
                                num_labels = path->extra->num_labels;