frr/bgpd/bgp_mplsvpn.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

4312 lines
119 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
2002-12-13 21:15:29 +01:00
/* MPLS-VPN
* Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
*/
2002-12-13 21:15:29 +01:00
#include <zebra.h>
#include "command.h"
#include "prefix.h"
#include "log.h"
#include "memory.h"
#include "stream.h"
#include "queue.h"
#include "filter.h"
#include "mpls.h"
#include "json.h"
#include "zclient.h"
2002-12-13 21:15:29 +01:00
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_errors.h"
2002-12-13 21:15:29 +01:00
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_label.h"
2002-12-13 21:15:29 +01:00
#include "bgpd/bgp_mplsvpn.h"
bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger <lberger@labn.net> Donald Sharp <sharpd@cumulusnetworks.com> Paul Jakma <paul.jakma@hpe.com> / <paul@jakma.org>
2016-01-27 17:37:33 +01:00
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_vpn.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_memory.h"
2002-12-13 21:15:29 +01:00
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
bgpd: add L3/L2VPN Virtual Network Control feature This feature adds an L3 & L2 VPN application that makes use of the VPN and Encap SAFIs. This code is currently used to support IETF NVO3 style operation. In NVO3 terminology it provides the Network Virtualization Authority (NVA) and the ability to import/export IP prefixes and MAC addresses from Network Virtualization Edges (NVEs). The code supports per-NVE tables. The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2 (L2) forwarding information between NVAs and NVEs is referred to as the Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For general background on NVO3 and RFP concepts see [1]. For information on Openflow see [2]. RFPs are integrated with BGP via the RF API contained in the new "rfapi" BGP sub-directory. Currently, only a simple example RFP is included in Quagga. Developers may use this example as a starting point to integrate Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code also supports the ability import/export of routing information between VNC and customer edge routers (CEs) operating within a virtual network. Import/export may take place between BGP views or to the default zebera VRF. BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN information between NVAs. BGP based IP VPN support is defined in RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use of both the Encapsulation Subsequent Address Family Identifier (SAFI) and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP Tunnel Encapsulation Attribute, are supported. MAC address distribution does not follow any standard BGB encoding, although it was inspired by the early IETF EVPN concepts. The feature is conditionally compiled and disabled by default. Use the --enable-bgp-vnc configure option to enable. The majority of this code was authored by G. Paul Ziemba <paulz@labn.net>. [1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req [2] https://www.opennetworking.org/sdn-resources/technical-library Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
#endif
DEFINE_MTYPE_STATIC(BGPD, MPLSVPN_NH_LABEL_BIND_CACHE,
"BGP MPLSVPN nexthop label bind cache");
/*
* Definitions and external declarations.
*/
extern struct zclient *zclient;
extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc,
int *index, afi_t *afi)
{
int ret = 0;
if (argv_find(argv, argc, "vpnv4", index)) {
ret = 1;
if (afi)
*afi = AFI_IP;
} else if (argv_find(argv, argc, "vpnv6", index)) {
ret = 1;
if (afi)
*afi = AFI_IP6;
}
return ret;
}
uint32_t decode_label(mpls_label_t *label_pnt)
2002-12-13 21:15:29 +01:00
{
uint32_t l;
uint8_t *pnt = (uint8_t *)label_pnt;
2002-12-13 21:15:29 +01:00
l = ((uint32_t)*pnt++ << 12);
l |= (uint32_t)*pnt++ << 4;
l |= (uint32_t)((*pnt & 0xf0) >> 4);
2002-12-13 21:15:29 +01:00
return l;
}
void encode_label(mpls_label_t label, mpls_label_t *label_pnt)
bgpd: add L3/L2VPN Virtual Network Control feature This feature adds an L3 & L2 VPN application that makes use of the VPN and Encap SAFIs. This code is currently used to support IETF NVO3 style operation. In NVO3 terminology it provides the Network Virtualization Authority (NVA) and the ability to import/export IP prefixes and MAC addresses from Network Virtualization Edges (NVEs). The code supports per-NVE tables. The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2 (L2) forwarding information between NVAs and NVEs is referred to as the Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For general background on NVO3 and RFP concepts see [1]. For information on Openflow see [2]. RFPs are integrated with BGP via the RF API contained in the new "rfapi" BGP sub-directory. Currently, only a simple example RFP is included in Quagga. Developers may use this example as a starting point to integrate Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code also supports the ability import/export of routing information between VNC and customer edge routers (CEs) operating within a virtual network. Import/export may take place between BGP views or to the default zebera VRF. BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN information between NVAs. BGP based IP VPN support is defined in RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use of both the Encapsulation Subsequent Address Family Identifier (SAFI) and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP Tunnel Encapsulation Attribute, are supported. MAC address distribution does not follow any standard BGB encoding, although it was inspired by the early IETF EVPN concepts. The feature is conditionally compiled and disabled by default. Use the --enable-bgp-vnc configure option to enable. The majority of this code was authored by G. Paul Ziemba <paulz@labn.net>. [1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req [2] https://www.opennetworking.org/sdn-resources/technical-library Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
{
uint8_t *pnt = (uint8_t *)label_pnt;
bgpd: add L3/L2VPN Virtual Network Control feature This feature adds an L3 & L2 VPN application that makes use of the VPN and Encap SAFIs. This code is currently used to support IETF NVO3 style operation. In NVO3 terminology it provides the Network Virtualization Authority (NVA) and the ability to import/export IP prefixes and MAC addresses from Network Virtualization Edges (NVEs). The code supports per-NVE tables. The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2 (L2) forwarding information between NVAs and NVEs is referred to as the Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For general background on NVO3 and RFP concepts see [1]. For information on Openflow see [2]. RFPs are integrated with BGP via the RF API contained in the new "rfapi" BGP sub-directory. Currently, only a simple example RFP is included in Quagga. Developers may use this example as a starting point to integrate Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code also supports the ability import/export of routing information between VNC and customer edge routers (CEs) operating within a virtual network. Import/export may take place between BGP views or to the default zebera VRF. BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN information between NVAs. BGP based IP VPN support is defined in RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use of both the Encapsulation Subsequent Address Family Identifier (SAFI) and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP Tunnel Encapsulation Attribute, are supported. MAC address distribution does not follow any standard BGB encoding, although it was inspired by the early IETF EVPN concepts. The feature is conditionally compiled and disabled by default. Use the --enable-bgp-vnc configure option to enable. The majority of this code was authored by G. Paul Ziemba <paulz@labn.net>. [1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req [2] https://www.opennetworking.org/sdn-resources/technical-library Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
if (pnt == NULL)
return;
if (label == BGP_PREVENT_VRF_2_VRF_LEAK) {
*label_pnt = label;
return;
}
bgpd: add L3/L2VPN Virtual Network Control feature This feature adds an L3 & L2 VPN application that makes use of the VPN and Encap SAFIs. This code is currently used to support IETF NVO3 style operation. In NVO3 terminology it provides the Network Virtualization Authority (NVA) and the ability to import/export IP prefixes and MAC addresses from Network Virtualization Edges (NVEs). The code supports per-NVE tables. The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2 (L2) forwarding information between NVAs and NVEs is referred to as the Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For general background on NVO3 and RFP concepts see [1]. For information on Openflow see [2]. RFPs are integrated with BGP via the RF API contained in the new "rfapi" BGP sub-directory. Currently, only a simple example RFP is included in Quagga. Developers may use this example as a starting point to integrate Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code also supports the ability import/export of routing information between VNC and customer edge routers (CEs) operating within a virtual network. Import/export may take place between BGP views or to the default zebera VRF. BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN information between NVAs. BGP based IP VPN support is defined in RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use of both the Encapsulation Subsequent Address Family Identifier (SAFI) and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP Tunnel Encapsulation Attribute, are supported. MAC address distribution does not follow any standard BGB encoding, although it was inspired by the early IETF EVPN concepts. The feature is conditionally compiled and disabled by default. Use the --enable-bgp-vnc configure option to enable. The majority of this code was authored by G. Paul Ziemba <paulz@labn.net>. [1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req [2] https://www.opennetworking.org/sdn-resources/technical-library Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
*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)
2002-12-13 21:15:29 +01:00
{
struct prefix p;
uint8_t psize = 0;
uint8_t prefixlen;
uint16_t type;
2002-12-13 21:15:29 +01:00
struct rd_as rd_as;
struct rd_ip rd_ip;
struct prefix_rd prd = {0};
mpls_label_t label = {0};
2015-05-20 03:03:45 +02:00
afi_t afi;
safi_t safi;
bool addpath_capable;
uint32_t addpath_id;
int ret = 0;
2002-12-13 21:15:29 +01:00
/* Make prefix_rd */
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
struct stream *data = stream_new(packet->length);
stream_put(data, packet->nlri, packet->length);
2015-05-20 03:03:45 +02:00
afi = packet->afi;
safi = packet->safi;
addpath_id = 0;
addpath_capable = bgp_addpath_encode_rx(peer, afi, safi);
2002-12-13 21:15:29 +01:00
#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */
while (STREAM_READABLE(data) > 0) {
2002-12-13 21:15:29 +01:00
/* Clear prefix structure. */
memset(&p, 0, sizeof(p));
if (addpath_capable) {
STREAM_GET(&addpath_id, data, BGP_ADDPATH_ID_LEN);
addpath_id = ntohl(addpath_id);
}
if (STREAM_READABLE(data) < 1) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (truncated NLRI of size %u; no prefix length)",
peer->host, packet->length);
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
goto done;
2015-05-20 03:03:45 +02:00
}
/* Fetch prefix length. */
STREAM_GETC(data, prefixlen);
p.family = afi2family(packet->afi);
psize = PSIZE(prefixlen);
bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger <lberger@labn.net> Donald Sharp <sharpd@cumulusnetworks.com> Paul Jakma <paul.jakma@hpe.com> / <paul@jakma.org>
2016-01-27 17:37:33 +01:00
if (prefixlen < VPN_PREFIXLEN_MIN_BYTES * 8) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",
bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger <lberger@labn.net> Donald Sharp <sharpd@cumulusnetworks.com> Paul Jakma <paul.jakma@hpe.com> / <paul@jakma.org>
2016-01-27 17:37:33 +01:00
peer->host, prefixlen);
ret = BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
goto done;
Fix most compiler warnings in default GCC build. Fix lots of warnings. Some const and type-pun breaks strict-aliasing warnings left but much reduced. * bgp_advertise.h: (struct bgp_advertise_fifo) is functionally identical to (struct fifo), so just use that. Makes it clearer the beginning of (struct bgp_advertise) is compatible with with (struct fifo), which seems to be enough for gcc. Add a BGP_ADV_FIFO_HEAD macro to contain the right cast to try shut up type-punning breaks strict aliasing warnings. * bgp_packet.c: Use BGP_ADV_FIFO_HEAD. (bgp_route_refresh_receive) fix an interesting logic error in (!ok || (ret != BLAH)) where ret is only well-defined if ok. * bgp_vty.c: Peer commands should use bgp_vty_return to set their return. * jhash.{c,h}: Can take const on * args without adding issues & fix warnings. * libospf.h: LSA sequence numbers use the unsigned range of values, and constants need to be set to unsigned, or it causes warnings in ospf6d. * md5.h: signedness of caddr_t is implementation specific, change to an explicit (uint_8 *), fix sign/unsigned comparison warnings. * vty.c: (vty_log_fixed) const on level is well-intentioned, but not going to fly given iov_base. * workqueue.c: ALL_LIST_ELEMENTS_RO tests for null pointer, which is always true for address of static variable. Correct but pointless warning in this case, but use a 2nd pointer to shut it up. * ospf6_route.h: Add a comment about the use of (struct prefix) to stuff 2 different 32 bit IDs into in (struct ospf6_route), and the resulting type-pun strict-alias breakage warnings this causes. Need to use 2 different fields to fix that warning? general: * remove unused variables, other than a few cases where they serve a sufficiently useful documentary purpose (e.g. for code that needs fixing), or they're required dummies. In those cases, try mark them as unused. * Remove dead code that can't be reached. * Quite a few 'no ...' forms of vty commands take arguments, but do not check the argument matches the command being negated. E.g., should 'distance X <prefix>' succeed if previously 'distance Y <prefix>' was set? Or should it be required that the distance match the previously configured distance for the prefix? Ultimately, probably better to be strict about this. However, changing from slack to strict might expose problems in command aliases and tools. * Fix uninitialised use of variables. * Fix sign/unsigned comparison warnings by making signedness of types consistent. * Mark functions as static where their use is restricted to the same compilation unit. * Add required headers * Move constants defined in headers into code. * remove dead, unused functions that have no debug purpose. (cherry picked from commit 7aa9dcef80b2ce50ecaa77653d87c8b84e009c49) Conflicts: bgpd/bgp_advertise.h bgpd/bgp_mplsvpn.c bgpd/bgp_nexthop.c bgpd/bgp_packet.c bgpd/bgp_route.c bgpd/bgp_routemap.c bgpd/bgp_vty.c lib/command.c lib/if.c lib/jhash.c lib/workqueue.c ospf6d/ospf6_lsa.c ospf6d/ospf6_neighbor.h ospf6d/ospf6_spf.c ospf6d/ospf6_top.c ospfd/ospf_api.c zebra/router-id.c zebra/rt_netlink.c zebra/rt_netlink.h
2014-09-19 15:42:23 +02:00
}
/* sanity check against packet data */
if (STREAM_READABLE(data) < psize) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)",
peer->host, prefixlen, packet->length);
ret = BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
goto done;
}
/* sanity check against storage for the IP address portion */
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t)sizeof(p.u)) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (psize %d exceeds storage size %zu)",
bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger <lberger@labn.net> Donald Sharp <sharpd@cumulusnetworks.com> Paul Jakma <paul.jakma@hpe.com> / <paul@jakma.org>
2016-01-27 17:37:33 +01:00
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
sizeof(p.u));
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
goto done;
}
/* Sanity check against max bitlen of the address family */
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen(&p)) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (psize %d exceeds family (%u) max byte len %u)",
bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger <lberger@labn.net> Donald Sharp <sharpd@cumulusnetworks.com> Paul Jakma <paul.jakma@hpe.com> / <paul@jakma.org>
2016-01-27 17:37:33 +01:00
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
p.family, prefix_blen(&p));
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
goto done;
}
/* Copy label to prefix. */
if (STREAM_READABLE(data) < BGP_LABEL_BYTES) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (truncated NLRI of size %u; no label)",
peer->host, packet->length);
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
goto done;
}
STREAM_GET(&label, data, BGP_LABEL_BYTES);
bgp_set_valid_label(&label);
2002-12-13 21:15:29 +01:00
/* Copy routing distinguisher to rd. */
if (STREAM_READABLE(data) < 8) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (truncated NLRI of size %u; no RD)",
peer->host, packet->length);
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
goto done;
}
STREAM_GET(&prd.val, data, 8);
2002-12-13 21:15:29 +01:00
/* Decode RD type. */
type = decode_rd_type(prd.val);
switch (type) {
case RD_TYPE_AS:
decode_rd_as(&prd.val[2], &rd_as);
break;
case RD_TYPE_AS4:
decode_rd_as4(&prd.val[2], &rd_as);
break;
case RD_TYPE_IP:
decode_rd_ip(&prd.val[2], &rd_ip);
break;
#ifdef ENABLE_BGP_VNC
bgpd: add L3/L2VPN Virtual Network Control feature This feature adds an L3 & L2 VPN application that makes use of the VPN and Encap SAFIs. This code is currently used to support IETF NVO3 style operation. In NVO3 terminology it provides the Network Virtualization Authority (NVA) and the ability to import/export IP prefixes and MAC addresses from Network Virtualization Edges (NVEs). The code supports per-NVE tables. The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2 (L2) forwarding information between NVAs and NVEs is referred to as the Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For general background on NVO3 and RFP concepts see [1]. For information on Openflow see [2]. RFPs are integrated with BGP via the RF API contained in the new "rfapi" BGP sub-directory. Currently, only a simple example RFP is included in Quagga. Developers may use this example as a starting point to integrate Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code also supports the ability import/export of routing information between VNC and customer edge routers (CEs) operating within a virtual network. Import/export may take place between BGP views or to the default zebera VRF. BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN information between NVAs. BGP based IP VPN support is defined in RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use of both the Encapsulation Subsequent Address Family Identifier (SAFI) and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP Tunnel Encapsulation Attribute, are supported. MAC address distribution does not follow any standard BGB encoding, although it was inspired by the early IETF EVPN concepts. The feature is conditionally compiled and disabled by default. Use the --enable-bgp-vnc configure option to enable. The majority of this code was authored by G. Paul Ziemba <paulz@labn.net>. [1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req [2] https://www.opennetworking.org/sdn-resources/technical-library Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
case RD_TYPE_VNC_ETH:
break;
#endif
default:
flog_err(EC_BGP_UPDATE_RCV, "Unknown RD type %d", type);
break; /* just report */
}
/* exclude label & RD */
p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8;
STREAM_GET(p.u.val, data, psize - VPN_PREFIXLEN_MIN_BYTES);
2002-12-13 21:15:29 +01:00
if (attr) {
bgp_update(peer, &p, addpath_id, attr, packet->afi,
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL);
2002-12-13 21:15:29 +01:00
} else {
bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
}
2002-12-13 21:15:29 +01:00
}
/* Packet length consistency check. */
if (STREAM_READABLE(data) != 0) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
peer->host, STREAM_READABLE(data));
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger <lberger@labn.net> Donald Sharp <sharpd@cumulusnetworks.com> Paul Jakma <paul.jakma@hpe.com> / <paul@jakma.org>
2016-01-27 17:37:33 +01:00
}
goto done;
stream_failure:
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (NLRI of size %u - length error)",
peer->host, packet->length);
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
done:
stream_free(data);
return ret;
#undef VPN_PREFIXLEN_MIN_BYTES
2002-12-13 21:15:29 +01:00
}
/*
* This function informs zebra of the label this vrf sets on routes
* leaked to VPN. Zebra should install this label in the kernel with
* an action of "pop label and then use this vrf's IP FIB to route the PDU."
*
* Sending this vrf-label association is qualified by a) whether vrf->vpn
* exporting is active ("export vpn" is enabled, vpn-policy RD and RT list
* are set) and b) whether vpn-policy label is set.
*
* If any of these conditions do not hold, then we send MPLS_LABEL_NONE
* for this vrf, which zebra interprets to mean "delete this vrf-label
* association."
*/
void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
{
mpls_label_t label = MPLS_LABEL_NONE;
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug) {
zlog_debug(
"%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp->name_pretty, afi2str(afi));
}
return;
}
if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) {
label = bgp->vpn_policy[afi].tovpn_label;
}
if (debug) {
zlog_debug("%s: vrf %s: afi %s: setting label %d for vrf id %d",
__func__, bgp->name_pretty, afi2str(afi), label,
bgp->vrf_id);
}
if (label == BGP_PREVENT_VRF_2_VRF_LEAK)
label = MPLS_LABEL_NONE;
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
}
/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this label to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi)
{
mpls_label_t label = MPLS_LABEL_NONE;
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug) {
zlog_debug(
"%s: vrf_id not set, can't delete zebra vrf label",
__func__);
}
return;
}
if (debug) {
zlog_debug("%s: deleting label for vrf %s (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id);
}
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
}
/*
* This function informs zebra of the srv6-function this vrf sets on routes
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT4/6's IP FIB to route the PDU."
*/
void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
enum seg6local_action_t act;
struct seg6local_context ctx = {};
struct in6_addr *tovpn_sid = NULL;
struct in6_addr *tovpn_sid_ls = NULL;
struct vrf *vrf;
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp->name_pretty, afi2str(afi));
return;
}
tovpn_sid = bgp->vpn_policy[afi].tovpn_sid;
if (!tovpn_sid) {
if (debug)
zlog_debug("%s: vrf %s: afi %s: sid not set", __func__,
bgp->name_pretty, afi2str(afi));
return;
}
if (debug)
zlog_debug("%s: vrf %s: afi %s: setting sid %pI6 for vrf id %d",
__func__, bgp->name_pretty, afi2str(afi), tovpn_sid,
bgp->vrf_id);
vrf = vrf_lookup_by_id(bgp->vrf_id);
if (!vrf)
return;
ctx.table = vrf->data.l.table_id;
act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx);
tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
*tovpn_sid_ls = *tovpn_sid;
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
}
/*
* This function informs zebra of the srv6-function this vrf sets on routes
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT46's IP FIB to route the PDU."
*/
void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
enum seg6local_action_t act;
struct seg6local_context ctx = {};
struct in6_addr *tovpn_sid = NULL;
struct in6_addr *tovpn_sid_ls = NULL;
struct vrf *vrf;
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug(
"%s: vrf %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp->name_pretty);
return;
}
tovpn_sid = bgp->tovpn_sid;
if (!tovpn_sid) {
if (debug)
zlog_debug("%s: vrf %s: sid not set", __func__,
bgp->name_pretty);
return;
}
if (debug)
zlog_debug("%s: vrf %s: setting sid %pI6 for vrf id %d",
__func__, bgp->name_pretty, tovpn_sid, bgp->vrf_id);
vrf = vrf_lookup_by_id(bgp->vrf_id);
if (!vrf)
return;
ctx.table = vrf->data.l.table_id;
act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx);
tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
*tovpn_sid_ls = *tovpn_sid;
bgp->tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
}
/*
* This function informs zebra of the srv6-function this vrf sets on routes
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT4/6/46's IP FIB to route the PDU."
*/
void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
if (bgp->vpn_policy[afi].tovpn_sid)
return vpn_leak_zebra_vrf_sid_update_per_af(bgp, afi);
if (bgp->tovpn_sid)
return vpn_leak_zebra_vrf_sid_update_per_vrf(bgp);
if (debug)
zlog_debug("%s: vrf %s: afi %s: sid not set", __func__,
bgp->name_pretty, afi2str(afi));
}
/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp->name_pretty, afi2str(afi));
return;
}
if (debug)
zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id);
zclient_send_localsid(zclient,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL);
XFREE(MTYPE_BGP_SRV6_SID,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
}
/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug(
"%s: vrf %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp->name_pretty);
return;
}
if (debug)
zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id);
zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
NULL);
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
}
/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi)
{
if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
vpn_leak_zebra_vrf_sid_withdraw_per_af(bgp, afi);
if (bgp->tovpn_zebra_vrf_sid_last_sent)
vpn_leak_zebra_vrf_sid_withdraw_per_vrf(bgp);
}
int vpn_leak_label_callback(
mpls_label_t label,
void *labelid,
bool allocated)
{
struct vpn_policy *vp = (struct vpn_policy *)labelid;
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
if (debug)
zlog_debug("%s: label=%u, allocated=%d",
__func__, label, allocated);
if (!allocated) {
/*
* previously-allocated label is now invalid
*/
if (CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
(vp->tovpn_label != MPLS_LABEL_NONE)) {
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
vp->afi, bgp_get_default(), vp->bgp);
vp->tovpn_label = MPLS_LABEL_NONE;
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
vp->afi, bgp_get_default(), vp->bgp);
}
return 0;
}
/*
* New label allocation
*/
if (!CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
/*
* not currently configured for auto label, reject allocation
*/
return -1;
}
if (vp->tovpn_label != MPLS_LABEL_NONE) {
if (label == vp->tovpn_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__, vp->bgp->name_pretty, vp->tovpn_label,
label);
/* use new one */
}
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
vp->afi, bgp_get_default(), vp->bgp);
vp->tovpn_label = label;
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
vp->afi, bgp_get_default(), vp->bgp);
return 0;
}
static void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name)
{
struct bgp_srv6_function *func;
func = XCALLOC(MTYPE_BGP_SRV6_FUNCTION,
sizeof(struct bgp_srv6_function));
func->sid = *sid;
snprintf(func->locator_name, sizeof(func->locator_name),
"%s", locator_name);
listnode_add(bgp->srv6_functions, func);
}
bgpd: Free Memory for SRv6 Functions and Locator Chunks Implement proper memory cleanup for SRv6 functions and locator chunks to prevent potential memory leaks. The list callback deletion functions have been set. The ASan leak log for reference: ``` *********************************************************************************** Address Sanitizer Error detected in bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.asan.bgpd.4180 ================================================================= ==4180==ERROR: LeakSanitizer: detected memory leaks Direct leak of 544 byte(s) in 2 object(s) allocated from: #0 0x7f8d176a0d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f8d1709f238 in qcalloc lib/memory.c:105 #2 0x55d5dba6ee75 in sid_register bgpd/bgp_mplsvpn.c:591 #3 0x55d5dba6ee75 in alloc_new_sid bgpd/bgp_mplsvpn.c:712 #4 0x55d5dba6f3ce in ensure_vrf_tovpn_sid_per_af bgpd/bgp_mplsvpn.c:758 #5 0x55d5dba6fb94 in ensure_vrf_tovpn_sid bgpd/bgp_mplsvpn.c:849 #6 0x55d5dba7f975 in vpn_leak_postchange bgpd/bgp_mplsvpn.h:299 #7 0x55d5dba7f975 in vpn_leak_postchange_all bgpd/bgp_mplsvpn.c:3704 #8 0x55d5dbbb6c66 in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3164 #9 0x7f8d1716f08a in zclient_read lib/zclient.c:4459 #10 0x7f8d1713f034 in event_call lib/event.c:1974 #11 0x7f8d1708242b in frr_run lib/libfrr.c:1214 #12 0x55d5db99d19d in main bgpd/bgp_main.c:510 #13 0x7f8d160c5c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 296 byte(s) in 1 object(s) allocated from: #0 0x7f8d176a0d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f8d1709f238 in qcalloc lib/memory.c:105 #2 0x7f8d170b1d5f in srv6_locator_chunk_alloc lib/srv6.c:135 #3 0x55d5dbbb6a19 in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3144 #4 0x7f8d1716f08a in zclient_read lib/zclient.c:4459 #5 0x7f8d1713f034 in event_call lib/event.c:1974 #6 0x7f8d1708242b in frr_run lib/libfrr.c:1214 #7 0x55d5db99d19d in main bgpd/bgp_main.c:510 #8 0x7f8d160c5c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) *********************************************************************************** ``` Signed-off-by: Keelan Cannoo <keelan.cannoo@icloud.com>
2023-11-29 12:49:58 +01:00
void srv6_function_free(struct bgp_srv6_function *func)
{
XFREE(MTYPE_BGP_SRV6_FUNCTION, func);
}
bgpd: free bgp vpn policy The bgp vpn policy had some attribute not free when the function bgp_free was called leading to memory leak as shown below. ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251:Direct leak of 592 byte(s) in 2 object(s) allocated from: ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #0 0x7f4b7ae92037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #1 0x7f4b7aa96e38 in qcalloc lib/memory.c:105 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #2 0x7f4b7aa9bec9 in srv6_locator_chunk_alloc lib/srv6.c:135 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #3 0x56396f8e56f8 in ensure_vrf_tovpn_sid_per_af bgpd/bgp_mplsvpn.c:752 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #4 0x56396f8e608a in ensure_vrf_tovpn_sid bgpd/bgp_mplsvpn.c:846 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #5 0x56396f8e075d in vpn_leak_postchange bgpd/bgp_mplsvpn.h:259 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #6 0x56396f8f3e5b in vpn_leak_postchange_all bgpd/bgp_mplsvpn.c:3397 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #7 0x56396fa920ef in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3238 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #8 0x7f4b7abb2913 in zclient_read lib/zclient.c:4134 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #9 0x7f4b7ab62010 in thread_call lib/thread.c:1991 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #10 0x7f4b7aa5a418 in frr_run lib/libfrr.c:1185 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #11 0x56396f7d756d in main bgpd/bgp_main.c:505 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #12 0x7f4b7a479d09 in __libc_start_main ../csu/libc-start.c:308 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251:Direct leak of 32 byte(s) in 2 object(s) allocated from: ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #0 0x7f4b7ae92037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #1 0x7f4b7aa96e38 in qcalloc lib/memory.c:105 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #2 0x56396f8e31b8 in vpn_leak_zebra_vrf_sid_update_per_af bgpd/bgp_mplsvpn.c:386 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #3 0x56396f8e3ae8 in vpn_leak_zebra_vrf_sid_update bgpd/bgp_mplsvpn.c:448 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #4 0x56396f8e09b0 in vpn_leak_postchange bgpd/bgp_mplsvpn.h:271 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #5 0x56396f8f3e5b in vpn_leak_postchange_all bgpd/bgp_mplsvpn.c:3397 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #6 0x56396fa920ef in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3238 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #7 0x7f4b7abb2913 in zclient_read lib/zclient.c:4134 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #8 0x7f4b7ab62010 in thread_call lib/thread.c:1991 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #9 0x7f4b7aa5a418 in frr_run lib/libfrr.c:1185 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #10 0x56396f7d756d in main bgpd/bgp_main.c:505 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #11 0x7f4b7a479d09 in __libc_start_main ../csu/libc-start.c:308 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251:Direct leak of 32 byte(s) in 2 object(s) allocated from: ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #0 0x7f4b7ae92037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #1 0x7f4b7aa96e38 in qcalloc lib/memory.c:105 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #2 0x56396f8e5730 in ensure_vrf_tovpn_sid_per_af bgpd/bgp_mplsvpn.c:753 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #3 0x56396f8e608a in ensure_vrf_tovpn_sid bgpd/bgp_mplsvpn.c:846 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #4 0x56396f8e075d in vpn_leak_postchange bgpd/bgp_mplsvpn.h:259 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #5 0x56396f8f3e5b in vpn_leak_postchange_all bgpd/bgp_mplsvpn.c:3397 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #6 0x56396fa920ef in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3238 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #7 0x7f4b7abb2913 in zclient_read lib/zclient.c:4134 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #8 0x7f4b7ab62010 in thread_call lib/thread.c:1991 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #9 0x7f4b7aa5a418 in frr_run lib/libfrr.c:1185 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #10 0x56396f7d756d in main bgpd/bgp_main.c:505 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- #11 0x7f4b7a479d09 in __libc_start_main ../csu/libc-start.c:308 ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251- ./bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.bgpd.asan.603251-SUMMARY: AddressSanitizer: 656 byte(s) leaked in 6 allocation(s). Signed-off-by: ryndia <dindyalsarvesh@gmail.com>
2023-06-27 08:59:09 +02:00
void sid_unregister(struct bgp *bgp, const struct in6_addr *sid)
{
struct listnode *node, *nnode;
struct bgp_srv6_function *func;
for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func))
if (sid_same(&func->sid, sid)) {
listnode_delete(bgp->srv6_functions, func);
bgpd: Free Memory for SRv6 Functions and Locator Chunks Implement proper memory cleanup for SRv6 functions and locator chunks to prevent potential memory leaks. The list callback deletion functions have been set. The ASan leak log for reference: ``` *********************************************************************************** Address Sanitizer Error detected in bgp_srv6l3vpn_to_bgp_vrf.test_bgp_srv6l3vpn_to_bgp_vrf/r2.asan.bgpd.4180 ================================================================= ==4180==ERROR: LeakSanitizer: detected memory leaks Direct leak of 544 byte(s) in 2 object(s) allocated from: #0 0x7f8d176a0d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f8d1709f238 in qcalloc lib/memory.c:105 #2 0x55d5dba6ee75 in sid_register bgpd/bgp_mplsvpn.c:591 #3 0x55d5dba6ee75 in alloc_new_sid bgpd/bgp_mplsvpn.c:712 #4 0x55d5dba6f3ce in ensure_vrf_tovpn_sid_per_af bgpd/bgp_mplsvpn.c:758 #5 0x55d5dba6fb94 in ensure_vrf_tovpn_sid bgpd/bgp_mplsvpn.c:849 #6 0x55d5dba7f975 in vpn_leak_postchange bgpd/bgp_mplsvpn.h:299 #7 0x55d5dba7f975 in vpn_leak_postchange_all bgpd/bgp_mplsvpn.c:3704 #8 0x55d5dbbb6c66 in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3164 #9 0x7f8d1716f08a in zclient_read lib/zclient.c:4459 #10 0x7f8d1713f034 in event_call lib/event.c:1974 #11 0x7f8d1708242b in frr_run lib/libfrr.c:1214 #12 0x55d5db99d19d in main bgpd/bgp_main.c:510 #13 0x7f8d160c5c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 296 byte(s) in 1 object(s) allocated from: #0 0x7f8d176a0d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f8d1709f238 in qcalloc lib/memory.c:105 #2 0x7f8d170b1d5f in srv6_locator_chunk_alloc lib/srv6.c:135 #3 0x55d5dbbb6a19 in bgp_zebra_process_srv6_locator_chunk bgpd/bgp_zebra.c:3144 #4 0x7f8d1716f08a in zclient_read lib/zclient.c:4459 #5 0x7f8d1713f034 in event_call lib/event.c:1974 #6 0x7f8d1708242b in frr_run lib/libfrr.c:1214 #7 0x55d5db99d19d in main bgpd/bgp_main.c:510 #8 0x7f8d160c5c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) *********************************************************************************** ``` Signed-off-by: Keelan Cannoo <keelan.cannoo@icloud.com>
2023-11-29 12:49:58 +01:00
srv6_function_free(func);
}
}
static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
{
struct listnode *node;
struct bgp_srv6_function *func;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func))
if (sid_same(&func->sid, sid))
return true;
return false;
}
/*
* This function generates a new SID based on bgp->srv6_locator_chunks and
* index. The locator and generated SID are stored in arguments sid_locator
* and sid, respectively.
*
* if index != 0: try to allocate as index-mode
* else: try to allocate as auto-mode
*/
static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
struct srv6_locator_chunk *sid_locator_chunk,
struct in6_addr *sid)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct listnode *node;
struct srv6_locator_chunk *chunk;
bool alloced = false;
int label = 0;
uint8_t offset = 0;
uint8_t func_len = 0, shift_len = 0;
uint32_t index_max = 0;
if (!bgp || !sid_locator_chunk || !sid)
return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
if (chunk->function_bits_length >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
if (debug)
zlog_debug(
"%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d",
__func__, &chunk->prefix,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
continue;
}
index_max = (1 << chunk->function_bits_length) - 1;
if (index > index_max) {
if (debug)
zlog_debug(
"%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)",
__func__, &chunk->prefix, index);
continue;
}
*sid = chunk->prefix.prefix;
*sid_locator_chunk = *chunk;
offset = chunk->block_bits_length + chunk->node_bits_length;
func_len = chunk->function_bits_length;
shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
if (index != 0) {
label = index << shift_len;
if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (debug)
zlog_debug(
"%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
__func__, &chunk->prefix,
label);
continue;
}
transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
break;
}
for (uint32_t i = 1; i < index_max; i++) {
label = i << shift_len;
if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (debug)
zlog_debug(
"%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
__func__, &chunk->prefix,
label);
continue;
}
transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
break;
}
}
if (!alloced)
return 0;
sid_register(bgp, sid, bgp->srv6_locator_name);
return label;
}
void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct srv6_locator_chunk *tovpn_sid_locator;
struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
/* skip when tovpn sid is already allocated on vrf instance */
if (bgp_vrf->vpn_policy[afi].tovpn_sid)
return;
/*
* skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated
*/
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
return;
tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO);
/* skip when VPN isn't configured on vrf-instance */
if (tovpn_sid_index == 0 && !tovpn_sid_auto)
return;
/* check invalid case both configured index and auto */
if (tovpn_sid_index != 0 && tovpn_sid_auto) {
zlog_err("%s: index-mode and auto-mode both selected. ignored.",
__func__);
return;
}
tovpn_sid_locator = srv6_locator_chunk_alloc();
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
tovpn_sid_locator, tovpn_sid);
if (tovpn_sid_transpose_label == 0) {
if (debug)
zlog_debug(
"%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
}
if (debug)
zlog_debug("%s: new sid %pI6 allocated for vrf %s: afi %s",
__func__, tovpn_sid, bgp_vrf->name_pretty,
afi2str(afi));
bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
tovpn_sid_transpose_label;
}
void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct srv6_locator_chunk *tovpn_sid_locator;
struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s", __func__,
bgp_vrf->name_pretty);
/* skip when tovpn sid is already allocated on vrf instance */
if (bgp_vrf->tovpn_sid)
return;
/*
* skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated
*/
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
return;
tovpn_sid_index = bgp_vrf->tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
/* skip when VPN isn't configured on vrf-instance */
if (tovpn_sid_index == 0 && !tovpn_sid_auto)
return;
/* check invalid case both configured index and auto */
if (tovpn_sid_index != 0 && tovpn_sid_auto) {
zlog_err("%s: index-mode and auto-mode both selected. ignored.",
__func__);
return;
}
tovpn_sid_locator = srv6_locator_chunk_alloc();
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
tovpn_sid_locator, tovpn_sid);
if (tovpn_sid_transpose_label == 0) {
if (debug)
zlog_debug("%s: not allocated new sid for vrf %s",
__func__, bgp_vrf->name_pretty);
srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
}
if (debug)
zlog_debug("%s: new sid %pI6 allocated for vrf %s", __func__,
tovpn_sid, bgp_vrf->name_pretty);
bgp_vrf->tovpn_sid = tovpn_sid;
bgp_vrf->tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label;
}
void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
{
/* per-af sid */
if (bgp_vrf->vpn_policy[afi].tovpn_sid_index != 0 ||
CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO))
return ensure_vrf_tovpn_sid_per_af(bgp_vpn, bgp_vrf, afi);
/* per-vrf sid */
if (bgp_vrf->tovpn_sid_index != 0 ||
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))
return ensure_vrf_tovpn_sid_per_vrf(bgp_vpn, bgp_vrf);
}
void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
if (debug)
zlog_debug("%s: try to remove SID for vrf %s: afi %s", __func__,
bgp_vrf->name_pretty, afi2str(afi));
tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO);
/* skip when VPN is configured on vrf-instance */
if (tovpn_sid_index != 0 || tovpn_sid_auto)
return;
srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
}
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = 0;
}
void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
if (debug)
zlog_debug("%s: try to remove SID for vrf %s", __func__,
bgp_vrf->name_pretty);
tovpn_sid_index = bgp_vrf->tovpn_sid_index;
tovpn_sid_auto =
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VPN_POLICY_TOVPN_SID_AUTO);
/* skip when VPN is configured on vrf-instance */
if (tovpn_sid_index != 0 || tovpn_sid_auto)
return;
srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
if (bgp_vrf->tovpn_sid) {
sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
}
bgp_vrf->tovpn_sid_transpose_label = 0;
}
void delete_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
{
delete_vrf_tovpn_sid_per_af(bgp_vpn, bgp_vrf, afi);
delete_vrf_tovpn_sid_per_vrf(bgp_vpn, bgp_vrf);
}
/*
* This function embeds upper `len` bits of `label` in `sid`,
* starting at offset `offset` as seen from the MSB of `sid`.
*
* e.g. Given that `label` is 0x12345 and `len` is 16,
* then `label` will be embedded in `sid` as follows:
*
* <---- len ----->
* label: 0001 0002 0003 0004 0005
* sid: .... 0001 0002 0003 0004
* <---- len ----->
* ^
* |
* offset from MSB
*
* e.g. Given that `label` is 0x12345 and `len` is 8,
* `label` will be embedded in `sid` as follows:
*
* <- len ->
* label: 0001 0002 0003 0004 0005
* sid: .... 0001 0002 0000 0000
* <- len ->
* ^
* |
* offset from MSB
*/
void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
uint8_t len)
{
for (uint8_t idx = 0; idx < len; idx++) {
uint8_t tidx = offset + idx;
sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
if (label >> (19 - idx) & 0x1)
sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
}
}
static bool labels_same(struct bgp_path_info *bpi, mpls_label_t *label,
uint32_t n)
{
if (!bpi->extra) {
if (!n)
return true;
else
return false;
}
return bgp_labels_same((const mpls_label_t *)bpi->extra->label,
bpi->extra->num_labels,
(const mpls_label_t *)label, n);
}
/*
* make encoded route labels match specified encoded label set
*/
static void setlabels(struct bgp_path_info *bpi,
mpls_label_t *label, /* array of labels */
uint32_t num_labels)
{
if (num_labels)
assert(label);
assert(num_labels <= BGP_MAX_LABELS);
if (!num_labels) {
if (bpi->extra)
bpi->extra->num_labels = 0;
return;
}
struct bgp_path_info_extra *extra = bgp_path_info_extra_get(bpi);
uint32_t i;
for (i = 0; i < num_labels; ++i) {
extra->label[i] = label[i];
if (!bgp_is_valid_label(&label[i])) {
bgp_set_valid_label(&extra->label[i]);
}
}
extra->num_labels = num_labels;
}
static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
struct attr *new_attr, afi_t afi,
safi_t safi,
struct bgp_path_info *source_bpi,
struct bgp_path_info *bpi,
struct bgp *bgp_orig,
const struct prefix *p, int debug)
{
struct bgp_path_info *bpi_ultimate;
struct bgp *bgp_nexthop;
struct bgp_table *table;
bool nh_valid;
bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
table = bgp_dest_table(bpi_ultimate->net);
if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig)
bgp_nexthop = bpi->extra->vrfleak->bgp_orig;
else
bgp_nexthop = bgp_orig;
/*
* No nexthop tracking for redistributed routes, for
* EVPN-imported routes that get leaked, or for routes
* leaked between VRFs with accept-own community.
*/
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
is_pi_family_evpn(bpi_ultimate) ||
CHECK_FLAG(bpi_ultimate->flags, BGP_PATH_ACCEPT_OWN))
nh_valid = true;
else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP &&
bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table &&
(table->safi == SAFI_UNICAST ||
table->safi == SAFI_LABELED_UNICAST)) {
/* the route is defined with the "network <prefix>" command */
if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK))
nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop,
afi, SAFI_UNICAST,
bpi_ultimate, NULL,
0, p);
else
/* if "no bgp network import-check" is set,
* then mark the nexthop as valid.
*/
nh_valid = true;
} else
/*
* TBD do we need to do anything about the
* 'connected' parameter?
*/
nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, afi,
safi, bpi, NULL, 0, p);
/*
* If you are using SRv6 VPN instead of MPLS, it need to check
* the SID allocation. If the sid is not allocated, the rib
* will be invalid.
*/
if (to_bgp->srv6_enabled &&
(!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
nh_valid = false;
}
if (debug)
zlog_debug("%s: %pFX nexthop is %svalid (in %s)", __func__, p,
(nh_valid ? "" : "not "), bgp_nexthop->name_pretty);
return nh_valid;
}
/*
* returns pointer to new bgp_path_info upon success
*/
static struct bgp_path_info *
leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
struct attr *new_attr, /* already interned */
afi_t afi, safi_t safi, struct bgp_path_info *source_bpi,
mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig,
struct prefix *nexthop_orig, int nexthop_self_flag, int debug)
{
const struct prefix *p = bgp_dest_get_prefix(bn);
struct bgp_path_info *bpi;
struct bgp_path_info *new;
struct bgp_path_info_extra *extra;
struct bgp_path_info *parent = source_bpi;
if (debug)
zlog_debug(
"%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d",
__func__, to_bgp->name_pretty, bn, source_bpi->type,
source_bpi->sub_type);
/*
* Routes that are redistributed into BGP from zebra do not get
bgpd: export redistributed routes with label allocation per nexthop The label allocation per nexthop mode requires to use a nexthop tracking context. For redistributed routes, a nexthop tracking context is created, and the resolution helps to know the real nexthop ip address used. The below configuration example has been used: > vrf vrf1 > ip route 172.31.0.14/32 192.0.2.14 > ip route 172.31.0.15/32 192.0.2.12 > ip route 172.31.0.30/32 192.0.2.30 > exit > router bgp 65500 vrf vrf1 > address-family ipv4 unicast > redistribute static > label vpn export per-nexthop > [..] The static routes are correctly imported in the BGP IPv4 RIB. Contrary to label allocation per vrf mode, some nexthop tracking are created/or reused: > # show bgp vrf vrf1 nexthop > 192.0.2.12 valid [IGP metric 0], #paths 3, peer 192.0.2.12 > if r1-eth1 > Last update: Fri Jan 13 15:49:42 2023 > 192.0.2.14 valid [IGP metric 0], #paths 1 > if r1-eth1 > Last update: Fri Jan 13 15:49:42 2023 > 192.0.2.30 valid [IGP metric 0], #paths 1 > if r1-eth1 > Last update: Fri Jan 13 15:49:51 2023 > [..] This results in having a BGP VPN route for each of the static routes: > # show bgp ipv4 vpn > [..] > Route Distinguisher: 444:1 > *> 172.31.0.14/32 192.0.2.14@9< 0 32768 ? > *> 172.31.0.15/32 192.0.2.12@9< 0 32768 ? > *> 172.31.0.30/32 192.0.2.30@9< 0 32768 ? > [..] Without that patch, only the redistributed routes that rely on a pre-existing nexthop tracking context could be exported. Also, a command in the code about redistributed routes is modified accordingly, to explain that redistribute routes may be submitted to nexthop tracking in the case label allocation per next-hop is used. note: VNC routes have been removed from the redistribution, because of a test failure in the bgp_l3vpn_to_bgp_direct test. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-03-03 21:33:34 +01:00
* nexthop tracking, unless MPLS allocation per nexthop is
* performed. In the default case nexthop tracking does not apply,
* if those routes are subsequently imported to other RIBs within
* BGP, the leaked routes do not carry the original
* BGP_ROUTE_REDISTRIBUTE sub_type. Therefore, in order to determine
* if the route we are currently leaking should have nexthop
* tracking, we must find the ultimate parent so we can check its
* sub_type.
*
* As of now, source_bpi may at most be a second-generation route
* (only one hop back to ultimate parent for vrf-vpn-vrf scheme).
* Using a loop here supports more complex intra-bgp import-export
* schemes that could be implemented in the future.
*
*/
/*
* match parent
*/
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->parent == parent)
break;
}
if (bpi) {
bool labelssame = labels_same(bpi, label, num_labels);
VRF-Lite: Fix export of withdraw-in-progress routes Problem: Stale routes are seen in the bgp table(ipv4 and ipv6) RCA: Scenario1: Interface down and withdraw is in-progress. Router bgp config leading to re-leaking. Now, withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes. Whenever we see an interface down and corresponding address delete, while withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue. ‘router bgp’ config is updated, which triggers bgp_vpn_leak_export; which exports routes from configured bgp vrf to VPN. So withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Scenario2: - 'no import vrf non-default-vrf’ [in the default vrf] - bgp update from the peer withdrawing prefix [non-default vrf] - 'import vrf non-default-vrf’ [configured in the default vrf] While withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue, In the meantime, if import vrf is configured, which exports routes from configured bgp vrf to VPN. So withdraw-in-progress new routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Fix: Whenever leaking routes (leak_update), for already existing routes, skip the routes with bgp_path_info marked as being removed. Also added the log message for the return. Co-authored-by: Santosh P K <sapk@vmware.com> Co-authored-by: Kantesh Mundaragi <kmundaragi@vmware.com> Signed-off-by: Abhinay Ramesh <rabhinay@vmware.com>
2021-04-01 07:22:23 +02:00
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)
&& CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
if (debug) {
zlog_debug(
"%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking",
__func__, to_bgp->name_pretty,
VRF-Lite: Fix export of withdraw-in-progress routes Problem: Stale routes are seen in the bgp table(ipv4 and ipv6) RCA: Scenario1: Interface down and withdraw is in-progress. Router bgp config leading to re-leaking. Now, withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes. Whenever we see an interface down and corresponding address delete, while withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue. ‘router bgp’ config is updated, which triggers bgp_vpn_leak_export; which exports routes from configured bgp vrf to VPN. So withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Scenario2: - 'no import vrf non-default-vrf’ [in the default vrf] - bgp update from the peer withdrawing prefix [non-default vrf] - 'import vrf non-default-vrf’ [configured in the default vrf] While withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue, In the meantime, if import vrf is configured, which exports routes from configured bgp vrf to VPN. So withdraw-in-progress new routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Fix: Whenever leaking routes (leak_update), for already existing routes, skip the routes with bgp_path_info marked as being removed. Also added the log message for the return. Co-authored-by: Santosh P K <sapk@vmware.com> Co-authored-by: Kantesh Mundaragi <kmundaragi@vmware.com> Signed-off-by: Abhinay Ramesh <rabhinay@vmware.com>
2021-04-01 07:22:23 +02:00
source_bpi->flags, bpi->flags, p);
}
return NULL;
}
if (attrhash_cmp(bpi->attr, new_attr) && labelssame
&& !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
bgp_attr_unintern(&new_attr);
if (debug)
zlog_debug(
"%s: ->%s: %pBD: Found route, no change",
__func__, to_bgp->name_pretty, bn);
return NULL;
}
/* If the RT was changed via extended communities as an
* import/export list, we should withdraw implicitly the old
* path from VRFs.
* For instance, RT list was modified using route-maps:
* route-map test permit 10
* set extcommunity rt none
*/
if (CHECK_FLAG(bpi->attr->flag,
ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) &&
CHECK_FLAG(new_attr->flag,
ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
if (!ecommunity_cmp(
bgp_attr_get_ecommunity(bpi->attr),
bgp_attr_get_ecommunity(new_attr))) {
vpn_leak_to_vrf_withdraw(bpi);
bgp_aggregate_decrement(to_bgp, p, bpi, afi,
safi);
bgp_path_info_delete(bn, bpi);
}
}
/* attr is changed */
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ATTR_CHANGED);
/* Rewrite BGP route information. */
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
bgp_path_info_restore(bn, bpi);
else
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_attr_unintern(&bpi->attr);
bpi->attr = new_attr;
bpi->uptime = monotime(NULL);
/*
* rewrite labels
*/
if (!labelssame)
setlabels(bpi, label, num_labels);
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN);
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
source_bpi, bpi, bgp_orig, p,
debug))
bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID);
else
bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID);
/* Process change. */
bgp_aggregate_increment(to_bgp, p, bpi, afi, safi);
bgp_process(to_bgp, bn, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %pBD Found route, changed attr",
__func__, to_bgp->name_pretty, bn);
bgp_dest_unlock_node(bn);
return bpi;
}
VRF-Lite: Fix export of withdraw-in-progress routes Problem: Stale routes are seen in the bgp table(ipv4 and ipv6) RCA: Scenario1: Interface down and withdraw is in-progress. Router bgp config leading to re-leaking. Now, withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes. Whenever we see an interface down and corresponding address delete, while withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue. ‘router bgp’ config is updated, which triggers bgp_vpn_leak_export; which exports routes from configured bgp vrf to VPN. So withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Scenario2: - 'no import vrf non-default-vrf’ [in the default vrf] - bgp update from the peer withdrawing prefix [non-default vrf] - 'import vrf non-default-vrf’ [configured in the default vrf] While withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue, In the meantime, if import vrf is configured, which exports routes from configured bgp vrf to VPN. So withdraw-in-progress new routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Fix: Whenever leaking routes (leak_update), for already existing routes, skip the routes with bgp_path_info marked as being removed. Also added the log message for the return. Co-authored-by: Santosh P K <sapk@vmware.com> Co-authored-by: Kantesh Mundaragi <kmundaragi@vmware.com> Signed-off-by: Abhinay Ramesh <rabhinay@vmware.com>
2021-04-01 07:22:23 +02:00
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)) {
if (debug) {
zlog_debug(
"%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking",
__func__, to_bgp->name_pretty,
VRF-Lite: Fix export of withdraw-in-progress routes Problem: Stale routes are seen in the bgp table(ipv4 and ipv6) RCA: Scenario1: Interface down and withdraw is in-progress. Router bgp config leading to re-leaking. Now, withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes. Whenever we see an interface down and corresponding address delete, while withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue. ‘router bgp’ config is updated, which triggers bgp_vpn_leak_export; which exports routes from configured bgp vrf to VPN. So withdraw-in-progress routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Scenario2: - 'no import vrf non-default-vrf’ [in the default vrf] - bgp update from the peer withdrawing prefix [non-default vrf] - 'import vrf non-default-vrf’ [configured in the default vrf] While withdrawal of exported routes is in-progress, routes are marked as being removed and put into work queue, In the meantime, if import vrf is configured, which exports routes from configured bgp vrf to VPN. So withdraw-in-progress new routes, are again leaked to bgp vrf instance(s) importing routes; leading to stale routes. Fix: Whenever leaking routes (leak_update), for already existing routes, skip the routes with bgp_path_info marked as being removed. Also added the log message for the return. Co-authored-by: Santosh P K <sapk@vmware.com> Co-authored-by: Kantesh Mundaragi <kmundaragi@vmware.com> Signed-off-by: Abhinay Ramesh <rabhinay@vmware.com>
2021-04-01 07:22:23 +02:00
source_bpi->flags, p);
}
return NULL;
}
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
to_bgp->peer_self, new_attr, bn);
bgp_path_info_extra_get(new);
if (!new->extra->vrfleak)
new->extra->vrfleak =
XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK,
sizeof(struct bgp_path_info_extra_vrfleak));
if (source_bpi->peer) {
extra = bgp_path_info_extra_get(new);
extra->vrfleak->peer_orig = peer_lock(source_bpi->peer);
}
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN);
if (num_labels)
setlabels(new, label, num_labels);
new->extra->vrfleak->parent = bgp_path_info_lock(parent);
bgp_dest_lock_node(
(struct bgp_dest *)parent->net);
new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig);
if (nexthop_orig)
new->extra->vrfleak->nexthop_orig = *nexthop_orig;
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
source_bpi, new, bgp_orig, p, debug))
bgp_path_info_set_flag(bn, new, BGP_PATH_VALID);
else
bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID);
bgp_aggregate_increment(to_bgp, p, new, afi, safi);
bgp_path_info_add(bn, new);
bgp_process(to_bgp, bn, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %pBD: Added new route", __func__,
to_bgp->name_pretty, bn);
bgp_dest_unlock_node(bn);
return new;
}
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
void bgp_mplsvpn_path_nh_label_unlink(struct bgp_path_info *pi)
{
struct bgp_label_per_nexthop_cache *blnc;
if (!pi)
return;
if (!CHECK_FLAG(pi->flags, BGP_PATH_MPLSVPN_LABEL_NH))
return;
blnc = pi->mplsvpn.blnc.label_nexthop_cache;
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
if (!blnc)
return;
LIST_REMOVE(pi, mplsvpn.blnc.label_nh_thread);
pi->mplsvpn.blnc.label_nexthop_cache->path_count--;
pi->mplsvpn.blnc.label_nexthop_cache = NULL;
UNSET_FLAG(pi->flags, BGP_PATH_MPLSVPN_LABEL_NH);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
if (LIST_EMPTY(&(blnc->paths)))
bgp_label_per_nexthop_free(blnc);
}
/* Called upon reception of a ZAPI Message from zebra, about
* a new available label.
*/
static int bgp_mplsvpn_get_label_per_nexthop_cb(mpls_label_t label,
void *context, bool allocated)
{
struct bgp_label_per_nexthop_cache *blnc = context;
mpls_label_t old_label;
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct bgp_path_info *pi;
struct bgp_table *table;
old_label = blnc->label;
if (debug)
zlog_debug("%s: label=%u, allocated=%d, nexthop=%pFX", __func__,
label, allocated, &blnc->nexthop);
if (allocated)
/* update the entry with the new label */
blnc->label = label;
else
/*
* previously-allocated label is now invalid
* eg: zebra deallocated the labels and notifies it
*/
blnc->label = MPLS_INVALID_LABEL;
if (old_label == blnc->label)
return 0; /* no change */
/* update paths */
if (blnc->label != MPLS_INVALID_LABEL)
bgp_zebra_send_nexthop_label(ZEBRA_MPLS_LABELS_ADD, blnc->label,
blnc->nh->ifindex,
blnc->nh->vrf_id, ZEBRA_LSP_BGP,
&blnc->nexthop, 0, NULL);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
LIST_FOREACH (pi, &(blnc->paths), mplsvpn.blnc.label_nh_thread) {
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
if (!pi->net)
continue;
table = bgp_dest_table(pi->net);
if (!table)
continue;
vpn_leak_from_vrf_update(blnc->to_bgp, table->bgp, pi);
}
return 0;
}
/* Get a per label nexthop value:
* - Find and return a per label nexthop from the cache
* - else allocate a new per label nexthop cache entry and request a
* label to zebra. Return MPLS_INVALID_LABEL
*/
static mpls_label_t
_vpn_leak_from_vrf_get_per_nexthop_label(struct bgp_path_info *pi,
struct bgp *to_bgp,
struct bgp *from_bgp, afi_t afi)
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
{
struct bgp_nexthop_cache *bnc = pi->nexthop;
struct bgp_label_per_nexthop_cache *blnc;
struct bgp_label_per_nexthop_cache_head *tree;
struct prefix *nh_pfx = NULL;
struct prefix nh_gate = {0};
/* extract the nexthop from the BNC nexthop cache */
switch (bnc->nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
/* the nexthop is recursive */
nh_gate.family = AF_INET;
nh_gate.prefixlen = IPV4_MAX_BITLEN;
IPV4_ADDR_COPY(&nh_gate.u.prefix4, &bnc->nexthop->gate.ipv4);
nh_pfx = &nh_gate;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
/* the nexthop is recursive */
nh_gate.family = AF_INET6;
nh_gate.prefixlen = IPV6_MAX_BITLEN;
IPV6_ADDR_COPY(&nh_gate.u.prefix6, &bnc->nexthop->gate.ipv6);
nh_pfx = &nh_gate;
break;
case NEXTHOP_TYPE_IFINDEX:
/* the nexthop is direcly connected */
nh_pfx = &bnc->prefix;
break;
case NEXTHOP_TYPE_BLACKHOLE:
assert(!"Blackhole nexthop. Already checked by the caller.");
}
/* find or allocate a nexthop label cache entry */
tree = &from_bgp->mpls_labels_per_nexthop[family2afi(nh_pfx->family)];
blnc = bgp_label_per_nexthop_find(tree, nh_pfx);
if (!blnc) {
blnc = bgp_label_per_nexthop_new(tree, nh_pfx);
blnc->to_bgp = to_bgp;
/* request a label to zebra for this nexthop
* the response from zebra will trigger the callback
*/
bgp_lp_get(LP_TYPE_NEXTHOP, blnc,
bgp_mplsvpn_get_label_per_nexthop_cb);
}
if (pi->mplsvpn.blnc.label_nexthop_cache == blnc)
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
/* no change */
return blnc->label;
/* Unlink from any existing nexthop cache. Free the entry if unused.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
/* updates NHT pi list reference */
LIST_INSERT_HEAD(&(blnc->paths), pi, mplsvpn.blnc.label_nh_thread);
pi->mplsvpn.blnc.label_nexthop_cache = blnc;
pi->mplsvpn.blnc.label_nexthop_cache->path_count++;
SET_FLAG(pi->flags, BGP_PATH_MPLSVPN_LABEL_NH);
blnc->last_update = monotime(NULL);
/* then add or update the selected nexthop */
if (!blnc->nh)
blnc->nh = nexthop_dup(bnc->nexthop, NULL);
else if (!nexthop_same(bnc->nexthop, blnc->nh)) {
nexthop_free(blnc->nh);
blnc->nh = nexthop_dup(bnc->nexthop, NULL);
if (blnc->label != MPLS_INVALID_LABEL) {
bgp_zebra_send_nexthop_label(
ZEBRA_MPLS_LABELS_REPLACE, blnc->label,
bnc->nexthop->ifindex, bnc->nexthop->vrf_id,
ZEBRA_LSP_BGP, &blnc->nexthop, 0, NULL);
}
}
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
return blnc->label;
}
/* Filter out all the cases where a per nexthop label is not possible:
* - return an invalid label when the nexthop is invalid
* - return the per VRF label when the per nexthop label is not supported
* Otherwise, find or request a per label nexthop.
*/
static mpls_label_t
vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
struct bgp *from_bgp,
struct bgp *to_bgp)
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
{
struct bgp_path_info *bpi_ultimate = bgp_get_imported_bpi_ultimate(pi);
struct bgp *bgp_nexthop = NULL;
bool nh_valid;
afi_t nh_afi;
bool is_bgp_static_route;
is_bgp_static_route = bpi_ultimate->sub_type == BGP_ROUTE_STATIC &&
bpi_ultimate->type == ZEBRA_ROUTE_BGP;
if (is_bgp_static_route == false && afi == AFI_IP &&
CHECK_FLAG(pi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) &&
(pi->attr->nexthop.s_addr == INADDR_ANY ||
!ipv4_unicast_valid(&pi->attr->nexthop))) {
/* IPv4 nexthop in standard BGP encoding format.
* Format of address is not valid (not any, not unicast).
* Fallback to the per VRF label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
return from_bgp->vpn_policy[afi].tovpn_label;
}
if (is_bgp_static_route == false && afi == AFI_IP &&
pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4 &&
(pi->attr->mp_nexthop_global_in.s_addr == INADDR_ANY ||
!ipv4_unicast_valid(&pi->attr->mp_nexthop_global_in))) {
/* IPv4 nexthop is in MP-BGP encoding format.
* Format of address is not valid (not any, not unicast).
* Fallback to the per VRF label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
return from_bgp->vpn_policy[afi].tovpn_label;
}
if (is_bgp_static_route == false && afi == AFI_IP6 &&
(pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) &&
(IN6_IS_ADDR_UNSPECIFIED(&pi->attr->mp_nexthop_global) ||
IN6_IS_ADDR_LOOPBACK(&pi->attr->mp_nexthop_global) ||
IN6_IS_ADDR_MULTICAST(&pi->attr->mp_nexthop_global))) {
/* IPv6 nexthop is in MP-BGP encoding format.
* Format of address is not valid
* Fallback to the per VRF label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
return from_bgp->vpn_policy[afi].tovpn_label;
}
/* Check the next-hop reachability.
* Get the bgp instance where the bgp_path_info originates.
*/
if (pi->extra && pi->extra->vrfleak && pi->extra->vrfleak->bgp_orig)
bgp_nexthop = pi->extra->vrfleak->bgp_orig;
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
else
bgp_nexthop = from_bgp;
nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr);
nh_valid = bgp_find_or_add_nexthop(from_bgp, bgp_nexthop, nh_afi,
SAFI_UNICAST, pi, NULL, 0, NULL);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
if (!nh_valid && is_bgp_static_route &&
!CHECK_FLAG(from_bgp->flags, BGP_FLAG_IMPORT_CHECK)) {
/* "network" prefixes not routable, but since 'no bgp network
* import-check' is configured, they are always valid in the BGP
* table. Fallback to the per-vrf label
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
return from_bgp->vpn_policy[afi].tovpn_label;
}
if (!nh_valid || !pi->nexthop || pi->nexthop->nexthop_num == 0 ||
!pi->nexthop->nexthop) {
/* invalid next-hop:
* do not send the per-vrf label
* otherwise, when the next-hop becomes valid,
* we will have 2 BGP updates:
* - one with the per-vrf label
* - the second with the per-nexthop label
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
return MPLS_INVALID_LABEL;
}
if (pi->nexthop->nexthop_num > 1 ||
pi->nexthop->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
/* Blackhole or ECMP routes
* is not compatible with per-nexthop label.
* Fallback to per-vrf label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
return from_bgp->vpn_policy[afi].tovpn_label;
}
return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp,
afi);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
}
/* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */
void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
const struct prefix *p = bgp_dest_get_prefix(path_vrf->net);
afi_t afi = family2afi(p->family);
struct attr static_attr = {0};
struct attr *new_attr = NULL;
safi_t safi = SAFI_MPLS_VPN;
mpls_label_t label_val;
mpls_label_t label;
struct bgp_dest *bn;
const char *debugmsg;
int nexthop_self_flag = 0;
struct ecommunity *old_ecom;
struct ecommunity *new_ecom = NULL;
struct ecommunity *rtlist_ecom;
if (debug)
zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty);
if (debug && bgp_attr_get_ecommunity(path_vrf->attr)) {
char *s = ecommunity_ecom2str(
bgp_attr_get_ecommunity(path_vrf->attr),
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__,
from_bgp->name, path_vrf->type, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
if (!to_bgp)
return;
if (!afi) {
if (debug)
zlog_debug("%s: can't get afi of prefix", __func__);
return;
}
/* Is this route exportable into the VPN table? */
if (!is_route_injectable_into_vpn(path_vrf))
return;
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, false)) {
if (debug)
zlog_debug("%s: %s skipping: %s", __func__,
from_bgp->name, debugmsg);
return;
}
/* shallow copy */
static_attr = *path_vrf->attr;
if (debug && bgp_attr_get_ecommunity(&static_attr)) {
char *s = ecommunity_ecom2str(
bgp_attr_get_ecommunity(&static_attr),
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: post route map static_attr.ecommunity{%s}",
__func__, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
/*
* Add the vpn-policy rt-list
*/
/* Export with the 'from' instance's export RTs. */
/* If doing VRF-to-VRF leaking, strip existing RTs first. */
old_ecom = bgp_attr_get_ecommunity(&static_attr);
rtlist_ecom = from_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN];
if (old_ecom) {
new_ecom = ecommunity_dup(old_ecom);
if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT))
ecommunity_strip_rts(new_ecom);
if (rtlist_ecom)
new_ecom = ecommunity_merge(new_ecom, rtlist_ecom);
if (!old_ecom->refcnt)
ecommunity_free(&old_ecom);
} else if (rtlist_ecom) {
new_ecom = ecommunity_dup(rtlist_ecom);
} else {
new_ecom = NULL;
}
bgp_attr_set_ecommunity(&static_attr, new_ecom);
/*
* route map handling
*/
if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
struct bgp_path_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
info.peer = to_bgp->peer_self;
info.attr = &static_attr;
ret = route_map_apply(from_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_TOVPN],
p, &info);
if (RMAP_DENYMATCH == ret) {
bgp_attr_flush(&static_attr); /* free any added parts */
if (debug)
zlog_debug("%s: vrf %s route map \"%s\" says DENY, returning",
__func__, from_bgp->name_pretty,
from_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_TOVPN]
->name);
return;
}
}
new_ecom = bgp_attr_get_ecommunity(&static_attr);
if (!ecommunity_has_route_target(new_ecom)) {
ecommunity_free(&new_ecom);
if (debug)
zlog_debug("%s: %s skipping: waiting for a valid export rt list.",
__func__, from_bgp->name_pretty);
return;
}
if (debug && bgp_attr_get_ecommunity(&static_attr)) {
char *s = ecommunity_ecom2str(
bgp_attr_get_ecommunity(&static_attr),
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: post merge static_attr.ecommunity{%s}",
__func__, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
community_strip_accept_own(&static_attr);
/* Nexthop */
/* if policy nexthop not set, use 0 */
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
struct prefix *nexthop =
&from_bgp->vpn_policy[afi].tovpn_nexthop;
switch (nexthop->family) {
case AF_INET:
/* prevent mp_nexthop_global_in <- self in bgp_route.c
*/
static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr;
static_attr.mp_nexthop_global_in = nexthop->u.prefix4;
static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
break;
case AF_INET6:
static_attr.mp_nexthop_global = nexthop->u.prefix6;
static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
break;
default:
assert(0);
}
} else {
if (!CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
if (afi == AFI_IP &&
!BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
/*
* For ipv4, copy to multiprotocol
* nexthop field
*/
static_attr.mp_nexthop_global_in =
static_attr.nexthop;
static_attr.mp_nexthop_len =
BGP_ATTR_NHLEN_IPV4;
/*
* XXX Leave static_attr.nexthop
* intact for NHT
*/
static_attr.flag &=
~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
}
} else {
/* Update based on next-hop family to account for
* RFC 5549 (BGP unnumbered) scenario. Note that
* specific action is only needed for the case of
* IPv4 nexthops as the attr has been copied
* otherwise.
*/
if (afi == AFI_IP
&& !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
static_attr.mp_nexthop_global_in.s_addr =
static_attr.nexthop.s_addr;
static_attr.mp_nexthop_len =
BGP_ATTR_NHLEN_IPV4;
static_attr.flag |=
ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
}
}
nexthop_self_flag = 1;
}
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP))
/* per nexthop label mode */
label_val = vpn_leak_from_vrf_get_per_nexthop_label(
afi, path_vrf, from_bgp, to_bgp);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
else
/* per VRF label mode */
label_val = from_bgp->vpn_policy[afi].tovpn_label;
if (label_val == MPLS_INVALID_LABEL &&
CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) {
/* no valid label for the moment
* when the 'bgp_mplsvpn_get_label_per_nexthop_cb' callback gets
* a valid label value, it will call the current function again.
*/
if (debug)
zlog_debug(
"%s: %s skipping: waiting for a valid per-label nexthop.",
__func__, from_bgp->name_pretty);
bgpd: Ecommunity_dup memory leak fix The shallow copy of attr wasn't freed when there was no valid label for the momentand the function return therefore creating leaks. The leak below are solved by flushing the shallow copy of attr. Address Sanitizer Error detected in bgp_vpnv6_per_nexthop_label.test_bgp_vpnv6_per_nexthop_label/r1.asan.bgpd.13409 ================================================================= ==13409==ERROR: LeakSanitizer: detected memory leaks Direct leak of 280 byte(s) in 7 object(s) allocated from: #0 0x7f62cd0c9d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f62ccac21c3 in qcalloc lib/memory.c:105 #2 0x5623b8810dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88c13b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x5623b89beabc in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x5623b89beabc in af_label_vpn_export_allocation_mode_magic bgpd/bgp_vty.c:9464 #7 0x5623b89beabc in af_label_vpn_export_allocation_mode bgpd/bgp_vty_clippy.c:2809 #8 0x7f62cca45511 in cmd_execute_command_real lib/command.c:978 #9 0x7f62cca459d5 in cmd_execute_command lib/command.c:1036 #10 0x7f62cca45e54 in cmd_execute lib/command.c:1203 #11 0x7f62ccb6ee20 in vty_command lib/vty.c:591 #12 0x7f62ccb6f2cb in vty_execute lib/vty.c:1354 #13 0x7f62ccb77b95 in vtysh_read lib/vty.c:2362 #14 0x7f62ccb62b8f in event_call lib/event.c:1969 #15 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #16 0x5623b87e054b in main bgpd/bgp_main.c:510 #17 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 280 byte(s) in 7 object(s) allocated from: #0 0x7f62cd0c9d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f62ccac21c3 in qcalloc lib/memory.c:105 #2 0x5623b8810dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b892e86d in bgp_update bgpd/bgp_route.c:4969 #5 0x5623b893134d in bgp_nlri_parse_ip bgpd/bgp_route.c:6213 #6 0x5623b88e2a0e in bgp_nlri_parse bgpd/bgp_packet.c:341 #7 0x5623b88e4f7c in bgp_update_receive bgpd/bgp_packet.c:2220 #8 0x5623b88f0474 in bgp_process_packet bgpd/bgp_packet.c:3386 #9 0x7f62ccb62b8f in event_call lib/event.c:1969 #10 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #11 0x5623b87e054b in main bgpd/bgp_main.c:510 #12 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 280 byte(s) in 7 object(s) allocated from: #0 0x7f62cd0c9d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f62ccac21c3 in qcalloc lib/memory.c:105 #2 0x5623b8810dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88c13b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x5623b89bdebb in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x5623b89bdebb in af_label_vpn_export_magic bgpd/bgp_vty.c:9547 #7 0x5623b89bdebb in af_label_vpn_export bgpd/bgp_vty_clippy.c:2868 #8 0x7f62cca45511 in cmd_execute_command_real lib/command.c:978 #9 0x7f62cca459d5 in cmd_execute_command lib/command.c:1036 #10 0x7f62cca45e54 in cmd_execute lib/command.c:1203 #11 0x7f62ccb6ee20 in vty_command lib/vty.c:591 #12 0x7f62ccb6f2cb in vty_execute lib/vty.c:1354 #13 0x7f62ccb77b95 in vtysh_read lib/vty.c:2362 #14 0x7f62ccb62b8f in event_call lib/event.c:1969 #15 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #16 0x5623b87e054b in main bgpd/bgp_main.c:510 #17 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 240 byte(s) in 6 object(s) allocated from: #0 0x7f62cd0c9d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f62ccac21c3 in qcalloc lib/memory.c:105 #2 0x5623b8810dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88dc289 in evaluate_paths bgpd/bgp_nht.c:1384 #5 0x5623b88ddb0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x5623b88de027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x5623b8a03163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f62ccb92d8a in zclient_read lib/zclient.c:4425 #9 0x7f62ccb62b8f in event_call lib/event.c:1969 #10 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #11 0x5623b87e054b in main bgpd/bgp_main.c:510 #12 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 120 byte(s) in 3 object(s) allocated from: #0 0x7f62cd0c9d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f62ccac21c3 in qcalloc lib/memory.c:105 #2 0x5623b8810dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b893a406 in bgp_redistribute_add bgpd/bgp_route.c:8692 #5 0x5623b8a02b3b in zebra_read_route bgpd/bgp_zebra.c:595 #6 0x7f62ccb92d8a in zclient_read lib/zclient.c:4425 #7 0x7f62ccb62b8f in event_call lib/event.c:1969 #8 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #9 0x5623b87e054b in main bgpd/bgp_main.c:510 #10 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 80 byte(s) in 2 object(s) allocated from: #0 0x7f62cd0c9d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f62ccac21c3 in qcalloc lib/memory.c:105 #2 0x5623b8810dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88dc188 in evaluate_paths bgpd/bgp_nht.c:1348 #5 0x5623b88ddb0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x5623b88de027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x5623b8a03163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f62ccb92d8a in zclient_read lib/zclient.c:4425 #9 0x7f62ccb62b8f in event_call lib/event.c:1969 #10 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #11 0x5623b87e054b in main bgpd/bgp_main.c:510 #12 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 56 byte(s) in 7 object(s) allocated from: #0 0x7f62cd0c9b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f62ccac1ee3 in qmalloc lib/memory.c:100 #2 0x5623b8810eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88c13b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x5623b89beabc in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x5623b89beabc in af_label_vpn_export_allocation_mode_magic bgpd/bgp_vty.c:9464 #7 0x5623b89beabc in af_label_vpn_export_allocation_mode bgpd/bgp_vty_clippy.c:2809 #8 0x7f62cca45511 in cmd_execute_command_real lib/command.c:978 #9 0x7f62cca459d5 in cmd_execute_command lib/command.c:1036 #10 0x7f62cca45e54 in cmd_execute lib/command.c:1203 #11 0x7f62ccb6ee20 in vty_command lib/vty.c:591 #12 0x7f62ccb6f2cb in vty_execute lib/vty.c:1354 #13 0x7f62ccb77b95 in vtysh_read lib/vty.c:2362 #14 0x7f62ccb62b8f in event_call lib/event.c:1969 #15 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #16 0x5623b87e054b in main bgpd/bgp_main.c:510 #17 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 56 byte(s) in 7 object(s) allocated from: #0 0x7f62cd0c9b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f62ccac1ee3 in qmalloc lib/memory.c:100 #2 0x5623b8810eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b892e86d in bgp_update bgpd/bgp_route.c:4969 #5 0x5623b893134d in bgp_nlri_parse_ip bgpd/bgp_route.c:6213 #6 0x5623b88e2a0e in bgp_nlri_parse bgpd/bgp_packet.c:341 #7 0x5623b88e4f7c in bgp_update_receive bgpd/bgp_packet.c:2220 #8 0x5623b88f0474 in bgp_process_packet bgpd/bgp_packet.c:3386 #9 0x7f62ccb62b8f in event_call lib/event.c:1969 #10 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #11 0x5623b87e054b in main bgpd/bgp_main.c:510 #12 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 56 byte(s) in 7 object(s) allocated from: #0 0x7f62cd0c9b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f62ccac1ee3 in qmalloc lib/memory.c:100 #2 0x5623b8810eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88c13b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x5623b89bdebb in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x5623b89bdebb in af_label_vpn_export_magic bgpd/bgp_vty.c:9547 #7 0x5623b89bdebb in af_label_vpn_export bgpd/bgp_vty_clippy.c:2868 #8 0x7f62cca45511 in cmd_execute_command_real lib/command.c:978 #9 0x7f62cca459d5 in cmd_execute_command lib/command.c:1036 #10 0x7f62cca45e54 in cmd_execute lib/command.c:1203 #11 0x7f62ccb6ee20 in vty_command lib/vty.c:591 #12 0x7f62ccb6f2cb in vty_execute lib/vty.c:1354 #13 0x7f62ccb77b95 in vtysh_read lib/vty.c:2362 #14 0x7f62ccb62b8f in event_call lib/event.c:1969 #15 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #16 0x5623b87e054b in main bgpd/bgp_main.c:510 #17 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 48 byte(s) in 6 object(s) allocated from: #0 0x7f62cd0c9b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f62ccac1ee3 in qmalloc lib/memory.c:100 #2 0x5623b8810eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88dc289 in evaluate_paths bgpd/bgp_nht.c:1384 #5 0x5623b88ddb0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x5623b88de027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x5623b8a03163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f62ccb92d8a in zclient_read lib/zclient.c:4425 #9 0x7f62ccb62b8f in event_call lib/event.c:1969 #10 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #11 0x5623b87e054b in main bgpd/bgp_main.c:510 #12 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 24 byte(s) in 3 object(s) allocated from: #0 0x7f62cd0c9b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f62ccac1ee3 in qmalloc lib/memory.c:100 #2 0x5623b8810eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b893a406 in bgp_redistribute_add bgpd/bgp_route.c:8692 #5 0x5623b8a02b3b in zebra_read_route bgpd/bgp_zebra.c:595 #6 0x7f62ccb92d8a in zclient_read lib/zclient.c:4425 #7 0x7f62ccb62b8f in event_call lib/event.c:1969 #8 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #9 0x5623b87e054b in main bgpd/bgp_main.c:510 #10 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 16 byte(s) in 2 object(s) allocated from: #0 0x7f62cd0c9b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f62ccac1ee3 in qmalloc lib/memory.c:100 #2 0x5623b8810eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x5623b88be8eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x5623b88dc188 in evaluate_paths bgpd/bgp_nht.c:1348 #5 0x5623b88ddb0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x5623b88de027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x5623b8a03163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f62ccb92d8a in zclient_read lib/zclient.c:4425 #9 0x7f62ccb62b8f in event_call lib/event.c:1969 #10 0x7f62ccaa5462 in frr_run lib/libfrr.c:1213 #11 0x5623b87e054b in main bgpd/bgp_main.c:510 #12 0x7f62cbae7c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) SUMMARY: AddressSanitizer: 1536 byte(s) leaked in 64 allocation(s). *********************************************************************************** Address Sanitizer Error detected in bgp_vpnv4_per_nexthop_label.test_bgp_vpnv4_per_nexthop_label/r1.asan.bgpd.10610 ================================================================= ==10610==ERROR: LeakSanitizer: detected memory leaks Direct leak of 280 byte(s) in 7 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9c4686d in bgp_update bgpd/bgp_route.c:4969 #5 0x55cdc9c4934d in bgp_nlri_parse_ip bgpd/bgp_route.c:6213 #6 0x55cdc9bfaa0e in bgp_nlri_parse bgpd/bgp_packet.c:341 #7 0x55cdc9bfcf7c in bgp_update_receive bgpd/bgp_packet.c:2220 #8 0x55cdc9c08474 in bgp_process_packet bgpd/bgp_packet.c:3386 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 280 byte(s) in 7 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bd93b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x55cdc9cd6abc in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x55cdc9cd6abc in af_label_vpn_export_allocation_mode_magic bgpd/bgp_vty.c:9464 #7 0x55cdc9cd6abc in af_label_vpn_export_allocation_mode bgpd/bgp_vty_clippy.c:2809 #8 0x7f81fbede511 in cmd_execute_command_real lib/command.c:978 #9 0x7f81fbede9d5 in cmd_execute_command lib/command.c:1036 #10 0x7f81fbedee54 in cmd_execute lib/command.c:1203 #11 0x7f81fc007e20 in vty_command lib/vty.c:591 #12 0x7f81fc0082cb in vty_execute lib/vty.c:1354 #13 0x7f81fc010b95 in vtysh_read lib/vty.c:2362 #14 0x7f81fbffbb8f in event_call lib/event.c:1969 #15 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #16 0x55cdc9af854b in main bgpd/bgp_main.c:510 #17 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 280 byte(s) in 7 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bd93b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x55cdc9cd5ebb in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x55cdc9cd5ebb in af_label_vpn_export_magic bgpd/bgp_vty.c:9547 #7 0x55cdc9cd5ebb in af_label_vpn_export bgpd/bgp_vty_clippy.c:2868 #8 0x7f81fbede511 in cmd_execute_command_real lib/command.c:978 #9 0x7f81fbede9d5 in cmd_execute_command lib/command.c:1036 #10 0x7f81fbedee54 in cmd_execute lib/command.c:1203 #11 0x7f81fc007e20 in vty_command lib/vty.c:591 #12 0x7f81fc0082cb in vty_execute lib/vty.c:1354 #13 0x7f81fc010b95 in vtysh_read lib/vty.c:2362 #14 0x7f81fbffbb8f in event_call lib/event.c:1969 #15 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #16 0x55cdc9af854b in main bgpd/bgp_main.c:510 #17 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 240 byte(s) in 6 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bf4289 in evaluate_paths bgpd/bgp_nht.c:1384 #5 0x55cdc9bf5b0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x55cdc9bf6027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x55cdc9d1b163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f81fc02bd8a in zclient_read lib/zclient.c:4425 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 80 byte(s) in 2 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bf4188 in evaluate_paths bgpd/bgp_nht.c:1348 #5 0x55cdc9bf5b0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x55cdc9bf6027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x55cdc9d1b163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f81fc02bd8a in zclient_read lib/zclient.c:4425 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 80 byte(s) in 2 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bd93b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x55cdc9bdafd5 in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x55cdc9bdafd5 in vpn_leak_label_callback bgpd/bgp_mplsvpn.c:581 #7 0x55cdc9bb2606 in lp_cbq_docallback bgpd/bgp_labelpool.c:118 #8 0x7f81fc0164b5 in work_queue_run lib/workqueue.c:266 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Direct leak of 40 byte(s) in 1 object(s) allocated from: #0 0x7f81fc562d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f81fbf5b1c3 in qcalloc lib/memory.c:105 #2 0x55cdc9b28dc8 in ecommunity_dup bgpd/bgp_ecommunity.c:252 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9c52406 in bgp_redistribute_add bgpd/bgp_route.c:8692 #5 0x55cdc9d1ab3b in zebra_read_route bgpd/bgp_zebra.c:595 #6 0x7f81fc02bd8a in zclient_read lib/zclient.c:4425 #7 0x7f81fbffbb8f in event_call lib/event.c:1969 #8 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #9 0x55cdc9af854b in main bgpd/bgp_main.c:510 #10 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 56 byte(s) in 7 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bd93b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x55cdc9cd6abc in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x55cdc9cd6abc in af_label_vpn_export_allocation_mode_magic bgpd/bgp_vty.c:9464 #7 0x55cdc9cd6abc in af_label_vpn_export_allocation_mode bgpd/bgp_vty_clippy.c:2809 #8 0x7f81fbede511 in cmd_execute_command_real lib/command.c:978 #9 0x7f81fbede9d5 in cmd_execute_command lib/command.c:1036 #10 0x7f81fbedee54 in cmd_execute lib/command.c:1203 #11 0x7f81fc007e20 in vty_command lib/vty.c:591 #12 0x7f81fc0082cb in vty_execute lib/vty.c:1354 #13 0x7f81fc010b95 in vtysh_read lib/vty.c:2362 #14 0x7f81fbffbb8f in event_call lib/event.c:1969 #15 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #16 0x55cdc9af854b in main bgpd/bgp_main.c:510 #17 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 56 byte(s) in 7 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bd93b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x55cdc9cd5ebb in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x55cdc9cd5ebb in af_label_vpn_export_magic bgpd/bgp_vty.c:9547 #7 0x55cdc9cd5ebb in af_label_vpn_export bgpd/bgp_vty_clippy.c:2868 #8 0x7f81fbede511 in cmd_execute_command_real lib/command.c:978 #9 0x7f81fbede9d5 in cmd_execute_command lib/command.c:1036 #10 0x7f81fbedee54 in cmd_execute lib/command.c:1203 #11 0x7f81fc007e20 in vty_command lib/vty.c:591 #12 0x7f81fc0082cb in vty_execute lib/vty.c:1354 #13 0x7f81fc010b95 in vtysh_read lib/vty.c:2362 #14 0x7f81fbffbb8f in event_call lib/event.c:1969 #15 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #16 0x55cdc9af854b in main bgpd/bgp_main.c:510 #17 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 56 byte(s) in 7 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9c4686d in bgp_update bgpd/bgp_route.c:4969 #5 0x55cdc9c4934d in bgp_nlri_parse_ip bgpd/bgp_route.c:6213 #6 0x55cdc9bfaa0e in bgp_nlri_parse bgpd/bgp_packet.c:341 #7 0x55cdc9bfcf7c in bgp_update_receive bgpd/bgp_packet.c:2220 #8 0x55cdc9c08474 in bgp_process_packet bgpd/bgp_packet.c:3386 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 48 byte(s) in 6 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bf4289 in evaluate_paths bgpd/bgp_nht.c:1384 #5 0x55cdc9bf5b0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x55cdc9bf6027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x55cdc9d1b163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f81fc02bd8a in zclient_read lib/zclient.c:4425 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 16 byte(s) in 2 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bf4188 in evaluate_paths bgpd/bgp_nht.c:1348 #5 0x55cdc9bf5b0b in bgp_process_nexthop_update bgpd/bgp_nht.c:733 #6 0x55cdc9bf6027 in bgp_parse_nexthop_update bgpd/bgp_nht.c:934 #7 0x55cdc9d1b163 in bgp_read_nexthop_update bgpd/bgp_zebra.c:104 #8 0x7f81fc02bd8a in zclient_read lib/zclient.c:4425 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 16 byte(s) in 2 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9bd93b3 in vpn_leak_from_vrf_update_all bgpd/bgp_mplsvpn.c:2005 #5 0x55cdc9bdafd5 in vpn_leak_postchange bgpd/bgp_mplsvpn.h:287 #6 0x55cdc9bdafd5 in vpn_leak_label_callback bgpd/bgp_mplsvpn.c:581 #7 0x55cdc9bb2606 in lp_cbq_docallback bgpd/bgp_labelpool.c:118 #8 0x7f81fc0164b5 in work_queue_run lib/workqueue.c:266 #9 0x7f81fbffbb8f in event_call lib/event.c:1969 #10 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #11 0x55cdc9af854b in main bgpd/bgp_main.c:510 #12 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 8 byte(s) in 1 object(s) allocated from: #0 0x7f81fc562b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40) #1 0x7f81fbf5aee3 in qmalloc lib/memory.c:100 #2 0x55cdc9b28eb8 in ecommunity_dup bgpd/bgp_ecommunity.c:256 #3 0x55cdc9bd68eb in vpn_leak_from_vrf_update bgpd/bgp_mplsvpn.c:1628 #4 0x55cdc9c52406 in bgp_redistribute_add bgpd/bgp_route.c:8692 #5 0x55cdc9d1ab3b in zebra_read_route bgpd/bgp_zebra.c:595 #6 0x7f81fc02bd8a in zclient_read lib/zclient.c:4425 #7 0x7f81fbffbb8f in event_call lib/event.c:1969 #8 0x7f81fbf3e462 in frr_run lib/libfrr.c:1213 #9 0x55cdc9af854b in main bgpd/bgp_main.c:510 #10 0x7f81faf80c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) SUMMARY: AddressSanitizer: 1536 byte(s) leaked in 64 allocation(s). *********************************************************************************** Signed-off-by: ryndia <dindyalsarvesh@gmail.com>
2023-10-13 00:04:30 +02:00
bgp_attr_flush(&static_attr);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
return;
}
if (label_val == MPLS_LABEL_NONE)
encode_label(MPLS_LABEL_IMPLICIT_NULL, &label);
else
encode_label(label_val, &label);
/* Set originator ID to "me" */
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
static_attr.originator_id = to_bgp->router_id;
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
struct srv6_locator_chunk *locator =
from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
static_attr.srv6_l3vpn->endpoint_behavior =
afi == AFI_IP
? (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
? SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID
: SRV6_ENDPOINT_BEHAVIOR_END_DT4)
: (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
? SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID
: SRV6_ENDPOINT_BEHAVIOR_END_DT6);
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->node_bits_length;
static_attr.srv6_l3vpn->func_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->arg_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->argument_bits_length;
static_attr.srv6_l3vpn->transposition_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->transposition_offset =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->block_bits_length +
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->node_bits_length;
;
memcpy(&static_attr.srv6_l3vpn->sid,
&from_bgp->vpn_policy[afi]
.tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
} else if (from_bgp->tovpn_sid_locator) {
struct srv6_locator_chunk *locator =
from_bgp->tovpn_sid_locator;
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
static_attr.srv6_l3vpn->endpoint_behavior =
CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID
: SRV6_ENDPOINT_BEHAVIOR_END_DT46;
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
from_bgp->tovpn_sid_locator->node_bits_length;
static_attr.srv6_l3vpn->func_len =
from_bgp->tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->arg_len =
from_bgp->tovpn_sid_locator->argument_bits_length;
static_attr.srv6_l3vpn->transposition_len =
from_bgp->tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->transposition_offset =
from_bgp->tovpn_sid_locator->block_bits_length +
from_bgp->tovpn_sid_locator->node_bits_length;
memcpy(&static_attr.srv6_l3vpn->sid,
&from_bgp->tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
}
new_attr = bgp_attr_intern(
&static_attr); /* hashed refcounted everything */
bgp_attr_flush(&static_attr); /* free locally-allocated parts */
if (debug && bgp_attr_get_ecommunity(new_attr)) {
char *s = ecommunity_ecom2str(bgp_attr_get_ecommunity(new_attr),
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
/* Now new_attr is an allocated interned attr */
bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p,
&(from_bgp->vpn_policy[afi].tovpn_rd));
struct bgp_path_info *new_info;
new_info =
leak_update(to_bgp, bn, new_attr, afi, safi, path_vrf, &label,
1, from_bgp, NULL, nexthop_self_flag, debug);
/*
* Routes actually installed in the vpn RIB must also be
* offered to all vrfs (because now they originate from
* the vpn RIB).
*
* Acceptance into other vrfs depends on rt-lists.
* Originating vrf will not accept the looped back route
* because of loop checking.
*/
if (new_info)
vpn_leak_to_vrf_update(from_bgp, new_info, NULL);
else
bgp_dest_unlock_node(bn);
}
void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
const struct prefix *p = bgp_dest_get_prefix(path_vrf->net);
afi_t afi = family2afi(p->family);
safi_t safi = SAFI_MPLS_VPN;
struct bgp_path_info *bpi;
struct bgp_dest *bn;
const char *debugmsg;
if (debug) {
zlog_debug(
"%s: entry: leak-from=%s, p=%pBD, type=%d, sub_type=%d",
__func__, from_bgp->name_pretty, path_vrf->net,
path_vrf->type, path_vrf->sub_type);
}
if (!to_bgp)
return;
if (!afi) {
if (debug)
zlog_debug("%s: can't get afi of prefix", __func__);
return;
}
/* Is this route exportable into the VPN table? */
if (!is_route_injectable_into_vpn(path_vrf))
return;
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, true)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
return;
}
bn = bgp_safi_node_lookup(to_bgp->rib[afi][safi], safi, p,
&(from_bgp->vpn_policy[afi].tovpn_rd));
if (!bn)
return;
if (debug)
zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf);
/*
* vrf -> vpn
* match original bpi imported from
*/
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->parent == path_vrf) {
break;
}
}
if (bpi) {
/* withdraw from looped vrfs as well */
vpn_leak_to_vrf_withdraw(bpi);
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(to_bgp, bn, afi, safi);
}
bgp_dest_unlock_node(bn);
}
void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct bgp_dest *pdest;
safi_t safi = SAFI_MPLS_VPN;
/*
* Walk vpn table, delete bpi with bgp_orig == from_bgp
*/
for (pdest = bgp_table_top(to_bgp->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
struct bgp_dest *bn;
struct bgp_path_info *bpi;
/* This is the per-RD table of prefixes */
table = bgp_dest_get_bgp_table_info(pdest);
if (!table)
continue;
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
bpi = bgp_dest_get_bgp_path_info(bn);
if (debug && bpi) {
zlog_debug("%s: looking at prefix %pBD",
__func__, bn);
}
for (; bpi; bpi = bpi->next) {
if (debug)
zlog_debug("%s: type %d, sub_type %d",
__func__, bpi->type,
bpi->sub_type);
if (bpi->sub_type != BGP_ROUTE_IMPORTED)
continue;
if (!bpi->extra || !bpi->extra->vrfleak)
continue;
if ((struct bgp *)bpi->extra->vrfleak->bgp_orig ==
from_bgp) {
/* delete route */
if (debug)
zlog_debug("%s: deleting it",
__func__);
/* withdraw from leak-to vrfs as well */
vpn_leak_to_vrf_withdraw(bpi);
bgp_aggregate_decrement(
to_bgp, bgp_dest_get_prefix(bn),
bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(to_bgp, bn, afi, safi);
bgpd: add support for l3vpn per-nexthop label This commit introduces a new method to associate a label to prefixes to export to a VPNv4 backbone. All the methods to associate a label to a BGP update is documented in rfc4364, chapter 4.3.2. Initially, the "single label for an entire VRF" method was available. This commit adds "single label for each attachment circuit" method. The change impacts the control-plane, because each BGP update is checked to know if the nexthop has reachability in the VRF or not. If this is the case, then a unique label for a given destination IP in the VRF will be picked up. This label will be reused for an other BGP update that will have the same nexthop IP address. The change impacts the data-plane, because the MPLs pop mechanism applied to incoming labelled packets changes: the MPLS label is popped, and the packet is directly sent to the connected nexthop described in the previous outgoing BGP VPN update. By default per-vrf mode is done, but the user may choose the per-nexthop mode, by using the vty command from the previous commit. In the latter case, a per-vrf label will however be allocated to handle networks that are not directly connected. This is the case for local traffic for instance. The change also include the following: - ECMP case In case a route is learnt in a given VRF, and is resolved via an ECMP nexthop. This implies that when exporting the route as a BGP update, if label allocation per nexthop is used, then two possible MPLS values could be picked up, which is not possible with the current implementation. Actually, the NLRI for VPNv4 stores one prefix, and one single label value, not two. Today, RFC8277 with multiple label capability is not yet available. To avoid this corner case, when a route is resolved via more than one nexthop, the label allocation per nexthop will not apply, and the default per-vrf label will be chosen. Let us imagine BGP redistributes a static route using the `172.31.0.20` nexthop. The nexthop resolution will find two different nexthops fo a unique BGP update. > r1# show running-config > [..] > vrf vrf1 > ip route 172.31.0.30/32 172.31.0.20 > r1# show bgp vrf vrf1 nexthop > [..] > 172.31.0.20 valid [IGP metric 0], #paths 1 > gate 192.0.2.11 > gate 192.0.2.12 > Last update: Mon Jan 16 09:27:09 2023 > Paths: > 1/1 172.31.0.30/32 VRF vrf1 flags 0x20018 To avoid this situation, BGP updates that resolve over multiple nexthops are using the unique per-vrf label. - recursive route case Prefixes that need a recursive route to be resolved can also be eligible for mpls allocation per nexthop. In that case, the nexthop will be the recursive nexthop calculated. To achieve this, all nexthop types in bnc contexts are valid, except for the blackhole nexthops. - network declared prefixes Nexthop tracking is used to look for the reachability of the prefixes. When the the 'no bgp network import-check' command is used, network declared prefixes are maintained active, even if there is no active nexthop. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-02-28 14:25:02 +01:00
bgp_mplsvpn_path_nh_label_unlink(
bpi->extra->vrfleak->parent);
}
}
}
}
}
void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi)
{
struct bgp_dest *bn;
struct bgp_path_info *bpi;
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
if (debug)
zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
from_bgp->name_pretty);
for (bn = bgp_table_top(from_bgp->rib[afi][SAFI_UNICAST]); bn;
bn = bgp_route_next(bn)) {
if (debug)
zlog_debug("%s: node=%p", __func__, bn);
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (debug)
zlog_debug(
"%s: calling vpn_leak_from_vrf_update",
__func__);
vpn_leak_from_vrf_update(to_bgp, from_bgp, bpi);
}
}
}
static struct bgp *bgp_lookup_by_rd(struct bgp_path_info *bpi,
struct prefix_rd *rd, afi_t afi)
{
struct listnode *node, *nnode;
struct bgp *bgp;
if (!rd)
return NULL;
/* If ACCEPT_OWN is not enabled for this path - return. */
if (!CHECK_FLAG(bpi->flags, BGP_PATH_ACCEPT_OWN))
return NULL;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
if (!CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET))
continue;
/* Check if we have source VRF by RD value */
if (memcmp(&bgp->vpn_policy[afi].tovpn_rd.val, rd->val,
ECOMMUNITY_SIZE) == 0)
return bgp;
}
return NULL;
}
static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn,
struct prefix_rd *prd)
{
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
afi_t afi = family2afi(p->family);
struct attr static_attr = {0};
struct attr *new_attr = NULL;
struct bgp_dest *bn;
safi_t safi = SAFI_UNICAST;
const char *debugmsg;
struct prefix nexthop_orig;
mpls_label_t *pLabels = NULL;
uint32_t num_labels = 0;
int nexthop_self_flag = 1;
struct bgp_path_info *bpi_ultimate = NULL;
int origin_local = 0;
struct bgp *src_vrf;
struct interface *ifp;
bgpd: support for as notation format for route distinguisher RD may be built based on an AS number. Like for the AS, the RD may use the AS notation. The two below examples can illustrate: RD 1.1:20 stands for an AS4B:NN RD with AS4B=65536 in dot format. RD 0.1:20 stands for an AS2B:NNNN RD with AS2B=0.1 in dot+ format. This commit adds the asnotation mode to prefix_rd2str() API so as to pick up the relevant display. Two new printfrr extensions are available to display the RD with the two above display methods. - The pRDD extension stands for dot asnotation format - The pRDE extension stands for dot+ asnotation format. - The pRD extension has been renamed to pRDP extension The code is changed each time '%pRD' printf extension is called. Possibly, the asnotation may change the output, then a macro defines the asnotation mode to use. A side effect of forging the mode to use is that the string could not be concatenated with other strings in vty_out and snprintfrr. Those functions have been called multiple times. When zlog_debug needs to display the RD with some other string, the prefix_rd2str() old API is used instead of the printf extension. Some code has been kept untouched: - code related to running-config. Actually, wherever an RD is displayed, its configured name should be dumped. - bgp rfapi code - bgp evpn multihoming code (partially done), since the logic is missing to get the asnotation of 'struct bgp_evpn_es'. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-22 09:57:10 +01:00
char rd_buf[RD_ADDRSTRLEN];
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug(
"%s: from vpn (%s) to vrf (%s), skipping: %s",
__func__, from_bgp->name_pretty,
to_bgp->name_pretty, debugmsg);
return;
}
/*
* For VRF-2-VRF route-leaking,
* the source will be the originating VRF.
*
* If ACCEPT_OWN mechanism is enabled, then we SHOULD(?)
* get the source VRF (BGP) by looking at the RD.
*/
struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi);
if (path_vpn->extra && path_vpn->extra->vrfleak &&
path_vpn->extra->vrfleak->bgp_orig)
src_vrf = path_vpn->extra->vrfleak->bgp_orig;
else if (src_bgp)
src_vrf = src_bgp;
else
src_vrf = from_bgp;
/* Check for intersection of route targets */
if (!ecommunity_include(
to_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
bgp_attr_get_ecommunity(path_vpn->attr))) {
if (debug)
zlog_debug(
"from vpn (%s) to vrf (%s), skipping after no intersection of route targets",
from_bgp->name_pretty, to_bgp->name_pretty);
return;
}
rd_buf[0] = '\0';
if (debug && prd)
bgpd: support for as notation format for route distinguisher RD may be built based on an AS number. Like for the AS, the RD may use the AS notation. The two below examples can illustrate: RD 1.1:20 stands for an AS4B:NN RD with AS4B=65536 in dot format. RD 0.1:20 stands for an AS2B:NNNN RD with AS2B=0.1 in dot+ format. This commit adds the asnotation mode to prefix_rd2str() API so as to pick up the relevant display. Two new printfrr extensions are available to display the RD with the two above display methods. - The pRDD extension stands for dot asnotation format - The pRDE extension stands for dot+ asnotation format. - The pRD extension has been renamed to pRDP extension The code is changed each time '%pRD' printf extension is called. Possibly, the asnotation may change the output, then a macro defines the asnotation mode to use. A side effect of forging the mode to use is that the string could not be concatenated with other strings in vty_out and snprintfrr. Those functions have been called multiple times. When zlog_debug needs to display the RD with some other string, the prefix_rd2str() old API is used instead of the printf extension. Some code has been kept untouched: - code related to running-config. Actually, wherever an RD is displayed, its configured name should be dumped. - bgp rfapi code - bgp evpn multihoming code (partially done), since the logic is missing to get the asnotation of 'struct bgp_evpn_es'. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-22 09:57:10 +01:00
prefix_rd2str(prd, rd_buf, sizeof(rd_buf), to_bgp->asnotation);
/* A route MUST NOT ever be accepted back into its source VRF, even if
* it carries one or more RTs that match that VRF.
*/
bgpd: Skip RD match if ACCEPT_OWN is not enabled RFC7611 introduces new extended community ACCEPT_OWN and is already implemented for FRR in the previous PR. However, this PR broke compatibility about importing VPN routes. Let's consider the following situation. There are 2 routers and these routers connects with iBGP session. These routers have two VRF, vrf10 and vrf20, and RD 0:10, 0:20 is configured as the route distinguisher of vrf10 and vrf20 respectively. +- R1 --------+ +- R2 --------+ | +---------+ | | +---------+ | | | VRF10 | | | | VRF10 | | | | RD 0:10 +--------+ RD 0:10 | | | +---------+ | | +---------+ | | +---------+ | | +---------+ | | | VRF20 +--------+ VRF20 | | | | RD 0:20 | | | | RD 0:20 | | | +---------+ | | +---------+ | +-------------+ +-------------+ In this situation, the VPN routes from R1's VRF10 should be imported to R2's VRF10 and the VPN routes from R2's VRF10 should be imported to R2's VRF20. However, the current implementation of ACCEPT_OWN will always reject routes if the RD of VPN routes are matched with the RD of VRF. Similar issues will happen in local VRF2VRF route leaks. In such cases, the route reaked from VRF10 should be imported to VRF20. However, the current implementation of ACCEPT_OWN will not permit them. +- R1 ---------------------+ | +------------+ | | +----v----+ +----v----+ | | | VRF10 | | VRF20 | | | | RD 0:10 | | RD 0:10 | | | +---------+ +---------+ | +--------------------------+ So, this commit add additional condition in RD match. If the route doesn't have ACCEPT_OWN extended community, source VRF check will be skipped. [RFC7611]: https://datatracker.ietf.org/doc/html/rfc7611 Signed-off-by: Ryoga Saito <ryoga.saito@linecorp.com>
2023-01-19 12:51:44 +01:00
if (CHECK_FLAG(path_vpn->flags, BGP_PATH_ACCEPT_OWN) && prd &&
memcmp(&prd->val, &to_bgp->vpn_policy[afi].tovpn_rd.val,
ECOMMUNITY_SIZE) == 0) {
if (debug)
zlog_debug(
bgpd: support for as notation format for route distinguisher RD may be built based on an AS number. Like for the AS, the RD may use the AS notation. The two below examples can illustrate: RD 1.1:20 stands for an AS4B:NN RD with AS4B=65536 in dot format. RD 0.1:20 stands for an AS2B:NNNN RD with AS2B=0.1 in dot+ format. This commit adds the asnotation mode to prefix_rd2str() API so as to pick up the relevant display. Two new printfrr extensions are available to display the RD with the two above display methods. - The pRDD extension stands for dot asnotation format - The pRDE extension stands for dot+ asnotation format. - The pRD extension has been renamed to pRDP extension The code is changed each time '%pRD' printf extension is called. Possibly, the asnotation may change the output, then a macro defines the asnotation mode to use. A side effect of forging the mode to use is that the string could not be concatenated with other strings in vty_out and snprintfrr. Those functions have been called multiple times. When zlog_debug needs to display the RD with some other string, the prefix_rd2str() old API is used instead of the printf extension. Some code has been kept untouched: - code related to running-config. Actually, wherever an RD is displayed, its configured name should be dumped. - bgp rfapi code - bgp evpn multihoming code (partially done), since the logic is missing to get the asnotation of 'struct bgp_evpn_es'. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-22 09:57:10 +01:00
"%s: skipping import, match RD (%s) of src VRF (%s) and the prefix (%pFX)",
__func__, rd_buf, to_bgp->name_pretty, p);
return;
}
if (debug)
bgpd: support for as notation format for route distinguisher RD may be built based on an AS number. Like for the AS, the RD may use the AS notation. The two below examples can illustrate: RD 1.1:20 stands for an AS4B:NN RD with AS4B=65536 in dot format. RD 0.1:20 stands for an AS2B:NNNN RD with AS2B=0.1 in dot+ format. This commit adds the asnotation mode to prefix_rd2str() API so as to pick up the relevant display. Two new printfrr extensions are available to display the RD with the two above display methods. - The pRDD extension stands for dot asnotation format - The pRDE extension stands for dot+ asnotation format. - The pRD extension has been renamed to pRDP extension The code is changed each time '%pRD' printf extension is called. Possibly, the asnotation may change the output, then a macro defines the asnotation mode to use. A side effect of forging the mode to use is that the string could not be concatenated with other strings in vty_out and snprintfrr. Those functions have been called multiple times. When zlog_debug needs to display the RD with some other string, the prefix_rd2str() old API is used instead of the printf extension. Some code has been kept untouched: - code related to running-config. Actually, wherever an RD is displayed, its configured name should be dumped. - bgp rfapi code - bgp evpn multihoming code (partially done), since the logic is missing to get the asnotation of 'struct bgp_evpn_es'. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-22 09:57:10 +01:00
zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf,
p, to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
struct ecommunity *old_ecom;
struct ecommunity *new_ecom;
/* If doing VRF-to-VRF leaking, strip RTs. */
old_ecom = bgp_attr_get_ecommunity(&static_attr);
if (old_ecom && CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
new_ecom = ecommunity_dup(old_ecom);
ecommunity_strip_rts(new_ecom);
bgp_attr_set_ecommunity(&static_attr, new_ecom);
if (new_ecom->size == 0) {
ecommunity_free(&new_ecom);
bgp_attr_set_ecommunity(&static_attr, NULL);
}
if (!old_ecom->refcnt)
ecommunity_free(&old_ecom);
}
community_strip_accept_own(&static_attr);
/*
* Nexthop: stash and clear
*
* Nexthop is valid in context of VPN core, but not in destination vrf.
* Stash it for later label resolution by vrf ingress path and then
* overwrite with 0, i.e., "me", for the sake of vrf advertisement.
*/
uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len);
memset(&nexthop_orig, 0, sizeof(nexthop_orig));
nexthop_orig.family = nhfamily;
/* If the path has accept-own community and the source VRF
* is valid, reset next-hop to self, to allow importing own
* routes between different VRFs on the same node.
* Set the nh ifindex to VRF's interface, not the real interface.
* Let the kernel to decide with double lookup the real next-hop
* interface when installing the route.
*/
if (src_bgp) {
subgroup_announce_reset_nhop(nhfamily, &static_attr);
ifp = if_get_vrf_loopback(src_vrf->vrf_id);
if (ifp)
static_attr.nh_ifindex = ifp->ifindex;
}
switch (nhfamily) {
case AF_INET:
/* save */
nexthop_orig.u.prefix4 = path_vpn->attr->mp_nexthop_global_in;
nexthop_orig.prefixlen = IPV4_MAX_BITLEN;
if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.nexthop.s_addr =
nexthop_orig.u.prefix4.s_addr;
static_attr.mp_nexthop_global_in =
path_vpn->attr->mp_nexthop_global_in;
static_attr.mp_nexthop_len =
path_vpn->attr->mp_nexthop_len;
}
static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
break;
case AF_INET6:
/* save */
nexthop_orig.u.prefix6 = path_vpn->attr->mp_nexthop_global;
nexthop_orig.prefixlen = IPV6_MAX_BITLEN;
if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
}
break;
}
/*
* route map handling
*/
if (to_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
struct bgp_path_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
info.peer = to_bgp->peer_self;
info.attr = &static_attr;
info.extra = path_vpn->extra; /* Used for source-vrf filter */
ret = route_map_apply(to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN],
p, &info);
if (RMAP_DENYMATCH == ret) {
bgp_attr_flush(&static_attr); /* free any added parts */
if (debug)
zlog_debug(
"%s: vrf %s vpn-policy route map \"%s\" says DENY, returning",
__func__, to_bgp->name_pretty,
to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
->name);
return;
}
/*
* if route-map changed nexthop, don't nexthop-self on output
*/
if (!CHECK_FLAG(static_attr.rmap_change_flags,
BATTR_RMAP_NEXTHOP_UNCHANGED))
nexthop_self_flag = 0;
}
new_attr = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr);
bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
/*
* ensure labels are copied
*
* However, there is a special case: if the route originated in
* another local VRF (as opposed to arriving via VPN), then the
* nexthop is reached by hairpinning through this router (me)
* using IP forwarding only (no LSP). Therefore, the route
* imported to the VRF should not have labels attached. Note
* that nexthop tracking is also involved: eliminating the
* labels for these routes enables the non-labeled nexthops
* from the originating VRF to be considered valid for this route.
*/
if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
/* work back to original route */
bgpd: VRF-Lite fix best path selection Description: Incorrect behavior during best path selection for the imported routes. Imported routes are always treated as eBGP routes. Change is intended for fixing the issues related to bgp best path selection for leaked routes: - FRR does ecmp for the imported routes, even without any ecmp related config. If the same prefix is imported from two different VRFs, then we configure the route with ecmp even without any ecmp related config. - Locally imported routes are preferred over imported eBGP routes. If there is a local route and eBGP learned route for the same prefix, if we import both the routes, imported local route is selected as best path. - Same route is imported from multiple tenant VRFs, both imported routes point to the same VRF in nexthop. - When the same route with same nexthop in two different VRFs is imported from those two VRFs, route is not installed as ecmp, even though we had ecmp config. - During best path selection, while comparing the paths for imported routes, we should correctly refer to the original route i.e. the ultimate path. - When the same route is imported from multiple VRF, use the correct VRF while installing in the FIB. - When same route is imported from two different tenant VRFs, while comparing bgp path info as part of bgp best path selection, we should ideally also compare corresponding VRFs. See-also: https://github.com/FRRouting/frr/files/7169555/FRR.and.Cisco.VRF-Lite.Behaviour.pdf Co-authored-by: Santosh P K <sapk@vmware.com> Co-authored-by: Kantesh Mundaragi <kmundaragi@vmware.com> Signed-off-by: Iqra Siddiqui <imujeebsiddi@vmware.com>
2020-06-08 23:40:17 +02:00
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
/*
* if original route was unicast,
* then it did not arrive over vpn
*/
if (bpi_ultimate->net) {
struct bgp_table *table;
table = bgp_dest_table(bpi_ultimate->net);
if (table && (table->safi == SAFI_UNICAST))
origin_local = 1;
}
/* copy labels */
if (!origin_local && path_vpn->extra
&& path_vpn->extra->num_labels) {
num_labels = path_vpn->extra->num_labels;
if (num_labels > BGP_MAX_LABELS)
num_labels = BGP_MAX_LABELS;
pLabels = path_vpn->extra->label;
}
}
if (debug)
zlog_debug("%s: pfx %pBD: num_labels %d", __func__,
path_vpn->net, num_labels);
if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels,
num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
debug))
bgp_dest_unlock_node(bn);
}
bool vpn_leak_to_vrf_no_retain_filter_check(struct bgp *from_bgp,
struct attr *attr, afi_t afi)
{
struct ecommunity *ecom_route_target = bgp_attr_get_ecommunity(attr);
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
struct listnode *node;
const char *debugmsg;
struct bgp *to_bgp;
/* Loop over BGP instances */
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, to_bgp)) {
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug(
"%s: from vpn (%s) to vrf (%s) afi %s, skipping: %s",
__func__, from_bgp->name_pretty,
to_bgp->name_pretty, afi2str(afi),
debugmsg);
continue;
}
/* Check for intersection of route targets */
if (!ecommunity_include(
to_bgp->vpn_policy[afi]
.rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
ecom_route_target)) {
if (debug)
zlog_debug(
"%s: from vpn (%s) to vrf (%s) afi %s %s, skipping after no intersection of route targets",
__func__, from_bgp->name_pretty,
to_bgp->name_pretty, afi2str(afi),
ecommunity_str(ecom_route_target));
continue;
}
return false;
}
if (debug)
zlog_debug(
"%s: from vpn (%s) afi %s %s, no import - must be filtered",
__func__, from_bgp->name_pretty, afi2str(afi),
ecommunity_str(ecom_route_target));
return true;
}
void vpn_leak_to_vrf_update(struct bgp *from_bgp,
struct bgp_path_info *path_vpn,
struct prefix_rd *prd)
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (debug)
zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn);
/* Loop over VRFs */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
if (!path_vpn->extra || !path_vpn->extra->vrfleak ||
path_vpn->extra->vrfleak->bgp_orig != bgp) { /* no loop */
vpn_leak_to_vrf_update_onevrf(bgp, from_bgp, path_vpn,
prd);
}
}
}
void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn)
{
const struct prefix *p;
afi_t afi;
safi_t safi = SAFI_UNICAST;
struct bgp *bgp;
struct listnode *mnode, *mnnode;
struct bgp_dest *bn;
struct bgp_path_info *bpi;
const char *debugmsg;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (debug)
zlog_debug("%s: entry: p=%pBD, type=%d, sub_type=%d", __func__,
path_vpn->net, path_vpn->type, path_vpn->sub_type);
if (debug)
zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn);
if (!path_vpn->net) {
#ifdef ENABLE_BGP_VNC
/* BGP_ROUTE_RFP routes do not have path_vpn->net set (yet) */
if (path_vpn->type == ZEBRA_ROUTE_BGP
&& path_vpn->sub_type == BGP_ROUTE_RFP) {
return;
}
#endif
if (debug)
zlog_debug(
"%s: path_vpn->net unexpectedly NULL, no prefix, bailing",
__func__);
return;
}
p = bgp_dest_get_prefix(path_vpn->net);
afi = family2afi(p->family);
/* Loop over VRFs */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: from %s, skipping: %s",
__func__, bgp->name_pretty,
debugmsg);
continue;
}
/* Check for intersection of route targets */
if (!ecommunity_include(
bgp->vpn_policy[afi]
.rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
bgp_attr_get_ecommunity(path_vpn->attr))) {
continue;
}
if (debug)
zlog_debug("%s: withdrawing from vrf %s", __func__,
bgp->name_pretty);
bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, NULL);
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
(struct bgp_path_info *)bpi->extra->vrfleak->parent ==
path_vpn) {
break;
}
}
if (bpi) {
if (debug)
zlog_debug("%s: deleting bpi %p", __func__,
bpi);
bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(bgp, bn, afi, safi);
}
bgp_dest_unlock_node(bn);
}
}
void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
{
struct bgp_dest *bn;
struct bgp_path_info *bpi;
safi_t safi = SAFI_UNICAST;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (debug)
zlog_debug("%s: entry", __func__);
/*
* Walk vrf table, delete bpi with bgp_orig in a different vrf
*/
for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn;
bn = bgp_route_next(bn)) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->bgp_orig != to_bgp &&
bpi->extra->vrfleak->parent &&
is_pi_family_vpn(bpi->extra->vrfleak->parent)) {
/* delete route */
bgp_aggregate_decrement(to_bgp,
bgp_dest_get_prefix(bn),
bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(to_bgp, bn, afi, safi);
}
}
}
}
void vpn_leak_no_retain(struct bgp *to_bgp, struct bgp *vpn_from, afi_t afi)
{
struct bgp_dest *pdest;
safi_t safi = SAFI_MPLS_VPN;
assert(vpn_from);
/*
* Walk vpn table
*/
for (pdest = bgp_table_top(vpn_from->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
struct bgp_dest *bn;
struct bgp_path_info *bpi;
/* This is the per-RD table of prefixes */
table = bgp_dest_get_bgp_table_info(pdest);
if (!table)
continue;
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->bgp_orig == to_bgp)
continue;
if (bpi->sub_type != BGP_ROUTE_NORMAL)
continue;
if (!vpn_leak_to_vrf_no_retain_filter_check(
vpn_from, bpi->attr, afi))
/* do not filter */
continue;
bgp_unlink_nexthop(bpi);
bgp_rib_remove(bn, bpi, bpi->peer, afi, safi);
}
}
}
}
void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
afi_t afi)
{
struct bgp_dest *pdest;
safi_t safi = SAFI_MPLS_VPN;
assert(vpn_from);
/*
* Walk vpn table
*/
for (pdest = bgp_table_top(vpn_from->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
struct bgp_dest *bn;
struct bgp_path_info *bpi;
/* This is the per-RD table of prefixes */
table = bgp_dest_get_bgp_table_info(pdest);
if (!table)
continue;
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->bgp_orig == to_bgp)
continue;
vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from,
bpi, NULL);
}
}
}
}
/*
* This function is called for definition/deletion/change to a route-map
*/
static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
afi_t afi;
struct route_map *rmap;
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
&& bgp->inst_type != BGP_INSTANCE_TYPE_VRF) {
return;
}
rmap = route_map_lookup_by_name(rmap_name); /* NULL if deleted */
for (afi = 0; afi < AFI_MAX; ++afi) {
if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]
&& !strcmp(rmap_name,
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_TOVPN])) {
if (debug)
zlog_debug(
"%s: rmap \"%s\" matches vrf-policy tovpn for as %d afi %s",
__func__, rmap_name, bgp->as,
afi2str(afi));
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
if (debug)
zlog_debug("%s: after vpn_leak_prechange",
__func__);
/* in case of definition/deletion */
bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] =
rmap;
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
if (debug)
zlog_debug("%s: after vpn_leak_postchange",
__func__);
}
if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]
&& !strcmp(rmap_name,
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN])) {
if (debug) {
zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s",
__func__, rmap_name, bgp->as,
afi2str(afi));
}
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
/* in case of definition/deletion */
bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
rmap;
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
}
}
}
/* This API is used during router-id change, reflect VPNs
* auto RD and RT values and readvertise routes to VPN table.
*/
void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
bool is_config)
{
afi_t afi;
int debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)
| BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
char *vname;
const char *export_name;
char buf[RD_ADDRSTRLEN];
struct bgp *bgp_import;
struct listnode *node;
struct ecommunity *ecom;
enum vpn_policy_direction idir, edir;
/*
* Router-id change that is not explicitly configured
* (a change from zebra, frr restart for example)
* should not replace a configured vpn RD/RT.
*/
if (!is_config) {
if (debug)
zlog_debug("%s: skipping non explicit router-id change",
__func__);
return;
}
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
&& bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
return;
export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME;
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
for (afi = 0; afi < AFI_MAX; ++afi) {
if (!vpn_leak_to_vpn_active(bgp, afi, NULL, false))
continue;
if (withdraw) {
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
afi, bgp_get_default(), bgp);
if (debug)
zlog_debug("%s: %s after to_vpn vpn_leak_prechange",
__func__, export_name);
/* Remove import RT from VRFs */
ecom = bgp->vpn_policy[afi].rtlist[edir];
for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].
export_vrf, node, vname)) {
if (strcmp(vname, VRF_DEFAULT_NAME) == 0)
bgp_import = bgp_get_default();
else
bgp_import = bgp_lookup_by_name(vname);
if (!bgp_import)
continue;
ecommunity_del_val(
bgp_import->vpn_policy[afi]
.rtlist[idir],
(struct ecommunity_val *)ecom->val);
}
} else {
/* New router-id derive auto RD and RT and export
* to VPN
*/
form_auto_rd(bgp->router_id, bgp->vrf_rd_id,
&bgp->vrf_prd_auto);
bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto;
prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
bgpd: support for as notation format for route distinguisher RD may be built based on an AS number. Like for the AS, the RD may use the AS notation. The two below examples can illustrate: RD 1.1:20 stands for an AS4B:NN RD with AS4B=65536 in dot format. RD 0.1:20 stands for an AS2B:NNNN RD with AS2B=0.1 in dot+ format. This commit adds the asnotation mode to prefix_rd2str() API so as to pick up the relevant display. Two new printfrr extensions are available to display the RD with the two above display methods. - The pRDD extension stands for dot asnotation format - The pRDE extension stands for dot+ asnotation format. - The pRD extension has been renamed to pRDP extension The code is changed each time '%pRD' printf extension is called. Possibly, the asnotation may change the output, then a macro defines the asnotation mode to use. A side effect of forging the mode to use is that the string could not be concatenated with other strings in vty_out and snprintfrr. Those functions have been called multiple times. When zlog_debug needs to display the RD with some other string, the prefix_rd2str() old API is used instead of the printf extension. Some code has been kept untouched: - code related to running-config. Actually, wherever an RD is displayed, its configured name should be dumped. - bgp rfapi code - bgp evpn multihoming code (partially done), since the logic is missing to get the asnotation of 'struct bgp_evpn_es'. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-22 09:57:10 +01:00
sizeof(buf), bgp->asnotation);
/* free up pre-existing memory if any and allocate
* the ecommunity attribute with new RD/RT
*/
if (bgp->vpn_policy[afi].rtlist[edir])
ecommunity_free(
&bgp->vpn_policy[afi].rtlist[edir]);
bgp->vpn_policy[afi].rtlist[edir] = ecommunity_str2com(
buf, ECOMMUNITY_ROUTE_TARGET, 0);
/* Update import_vrf rt_list */
ecom = bgp->vpn_policy[afi].rtlist[edir];
for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].
export_vrf, node, vname)) {
if (strcmp(vname, VRF_DEFAULT_NAME) == 0)
bgp_import = bgp_get_default();
else
bgp_import = bgp_lookup_by_name(vname);
if (!bgp_import)
continue;
if (bgp_import->vpn_policy[afi].rtlist[idir])
bgp_import->vpn_policy[afi].rtlist[idir]
= ecommunity_merge(
bgp_import->vpn_policy[afi]
.rtlist[idir], ecom);
else
bgp_import->vpn_policy[afi].rtlist[idir]
= ecommunity_dup(ecom);
}
/* Update routes to VPN */
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
afi, bgp_get_default(),
bgp);
if (debug)
zlog_debug("%s: %s after to_vpn vpn_leak_postchange",
__func__, export_name);
}
}
}
void vpn_policy_routemap_event(const char *rmap_name)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
struct listnode *mnode, *mnnode;
struct bgp *bgp;
if (debug)
zlog_debug("%s: entry", __func__);
if (bm->bgp == NULL) /* may be called during cleanup */
return;
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
vpn_policy_routemap_update(bgp, rmap_name);
}
void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi, safi_t safi)
{
const char *export_name;
enum vpn_policy_direction idir, edir;
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
char *vname, *tmp_name;
char buf[RD_ADDRSTRLEN];
struct ecommunity *ecom;
bool first_export = false;
int debug;
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
struct listnode *node;
bool is_inst_match = false;
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
/*
* Cross-ref both VRFs. Also, note if this is the first time
* any VRF is importing from "import_vrf".
*/
vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
: XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
/* Check the import_vrf list of destination vrf for the source vrf name,
* insert otherwise.
*/
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf,
node, tmp_name)) {
if (strcmp(vname, tmp_name) == 0) {
is_inst_match = true;
break;
}
}
if (!is_inst_match)
listnode_add(to_bgp->vpn_policy[afi].import_vrf,
vname);
else
XFREE(MTYPE_TMP, vname);
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
/* Check if the source vrf already exports to any vrf,
* first time export requires to setup auto derived RD/RT values.
* Add the destination vrf name to export vrf list if it is
* not present.
*/
is_inst_match = false;
vname = XSTRDUP(MTYPE_TMP, export_name);
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) {
first_export = true;
} else {
for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf,
node, tmp_name)) {
if (strcmp(vname, tmp_name) == 0) {
is_inst_match = true;
break;
}
}
}
if (!is_inst_match)
listnode_add(from_bgp->vpn_policy[afi].export_vrf,
vname);
else
XFREE(MTYPE_TMP, vname);
/* Update import RT for current VRF using export RT of the VRF we're
* importing from. First though, make sure "import_vrf" has that
* set.
*/
if (first_export) {
form_auto_rd(from_bgp->router_id, from_bgp->vrf_rd_id,
&from_bgp->vrf_prd_auto);
from_bgp->vpn_policy[afi].tovpn_rd = from_bgp->vrf_prd_auto;
SET_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
bgpd: support for as notation format for route distinguisher RD may be built based on an AS number. Like for the AS, the RD may use the AS notation. The two below examples can illustrate: RD 1.1:20 stands for an AS4B:NN RD with AS4B=65536 in dot format. RD 0.1:20 stands for an AS2B:NNNN RD with AS2B=0.1 in dot+ format. This commit adds the asnotation mode to prefix_rd2str() API so as to pick up the relevant display. Two new printfrr extensions are available to display the RD with the two above display methods. - The pRDD extension stands for dot asnotation format - The pRDE extension stands for dot+ asnotation format. - The pRD extension has been renamed to pRDP extension The code is changed each time '%pRD' printf extension is called. Possibly, the asnotation may change the output, then a macro defines the asnotation mode to use. A side effect of forging the mode to use is that the string could not be concatenated with other strings in vty_out and snprintfrr. Those functions have been called multiple times. When zlog_debug needs to display the RD with some other string, the prefix_rd2str() old API is used instead of the printf extension. Some code has been kept untouched: - code related to running-config. Actually, wherever an RD is displayed, its configured name should be dumped. - bgp rfapi code - bgp evpn multihoming code (partially done), since the logic is missing to get the asnotation of 'struct bgp_evpn_es'. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-22 09:57:10 +01:00
prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd, buf,
sizeof(buf), from_bgp->asnotation);
from_bgp->vpn_policy[afi].rtlist[edir] =
ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
SET_FLAG(from_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_EXPORT);
from_bgp->vpn_policy[afi].tovpn_label =
BGP_PREVENT_VRF_2_VRF_LEAK;
}
ecom = from_bgp->vpn_policy[afi].rtlist[edir];
if (to_bgp->vpn_policy[afi].rtlist[idir])
to_bgp->vpn_policy[afi].rtlist[idir] =
ecommunity_merge(to_bgp->vpn_policy[afi]
.rtlist[idir], ecom);
else
to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom);
SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT);
if (debug) {
const char *from_name;
char *ecom1, *ecom2;
from_name = from_bgp->name ? from_bgp->name :
VRF_DEFAULT_NAME;
ecom1 = ecommunity_ecom2str(
to_bgp->vpn_policy[afi].rtlist[idir],
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
ecom2 = ecommunity_ecom2str(
to_bgp->vpn_policy[afi].rtlist[edir],
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug(
"%s from %s to %s first_export %u import-rt %s export-rt %s",
__func__, from_name, export_name, first_export, ecom1,
ecom2);
ecommunity_strfree(&ecom1);
ecommunity_strfree(&ecom2);
}
/* Does "import_vrf" first need to export its routes or that
* is already done and we just need to import those routes
* from the global table?
*/
if (first_export)
vpn_leak_postchange(edir, afi, bgp_get_default(), from_bgp);
else
vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
}
void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi, safi_t safi)
{
const char *export_name, *tmp_name;
enum vpn_policy_direction idir, edir;
char *vname;
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
struct ecommunity *ecom = NULL;
struct listnode *node;
int debug;
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
/* Were we importing from "import_vrf"? */
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node,
vname)) {
if (strcmp(vname, tmp_name) == 0)
break;
}
/*
* We do not check in the cli if the passed in bgp
* instance is actually imported into us before
* we call this function. As such if we do not
* find this in the import_vrf list than
* we just need to return safely.
*/
if (!vname)
return;
if (debug)
zlog_debug("%s from %s to %s", __func__, tmp_name, export_name);
/* Remove "import_vrf" from our import list. */
listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname);
XFREE(MTYPE_TMP, vname);
/* Remove routes imported from "import_vrf". */
/* TODO: In the current logic, we have to first remove all
* imported routes and then (if needed) import back routes
*/
vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp);
if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
if (!to_bgp->vpn_policy[afi].rmap[idir])
UNSET_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT);
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
if (to_bgp->vpn_policy[afi].rtlist[idir])
ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
} else {
ecom = from_bgp->vpn_policy[afi].rtlist[edir];
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
if (ecom)
ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir],
(struct ecommunity_val *)ecom->val);
vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
}
/*
* What?
* So SA is assuming that since the ALL_LIST_ELEMENTS_RO
* below is checking for NULL that export_vrf can be
* NULL, consequently it is complaining( like a cabbage )
* that we could dereference and crash in the listcount(..)
* check below.
* So make it happy, under protest, with liberty and justice
* for all.
*/
assert(from_bgp->vpn_policy[afi].export_vrf);
/* Remove us from "import_vrf's" export list. If no other VRF
* is importing from "import_vrf", cleanup appropriately.
*/
for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf,
node, vname)) {
if (strcmp(vname, export_name) == 0)
break;
}
/*
* If we have gotten to this point then the vname must
* exist. If not, we are in a world of trouble and
* have slag sitting around.
*
* import_vrf and export_vrf must match in having
* the in/out names as appropriate.
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
* export_vrf list could have been cleaned up
* as part of no router bgp source instnace.
*/
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
if (!vname)
return;
listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname);
XFREE(MTYPE_TMP, vname);
if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) {
vpn_leak_prechange(edir, afi, bgp_get_default(), from_bgp);
ecommunity_free(&from_bgp->vpn_policy[afi].rtlist[edir]);
UNSET_FLAG(from_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_EXPORT);
memset(&from_bgp->vpn_policy[afi].tovpn_rd, 0,
sizeof(struct prefix_rd));
UNSET_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
from_bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
}
}
2002-12-13 21:15:29 +01:00
/* For testing purpose, static route of MPLS-VPN. */
DEFUN (vpnv4_network,
vpnv4_network_cmd,
"network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)",
2002-12-13 21:15:29 +01:00
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
2002-12-13 21:15:29 +01:00
"Specify Route Distinguisher\n"
"VPN Route Distinguisher\n"
"VPN NLRI label (tag)\n"
"VPN NLRI label (tag)\n"
"Label value\n")
2002-12-13 21:15:29 +01:00
{
int idx_ipv4_prefixlen = 1;
int idx_ext_community = 3;
int idx_label = 5;
return bgp_static_set(vty, false, argv[idx_ipv4_prefixlen]->arg,
argv[idx_ext_community]->arg,
argv[idx_label]->arg, AFI_IP, SAFI_MPLS_VPN, NULL,
0, 0, 0, NULL, NULL, NULL, NULL);
}
DEFUN (vpnv4_network_route_map,
vpnv4_network_route_map_cmd,
"network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) route-map RMAP_NAME",
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
"Specify Route Distinguisher\n"
"VPN Route Distinguisher\n"
"VPN NLRI label (tag)\n"
"VPN NLRI label (tag)\n"
"Label value\n"
"route map\n"
"route map name\n")
{
int idx_ipv4_prefixlen = 1;
int idx_ext_community = 3;
int idx_label = 5;
int idx_rmap = 7;
return bgp_static_set(vty, false, argv[idx_ipv4_prefixlen]->arg,
argv[idx_ext_community]->arg, argv[idx_label]->arg,
AFI_IP, SAFI_MPLS_VPN, argv[idx_rmap]->arg, 0, 0,
0, NULL, NULL, NULL, NULL);
2002-12-13 21:15:29 +01:00
}
/* For testing purpose, static route of MPLS-VPN. */
DEFUN (no_vpnv4_network,
no_vpnv4_network_cmd,
"no network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)",
2002-12-13 21:15:29 +01:00
NO_STR
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
2002-12-13 21:15:29 +01:00
"Specify Route Distinguisher\n"
"VPN Route Distinguisher\n"
"VPN NLRI label (tag)\n"
"VPN NLRI label (tag)\n"
"Label value\n")
2002-12-13 21:15:29 +01:00
{
int idx_ipv4_prefixlen = 2;
int idx_ext_community = 4;
int idx_label = 6;
return bgp_static_set(vty, true, argv[idx_ipv4_prefixlen]->arg,
argv[idx_ext_community]->arg,
argv[idx_label]->arg, AFI_IP, SAFI_MPLS_VPN, NULL,
0, 0, 0, NULL, NULL, NULL, NULL);
2002-12-13 21:15:29 +01:00
}
DEFUN (vpnv6_network,
vpnv6_network_cmd,
"network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) [route-map RMAP_NAME]",
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
"Specify Route Distinguisher\n"
"VPN Route Distinguisher\n"
"VPN NLRI label (tag)\n"
"VPN NLRI label (tag)\n"
"Label value\n"
"route map\n"
"route map name\n")
{
int idx_ipv6_prefix = 1;
int idx_ext_community = 3;
int idx_label = 5;
int idx_rmap = 7;
*: fix a bunch of segfaults detected by a CLI fuzzer This patch fixes the following segfaults: zebra aborted: vtysh -c "show ipv6 mroute" zebra aborted: vtysh -c "configure terminal" -c "debug zebra kernel msgdump" zebra aborted: vtysh -c "configure terminal" -c "interface eth99" -c "link-params" -c "no packet-loss" zebra aborted: vtysh -c "configure terminal" -c "interface eth99" -c "link-params" -c "no metric" zebra aborted: vtysh -c "configure terminal" -c "interface eth99" -c "link-params" -c "no ava-bw" zebra aborted: vtysh -c "configure terminal" -c "interface eth99" -c "link-params" -c "no res-bw" zebra aborted: vtysh -c "configure terminal" -c "interface eth99" -c "link-params" -c "no use-bw" ospfd aborted: vtysh -c "configure terminal" -c "router ospf" -c "area 1.1.1.1 nssa" ospfd aborted: vtysh -c "configure terminal" -c "router ospf" -c "area 4294967295 nssa" pimd aborted: vtysh -c "show ip msdp sa 1.1.1.1" pimd aborted: vtysh -c "configure terminal" -c "ip ssmpingd" pimd aborted: vtysh -c "configure terminal" -c "no ip ssmpingd" pimd aborted: vtysh -c "configure terminal" -c "no ip msdp mesh-group WORD source" pimd aborted: vtysh -c "configure terminal" -c "interface eth99" -c "ip pim hello 180" bgpd aborted: vtysh -c "show bgp l2vpn evpn rd 1:1" bgpd aborted: vtysh -c "clear vnc nve un *" bgpd aborted: vtysh -c "clear vnc nve un 1.1.1.1" bgpd aborted: vtysh -c "clear vnc nve un 2001:db8::1" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 1.1.1.1 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 1.1.1.1 cost 255 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 1.1.1.1 cost 255" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 1.1.1.1" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 2001:db8::1 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 2001:db8::1 cost 255 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 2001:db8::1 cost 255" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 1.1.1.1 un 2001:db8::1" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 1.1.1.1 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 1.1.1.1 cost 255 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 1.1.1.1 cost 255" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 1.1.1.1" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 2001:db8::1 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 2001:db8::1 cost 255 lifetime 4294967295" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 2001:db8::1 cost 255" bgpd aborted: vtysh -c "add vnc mac 11:11:11:11:11:11 virtual-network-identifier 4294967295 vn 2001:db8::1 un 2001:db8::1" bgpd aborted: vtysh -c "configure terminal" -c "router bgp 1" -c "no vnc export bgp ipv4 prefix-list NAME" bgpd aborted: vtysh -c "configure terminal" -c "router bgp 1" -c "no vnc export bgp ipv6 prefix-list NAME" bgpd aborted: vtysh -c "configure terminal" -c "router bgp 1" -c "no vnc export bgp route-map NAME" bgpd aborted: vtysh -c "configure terminal" -c "router bgp 1" -c "no vnc export zebra ipv4 prefix-list NAME" bgpd aborted: vtysh -c "configure terminal" -c "router bgp 1" -c "no vnc export zebra ipv6 prefix-list NAME" bgpd aborted: vtysh -c "configure terminal" -c "router bgp 1" -c "no vnc export zebra route-map NAME" bgpd aborted: vtysh -c "configure terminal" -c "route-map RMAP permit 1" -c "no set ipv6 vpn next-hop" bgpd aborted: vtysh -c "configure terminal" -c "route-map RMAP permit 1" -c "set vpnv4 next-hop" bgpd aborted: vtysh -c "configure terminal" -c "route-map RMAP permit 1" -c "set vpnv6 next-hop" bgpd aborted: vtysh -c "configure terminal" -c "router bgp" -c "address-family ipv6 vpn" -c "network 2001:db8::1/128 rd 1:1 tag WORD" bgpd aborted: vtysh -c "configure terminal" -c "router bgp" -c "address-family vpnv6 unicast" -c "network 2001:db8::1/128 rd 1:1 tag WORD" bgpd aborted: vtysh -c "configure terminal" -c "router bgp" -c "no neighbor WORD shutdown message MSG..." bgpd aborted: vtysh -c "configure terminal" -c "router bgp" -c "neighbor WORD shutdown message MSG..." More to come later. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2017-05-04 04:49:50 +02:00
if (argc == 8)
return bgp_static_set(vty, false, argv[idx_ipv6_prefix]->arg,
argv[idx_ext_community]->arg,
argv[idx_label]->arg, AFI_IP6,
SAFI_MPLS_VPN, argv[idx_rmap]->arg, 0, 0,
0, NULL, NULL, NULL, NULL);
else
return bgp_static_set(vty, false, argv[idx_ipv6_prefix]->arg,
argv[idx_ext_community]->arg,
argv[idx_label]->arg, AFI_IP6,
SAFI_MPLS_VPN, NULL, 0, 0, 0, NULL, NULL,
NULL, NULL);
}
/* For testing purpose, static route of MPLS-VPN. */
DEFUN (no_vpnv6_network,
no_vpnv6_network_cmd,
"no network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)",
NO_STR
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
"Specify Route Distinguisher\n"
"VPN Route Distinguisher\n"
"VPN NLRI label (tag)\n"
"VPN NLRI label (tag)\n"
"Label value\n")
{
int idx_ipv6_prefix = 2;
int idx_ext_community = 4;
int idx_label = 6;
return bgp_static_set(vty, true, argv[idx_ipv6_prefix]->arg,
argv[idx_ext_community]->arg,
argv[idx_label]->arg, AFI_IP6, SAFI_MPLS_VPN,
NULL, 0, 0, 0, NULL, NULL, NULL, NULL);
}
int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg, int tags,
bool use_json)
2002-12-13 21:15:29 +01:00
{
struct bgp *bgp;
struct bgp_table *table;
bgpd: Adopt `show bgp detail-routes` command for L3VPN outputs as well ``` unet> sh pe2 vtysh -c 'sh ip bgp ipv4 vpn detail-routes' BGP table version is 4, local router ID is 10.10.10.20, vrf id 0 Default local pref 100, local AS 65001 Route Distinguisher: 192.168.2.2:2 BGP routing table entry for 192.168.2.2:2:10.0.0.0/24, version 1 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, metric 0, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 BGP routing table entry for 192.168.2.2:2:172.16.255.1/32, version 2 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 BGP routing table entry for 192.168.2.2:2:192.168.1.0/24, version 3 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 BGP routing table entry for 192.168.2.2:2:192.168.2.0/24, version 4 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, metric 0, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 Displayed 4 routes and 4 total paths ``` Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
2022-12-20 12:01:52 +01:00
uint16_t show_flags = 0;
if (use_json)
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
2002-12-13 21:15:29 +01:00
bgp = bgp_get_default();
if (bgp == NULL) {
if (!use_json)
vty_out(vty, "No BGP process is configured\n");
else
vty_out(vty, "{}\n");
2002-12-13 21:15:29 +01:00
return CMD_WARNING;
}
table = bgp->rib[afi][SAFI_MPLS_VPN];
return bgp_show_table_rd(vty, bgp, afi, SAFI_MPLS_VPN, table, prd, type,
bgpd: Adopt `show bgp detail-routes` command for L3VPN outputs as well ``` unet> sh pe2 vtysh -c 'sh ip bgp ipv4 vpn detail-routes' BGP table version is 4, local router ID is 10.10.10.20, vrf id 0 Default local pref 100, local AS 65001 Route Distinguisher: 192.168.2.2:2 BGP routing table entry for 192.168.2.2:2:10.0.0.0/24, version 1 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, metric 0, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 BGP routing table entry for 192.168.2.2:2:172.16.255.1/32, version 2 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 BGP routing table entry for 192.168.2.2:2:192.168.1.0/24, version 3 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 BGP routing table entry for 192.168.2.2:2:192.168.2.0/24, version 4 not allocated Paths: (1 available, best #1) Not advertised to any peer 65000 192.168.2.1 from 0.0.0.0 (10.10.10.20) vrf RED(4) announce-nh-self Origin incomplete, metric 0, localpref 50, valid, sourced, local, best (First path received) Extended Community: RT:192.168.2.2:2 Originator: 10.10.10.20 Remote label: 2222 Last update: Tue Dec 20 13:01:20 2022 Displayed 4 routes and 4 total paths ``` Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
2022-12-20 12:01:52 +01:00
output_arg, show_flags);
2002-12-13 21:15:29 +01:00
}
DEFUN (show_bgp_ip_vpn_all_rd,
show_bgp_ip_vpn_all_rd_cmd,
"show bgp "BGP_AFI_CMD_STR" vpn all [rd <ASN:NN_OR_IP-ADDRESS:NN|all>] [json]",
SHOW_STR
BGP_STR
BGP_VPNVX_HELP_STR
"Display VPN NLRI specific information\n"
"Display VPN NLRI specific information\n"
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n"
JSON_STR)
{
int ret;
struct prefix_rd prd;
afi_t afi;
int idx = 0;
if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
/* Constrain search if user supplies RD && RD != "all" */
if (argv_find(argv, argc, "rd", &idx)
&& strcmp(argv[idx + 1]->arg, "all")) {
ret = str2prefix_rd(argv[idx + 1]->arg, &prd);
if (!ret) {
vty_out(vty,
"%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
return bgp_show_mpls_vpn(vty, afi, &prd,
bgp_show_type_normal, NULL, 0,
use_json(argc, argv));
} else {
return bgp_show_mpls_vpn(vty, afi, NULL,
bgp_show_type_normal, NULL, 0,
use_json(argc, argv));
}
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
ALIAS(show_bgp_ip_vpn_all_rd,
show_bgp_ip_vpn_rd_cmd,
"show bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> [json]",
SHOW_STR
BGP_STR
BGP_VPNVX_HELP_STR
"Display VPN NLRI specific information\n"
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n"
JSON_STR)
#ifdef KEEP_OLD_VPN_COMMANDS
DEFUN (show_ip_bgp_vpn_rd,
show_ip_bgp_vpn_rd_cmd,
"show ip bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all>",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_AFI_HELP_STR
BGP_AF_MODIFIER_STR
2002-12-13 21:15:29 +01:00
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n")
2002-12-13 21:15:29 +01:00
{
int idx_ext_community = argc - 1;
2002-12-13 21:15:29 +01:00
int ret;
struct prefix_rd prd;
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
if (!strcmp(argv[idx_ext_community]->arg, "all"))
return bgp_show_mpls_vpn(vty, afi, NULL,
bgp_show_type_normal, NULL, 0,
0);
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal,
NULL, 0, 0);
2002-12-13 21:15:29 +01:00
}
return CMD_SUCCESS;
}
2002-12-13 21:15:29 +01:00
DEFUN (show_ip_bgp_vpn_all,
show_ip_bgp_vpn_all_cmd,
"show [ip] bgp <vpnv4|vpnv6>",
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR)
{
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi))
return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal,
NULL, 0, 0);
return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_vpn_all_tags,
show_ip_bgp_vpn_all_tags_cmd,
"show [ip] bgp <vpnv4|vpnv6> all tags",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR
"Display information about all VPNv4/VPNV6 NLRIs\n"
2002-12-13 21:15:29 +01:00
"Display BGP tags for prefixes\n")
{
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi))
return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal,
NULL, 1, 0);
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
DEFUN (show_ip_bgp_vpn_rd_tags,
show_ip_bgp_vpn_rd_tags_cmd,
"show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> tags",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR
2002-12-13 21:15:29 +01:00
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n"
2002-12-13 21:15:29 +01:00
"Display BGP tags for prefixes\n")
{
int idx_ext_community = 5;
2002-12-13 21:15:29 +01:00
int ret;
struct prefix_rd prd;
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
if (!strcmp(argv[idx_ext_community]->arg, "all"))
return bgp_show_mpls_vpn(vty, afi, NULL,
bgp_show_type_normal, NULL, 1,
0);
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal,
NULL, 1, 0);
2002-12-13 21:15:29 +01:00
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
DEFUN (show_ip_bgp_vpn_all_neighbor_routes,
show_ip_bgp_vpn_all_neighbor_routes_cmd,
"show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D routes [json]",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR
"Display information about all VPNv4/VPNv6 NLRIs\n"
2002-12-13 21:15:29 +01:00
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Display routes learned from neighbor\n"
JSON_STR)
2002-12-13 21:15:29 +01:00
{
int idx_ipv4 = 6;
union sockunion su;
2002-12-13 21:15:29 +01:00
struct peer *peer;
int ret;
bool uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
if (ret < 0) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(json_no, "warning",
"Malformed address");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
argv[idx_ipv4]->arg);
return CMD_WARNING;
}
peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(
json_no, "warning",
"No such neighbor or address family");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty,
"%% No such neighbor or address family\n");
return CMD_WARNING;
}
return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_neighbor,
&su, 0, uj);
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
DEFUN (show_ip_bgp_vpn_rd_neighbor_routes,
show_ip_bgp_vpn_rd_neighbor_routes_cmd,
"show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D routes [json]",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR
2002-12-13 21:15:29 +01:00
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n"
2002-12-13 21:15:29 +01:00
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Display routes learned from neighbor\n"
JSON_STR)
2002-12-13 21:15:29 +01:00
{
int idx_ext_community = 5;
int idx_ipv4 = 7;
2002-12-13 21:15:29 +01:00
int ret;
union sockunion su;
2002-12-13 21:15:29 +01:00
struct peer *peer;
struct prefix_rd prd;
bool prefix_rd_all = false;
bool uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
if (!strcmp(argv[idx_ext_community]->arg, "all"))
prefix_rd_all = true;
else {
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
if (!ret) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(
json_no, "warning",
"Malformed Route Distinguisher");
vty_out(vty, "%s\n",
json_object_to_json_string(
json_no));
json_object_free(json_no);
} else
vty_out(vty,
"%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
}
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
if (ret < 0) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(json_no, "warning",
"Malformed address");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
argv[idx_ext_community]->arg);
return CMD_WARNING;
}
peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(
json_no, "warning",
"No such neighbor or address family");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty,
"%% No such neighbor or address family\n");
return CMD_WARNING;
}
if (prefix_rd_all)
return bgp_show_mpls_vpn(vty, afi, NULL,
bgp_show_type_neighbor, &su, 0,
uj);
else
return bgp_show_mpls_vpn(vty, afi, &prd,
bgp_show_type_neighbor, &su, 0,
uj);
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes,
show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd,
"show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D advertised-routes [json]",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR
"Display information about all VPNv4/VPNv6 NLRIs\n"
2002-12-13 21:15:29 +01:00
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Display the routes advertised to a BGP neighbor\n"
JSON_STR)
2002-12-13 21:15:29 +01:00
{
int idx_ipv4 = 6;
2002-12-13 21:15:29 +01:00
int ret;
struct peer *peer;
union sockunion su;
bool uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
if (ret < 0) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(json_no, "warning",
"Malformed address");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
argv[idx_ipv4]->arg);
return CMD_WARNING;
}
peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(
json_no, "warning",
"No such neighbor or address family");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty,
"%% No such neighbor or address family\n");
return CMD_WARNING;
}
return show_adj_route_vpn(vty, peer, NULL, AFI_IP,
SAFI_MPLS_VPN, uj);
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes,
show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd,
"show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D advertised-routes [json]",
2002-12-13 21:15:29 +01:00
SHOW_STR
IP_STR
BGP_STR
BGP_VPNVX_HELP_STR
2002-12-13 21:15:29 +01:00
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n"
2002-12-13 21:15:29 +01:00
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Display the routes advertised to a BGP neighbor\n"
JSON_STR)
2002-12-13 21:15:29 +01:00
{
int idx_ext_community = 5;
int idx_ipv4 = 7;
2002-12-13 21:15:29 +01:00
int ret;
struct peer *peer;
struct prefix_rd prd;
union sockunion su;
bool uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
if (ret < 0) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(json_no, "warning",
"Malformed address");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
argv[idx_ext_community]->arg);
return CMD_WARNING;
}
peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(
json_no, "warning",
"No such neighbor or address family");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty,
"%% No such neighbor or address family\n");
return CMD_WARNING;
}
if (!strcmp(argv[idx_ext_community]->arg, "all"))
return show_adj_route_vpn(vty, peer, NULL, AFI_IP,
SAFI_MPLS_VPN, uj);
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
if (!ret) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
json_object_string_add(
json_no, "warning",
"Malformed Route Distinguisher");
vty_out(vty, "%s\n",
json_object_to_json_string(json_no));
json_object_free(json_no);
} else
vty_out(vty,
"%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
return show_adj_route_vpn(vty, peer, &prd, AFI_IP,
SAFI_MPLS_VPN, uj);
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
#endif /* KEEP_OLD_VPN_COMMANDS */
2002-12-13 21:15:29 +01:00
void bgp_mplsvpn_init(void)
2002-12-13 21:15:29 +01:00
{
install_element(BGP_VPNV4_NODE, &vpnv4_network_cmd);
install_element(BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd);
2002-12-13 21:15:29 +01:00
install_element(BGP_VPNV4_NODE, &no_vpnv4_network_cmd);
install_element(BGP_VPNV6_NODE, &vpnv6_network_cmd);
install_element(BGP_VPNV6_NODE, &no_vpnv6_network_cmd);
install_element(VIEW_NODE, &show_bgp_ip_vpn_all_rd_cmd);
install_element(VIEW_NODE, &show_bgp_ip_vpn_rd_cmd);
#ifdef KEEP_OLD_VPN_COMMANDS
install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_cmd);
install_element(VIEW_NODE, &show_ip_bgp_vpn_all_cmd);
install_element(VIEW_NODE, &show_ip_bgp_vpn_all_tags_cmd);
install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_tags_cmd);
install_element(VIEW_NODE, &show_ip_bgp_vpn_all_neighbor_routes_cmd);
install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_neighbor_routes_cmd);
install_element(VIEW_NODE,
&show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd);
install_element(VIEW_NODE,
&show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd);
#endif /* KEEP_OLD_VPN_COMMANDS */
2002-12-13 21:15:29 +01:00
}
vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey)
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
afi_t afi = AFI_IP;
if (eckey->unit_size == IPV6_ECOMMUNITY_SIZE)
afi = AFI_IP6;
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
struct ecommunity *ec;
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
ec = bgp->vpn_policy[afi].import_redirect_rtlist;
if (ec && eckey->unit_size != ec->unit_size)
continue;
if (ecommunity_include(ec, eckey))
return bgp->vrf_id;
}
return VRF_UNKNOWN;
}
/*
* The purpose of this function is to process leaks that were deferred
* from earlier per-vrf configuration due to not-yet-existing default
* vrf, in other words, configuration such as:
*
* router bgp MMM vrf FOO
* address-family ipv4 unicast
* rd vpn export 1:1
* exit-address-family
*
* router bgp NNN
* ...
*
* This function gets called when the default instance ("router bgp NNN")
* is created.
*/
void vpn_leak_postchange_all(void)
{
struct listnode *next;
struct bgp *bgp;
struct bgp *bgp_default = bgp_get_default();
assert(bgp_default);
/* First, do any exporting from VRFs to the single VPN RIB */
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
vpn_leak_postchange(
BGP_VPN_POLICY_DIR_TOVPN,
AFI_IP,
bgp_default,
bgp);
vpn_leak_postchange(
BGP_VPN_POLICY_DIR_TOVPN,
AFI_IP6,
bgp_default,
bgp);
}
/* Now, do any importing to VRFs from the single VPN RIB */
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
vpn_leak_postchange(
BGP_VPN_POLICY_DIR_FROMVPN,
AFI_IP,
bgp_default,
bgp);
vpn_leak_postchange(
BGP_VPN_POLICY_DIR_FROMVPN,
AFI_IP6,
bgp_default,
bgp);
}
}
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
/* When a bgp vrf instance is unconfigured, remove its routes
* from the VPN table and this vrf could be importing routes from other
* bgp vrf instnaces, unimport them.
* VRF X and VRF Y are exporting routes to each other.
* When VRF X is deleted, unimport its routes from all target vrfs,
* also VRF Y should unimport its routes from VRF X table.
* This will ensure VPN table is cleaned up appropriately.
*/
void bgp_vpn_leak_unimport(struct bgp *from_bgp)
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
{
struct bgp *bgp_default = bgp_get_default();
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
struct bgp *to_bgp;
const char *tmp_name;
char *vname;
struct listnode *node, *next;
safi_t safi = SAFI_UNICAST;
afi_t afi;
bool is_vrf_leak_bind;
int debug;
if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
return;
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
for (afi = 0; afi < AFI_MAX; ++afi) {
/* vrf leak is for IPv4 and IPv6 Unicast only */
if (afi != AFI_IP && afi != AFI_IP6)
continue;
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) {
if (from_bgp == to_bgp)
continue;
/* Unimport and remove source vrf from the
* other vrfs import list.
*/
struct vpn_policy *to_vpolicy;
is_vrf_leak_bind = false;
to_vpolicy = &(to_bgp->vpn_policy[afi]);
for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, node,
vname)) {
if (strcmp(vname, tmp_name) == 0) {
is_vrf_leak_bind = true;
break;
}
}
/* skip this bgp instance as there is no leak to this
* vrf instance.
*/
if (!is_vrf_leak_bind)
continue;
if (debug)
zlog_debug("%s: unimport routes from %s to_bgp %s afi %s import vrfs count %u",
__func__, from_bgp->name_pretty,
to_bgp->name_pretty, afi2str(afi),
to_vpolicy->import_vrf->count);
vrf_unimport_from_vrf(to_bgp, from_bgp, afi, safi);
/* readd vrf name as unimport removes import vrf name
* from the destination vrf's import list where the
* `import vrf` configuration still exist.
*/
vname = XSTRDUP(MTYPE_TMP, tmp_name);
listnode_add(to_bgp->vpn_policy[afi].import_vrf,
vname);
SET_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT);
/* If to_bgp exports its routes to the bgp vrf
* which is being deleted, un-import the
* to_bgp routes from VPN.
*/
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi]
.export_vrf, node,
vname)) {
if (strcmp(vname, tmp_name) == 0) {
vrf_unimport_from_vrf(from_bgp, to_bgp,
afi, safi);
break;
}
}
}
if (bgp_default &&
!CHECK_FLAG(bgp_default->af_flags[afi][SAFI_MPLS_VPN],
BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL)) {
/* 'from_bgp' instance will be deleted
* so force to unset importation to update VPN labels
*/
UNSET_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT);
vpn_leak_no_retain(from_bgp, bgp_default, afi);
}
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
}
return;
bgpd: no router bgp cleanup vrf leaked vpn routes A VRF leak is configured between two vrfs, bgp VRF X and VRF Y. When a bgp VRF X is removed, unimport bgp VRF X routes from VPN and VRF Y. If VRF X is also importing from bgp VRF Y, remove X from export list of Y and do required route cleanup. Ticket:CM-20534 CM-24484 Reviewed By: Testing Done: Before deleteing vrf1002: nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:04:51 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): 6.0.2.9:2 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1002 RD: 6.0.3.9:3 Export RT: 6.0.3.9:3 After deleting vrf1002: nl1(config)# no router bgp 64902 vrf vrf1002 nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 20, metric 0, vrf vrf1003, best Last update 00:00:32 ago * 200.3.8.2, via swp1.3 * 200.3.9.2, via swp2.3 * 200.3.10.2, via swp3.3 Instance vrf1003: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1002 Import RT(s): This VRF is not exporting IPv4 Unicast routes to any other VRF nl1# show bgp ipv4 vpn No BGP prefixes displayed, 0 exist Readd vrf1002: points back to source vrf nl1# show ip route vrf vrf1003 9.9.2.4/32 Routing entry for 9.9.2.4/32 Known via "bgp", distance 200, metric 0, vrf vrf1003, best Last update 00:00:21 ago * 200.2.8.2, via swp1.2(vrf vrf1002) * 200.2.9.2, via swp2.2(vrf vrf1002) * 200.2.10.2, via swp3.2(vrf vrf1002) Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-06-11 02:14:42 +02:00
}
/* When a router bgp is configured, there could be a bgp vrf
* instance importing routes from this newly configured
* bgp vrf instance. Export routes from configured
* bgp vrf to VPN.
* VRF Y has import from bgp vrf x,
* when a bgp vrf x instance is created, export its routes
* to VRF Y instance.
*/
void bgp_vpn_leak_export(struct bgp *from_bgp)
{
afi_t afi;
const char *export_name;
char *vname;
struct listnode *node, *next;
struct ecommunity *ecom;
enum vpn_policy_direction idir, edir;
safi_t safi = SAFI_UNICAST;
struct bgp *to_bgp;
int debug;
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
export_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
for (afi = 0; afi < AFI_MAX; ++afi) {
/* vrf leak is for IPv4 and IPv6 Unicast only */
if (afi != AFI_IP && afi != AFI_IP6)
continue;
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) {
if (from_bgp == to_bgp)
continue;
/* bgp instance has import list, check to see if newly
* configured bgp instance is the list.
*/
struct vpn_policy *to_vpolicy;
to_vpolicy = &(to_bgp->vpn_policy[afi]);
for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf,
node, vname)) {
if (strcmp(vname, export_name) != 0)
continue;
if (debug)
zlog_debug("%s: found from_bgp %s in to_bgp %s import list, import routes.",
__func__,
export_name, to_bgp->name_pretty);
ecom = from_bgp->vpn_policy[afi].rtlist[edir];
/* remove import rt, it will be readded
* as part of import from vrf.
*/
if (ecom)
ecommunity_del_val(
to_vpolicy->rtlist[idir],
(struct ecommunity_val *)
ecom->val);
vrf_import_from_vrf(to_bgp, from_bgp,
afi, safi);
break;
}
}
}
}
/* The nexthops values are compared to
* find in the tree the appropriate cache entry
*/
int bgp_mplsvpn_nh_label_bind_cmp(
const struct bgp_mplsvpn_nh_label_bind_cache *a,
const struct bgp_mplsvpn_nh_label_bind_cache *b)
{
if (prefix_cmp(&a->nexthop, &b->nexthop))
return 1;
if (a->orig_label > b->orig_label)
return 1;
if (a->orig_label < b->orig_label)
return -1;
return 0;
}
static void bgp_mplsvpn_nh_label_bind_send_nexthop_label(
struct bgp_mplsvpn_nh_label_bind_cache *bmnc, int cmd)
{
struct prefix pfx_nh, *p = NULL;
uint32_t num_labels = 0, lsp_num_labels;
mpls_label_t label[MPLS_MAX_LABELS];
struct nexthop *nh;
ifindex_t ifindex = IFINDEX_INTERNAL;
vrf_id_t vrf_id = VRF_DEFAULT;
uint32_t i;
if (bmnc->nh == NULL)
return;
nh = bmnc->nh;
switch (nh->type) {
case NEXTHOP_TYPE_IFINDEX:
p = &bmnc->nexthop;
label[num_labels] = bmnc->orig_label;
num_labels += 1;
ifindex = nh->ifindex;
vrf_id = nh->vrf_id;
break;
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
if (nh->type == NEXTHOP_TYPE_IPV4 ||
nh->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
pfx_nh.family = AF_INET;
pfx_nh.prefixlen = IPV4_MAX_BITLEN;
IPV4_ADDR_COPY(&pfx_nh.u.prefix4, &nh->gate.ipv4);
} else {
pfx_nh.family = AF_INET6;
pfx_nh.prefixlen = IPV6_MAX_BITLEN;
IPV6_ADDR_COPY(&pfx_nh.u.prefix6, &nh->gate.ipv6);
}
p = &pfx_nh;
if (nh->nh_label) {
if (nh->nh_label->num_labels + 1 > MPLS_MAX_LABELS) {
/* label stack overflow. no label switching will be performed
*/
flog_err(EC_BGP_LABEL,
"%s [Error] BGP label %u->%u to %pFX, forged label stack too big: %u. Abort LSP installation",
bmnc->bgp_vpn->name_pretty,
bmnc->new_label, bmnc->orig_label,
&bmnc->nexthop,
nh->nh_label->num_labels + 1);
return;
}
lsp_num_labels = nh->nh_label->num_labels;
for (i = 0; i < lsp_num_labels; i++)
label[num_labels + i] = nh->nh_label->label[i];
num_labels = lsp_num_labels;
}
label[num_labels] = bmnc->orig_label;
num_labels += 1;
if (nh->type == NEXTHOP_TYPE_IPV4_IFINDEX ||
nh->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
ifindex = nh->ifindex;
vrf_id = nh->vrf_id;
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
return;
}
bgp_zebra_send_nexthop_label(cmd, bmnc->new_label, ifindex, vrf_id,
ZEBRA_LSP_BGP, p, num_labels, &label[0]);
}
void bgp_mplsvpn_nh_label_bind_free(
struct bgp_mplsvpn_nh_label_bind_cache *bmnc)
{
if (bmnc->allocation_in_progress) {
bmnc->allocation_in_progress = false;
bgp_mplsvpn_nh_label_bind_cache_del(
&bmnc->bgp_vpn->mplsvpn_nh_label_bind, bmnc);
return;
}
if (bmnc->new_label != MPLS_INVALID_LABEL) {
bgp_mplsvpn_nh_label_bind_send_nexthop_label(
bmnc, ZEBRA_MPLS_LABELS_DELETE);
bgp_lp_release(LP_TYPE_BGP_L3VPN_BIND, bmnc, bmnc->new_label);
}
bgp_mplsvpn_nh_label_bind_cache_del(
&bmnc->bgp_vpn->mplsvpn_nh_label_bind, bmnc);
bgpd: Free nexthop in bgp_mplsvpn_nh_label_bind_free `bmnc->nh` was not properly freed, leading to a memory leak. The commit adds a check to ensure that the `bmnc->nh` member variable is freed if it exists. The ASan leak log for reference: ``` *********************************************************************************** Address Sanitizer Error detected in bgp_vpnv4_asbr.test_bgp_vpnv4_asbr/r2.asan.bgpd.6382 ================================================================= ==6382==ERROR: LeakSanitizer: detected memory leaks Direct leak of 720 byte(s) in 5 object(s) allocated from: #0 0x7f6a80d02d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x55c9afd7c81c in qcalloc lib/memory.c:105 #2 0x55c9afd9166b in nexthop_new lib/nexthop.c:358 #3 0x55c9afd93aaa in nexthop_dup lib/nexthop.c:843 #4 0x55c9afad39bb in bgp_mplsvpn_nh_label_bind_register_local_label bgpd/bgp_mplsvpn.c:4259 #5 0x55c9afb1c5e9 in bgp_mplsvpn_handle_label_allocation bgpd/bgp_route.c:3239 #6 0x55c9afb1c5e9 in bgp_process_main_one bgpd/bgp_route.c:3339 #7 0x55c9afb1d2c1 in bgp_process_wq bgpd/bgp_route.c:3591 #8 0x55c9afe33df9 in work_queue_run lib/workqueue.c:266 #9 0x55c9afe198e2 in event_call lib/event.c:1995 #10 0x55c9afd5fc6f in frr_run lib/libfrr.c:1213 #11 0x55c9af9f6f00 in main bgpd/bgp_main.c:505 #12 0x7f6a7f55ec86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 16 byte(s) in 2 object(s) allocated from: #0 0x7f6a80d02d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x55c9afd7c81c in qcalloc lib/memory.c:105 #2 0x55c9afd91ce8 in nexthop_add_labels lib/nexthop.c:536 #3 0x55c9afd93754 in nexthop_copy_no_recurse lib/nexthop.c:802 #4 0x55c9afd939fb in nexthop_copy lib/nexthop.c:821 #5 0x55c9afd93abb in nexthop_dup lib/nexthop.c:845 #6 0x55c9afad39bb in bgp_mplsvpn_nh_label_bind_register_local_label bgpd/bgp_mplsvpn.c:4259 #7 0x55c9afb1c5e9 in bgp_mplsvpn_handle_label_allocation bgpd/bgp_route.c:3239 #8 0x55c9afb1c5e9 in bgp_process_main_one bgpd/bgp_route.c:3339 #9 0x55c9afb1d2c1 in bgp_process_wq bgpd/bgp_route.c:3591 #10 0x55c9afe33df9 in work_queue_run lib/workqueue.c:266 #11 0x55c9afe198e2 in event_call lib/event.c:1995 #12 0x55c9afd5fc6f in frr_run lib/libfrr.c:1213 #13 0x55c9af9f6f00 in main bgpd/bgp_main.c:505 #14 0x7f6a7f55ec86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) SUMMARY: AddressSanitizer: 736 byte(s) leaked in 7 allocation(s). *********************************************************************************** ``` Signed-off-by: Keelan Cannoo <keelan.cannoo@icloud.com>
2023-07-04 12:13:15 +02:00
if (bmnc->nh)
nexthop_free(bmnc->nh);
XFREE(MTYPE_MPLSVPN_NH_LABEL_BIND_CACHE, bmnc);
}
struct bgp_mplsvpn_nh_label_bind_cache *
bgp_mplsvpn_nh_label_bind_new(struct bgp_mplsvpn_nh_label_bind_cache_head *tree,
struct prefix *p, mpls_label_t orig_label)
{
struct bgp_mplsvpn_nh_label_bind_cache *bmnc;
bmnc = XCALLOC(MTYPE_MPLSVPN_NH_LABEL_BIND_CACHE,
sizeof(struct bgp_mplsvpn_nh_label_bind_cache));
bmnc->new_label = MPLS_INVALID_LABEL;
prefix_copy(&bmnc->nexthop, p);
bmnc->orig_label = orig_label;
LIST_INIT(&(bmnc->paths));
bgp_mplsvpn_nh_label_bind_cache_add(tree, bmnc);
return bmnc;
}
struct bgp_mplsvpn_nh_label_bind_cache *bgp_mplsvpn_nh_label_bind_find(
struct bgp_mplsvpn_nh_label_bind_cache_head *tree, struct prefix *p,
mpls_label_t orig_label)
{
struct bgp_mplsvpn_nh_label_bind_cache bmnc = {0};
if (!tree)
return NULL;
prefix_copy(&bmnc.nexthop, p);
bmnc.orig_label = orig_label;
return bgp_mplsvpn_nh_label_bind_cache_find(tree, &bmnc);
}
/* Called to check if the incoming l3vpn path entry
* has mpls label information
*/
bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi)
{
if (pi->attr && pi->attr->srv6_l3vpn)
/* srv6 sid */
return false;
if (pi->attr &&
CHECK_FLAG(pi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) &&
pi->attr->label_index != BGP_INVALID_LABEL_INDEX)
/* prefix_sid attribute */
return false;
if (!pi->extra || !bgp_is_valid_label(&pi->extra->label[0]))
/* invalid MPLS label */
return false;
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.
*/
static int bgp_mplsvpn_nh_label_bind_get_local_label_cb(mpls_label_t label,
void *context,
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",
__func__, label, allocated, &bmnc->nexthop,
bmnc->orig_label);
if (allocated)
/* update the entry with the new label */
bmnc->new_label = label;
else
/*
* previously-allocated label is now invalid
* eg: zebra deallocated the labels and notifies it
*/
bmnc->new_label = MPLS_INVALID_LABEL;
if (!bmnc->allocation_in_progress) {
bgp_mplsvpn_nh_label_bind_free(bmnc);
return 0;
}
bmnc->allocation_in_progress = false;
if (bmnc->new_label != MPLS_INVALID_LABEL)
/*
* Create the LSP : <local_label -> bmnc->orig_label,
* via bmnc->prefix, interface bnc->nexthop->ifindex
*/
bgp_mplsvpn_nh_label_bind_send_nexthop_label(
bmnc, ZEBRA_MPLS_LABELS_ADD);
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;
}
void bgp_mplsvpn_path_nh_label_bind_unlink(struct bgp_path_info *pi)
{
struct bgp_mplsvpn_nh_label_bind_cache *bmnc;
if (!pi)
return;
if (!CHECK_FLAG(pi->flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND))
return;
bmnc = pi->mplsvpn.bmnc.nh_label_bind_cache;
if (!bmnc)
return;
LIST_REMOVE(pi, mplsvpn.bmnc.nh_label_bind_thread);
pi->mplsvpn.bmnc.nh_label_bind_cache->path_count--;
pi->mplsvpn.bmnc.nh_label_bind_cache = NULL;
SET_FLAG(pi->flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND);
if (LIST_EMPTY(&(bmnc->paths)))
bgp_mplsvpn_nh_label_bind_free(bmnc);
}
void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp,
struct bgp_dest *dest,
struct bgp_path_info *pi)
{
struct bgp_mplsvpn_nh_label_bind_cache *bmnc;
struct bgp_mplsvpn_nh_label_bind_cache_head *tree;
tree = &bgp->mplsvpn_nh_label_bind;
bmnc = bgp_mplsvpn_nh_label_bind_find(
tree, &pi->nexthop->prefix, decode_label(&pi->extra->label[0]));
if (!bmnc) {
bmnc = bgp_mplsvpn_nh_label_bind_new(
tree, &pi->nexthop->prefix,
decode_label(&pi->extra->label[0]));
bmnc->bgp_vpn = bgp;
bmnc->allocation_in_progress = true;
bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc,
bgp_mplsvpn_nh_label_bind_get_local_label_cb);
}
if (pi->mplsvpn.bmnc.nh_label_bind_cache == bmnc)
/* no change */
return;
bgp_mplsvpn_path_nh_label_bind_unlink(pi);
/* updates NHT pi list reference */
LIST_INSERT_HEAD(&(bmnc->paths), pi, mplsvpn.bmnc.nh_label_bind_thread);
pi->mplsvpn.bmnc.nh_label_bind_cache = bmnc;
pi->mplsvpn.bmnc.nh_label_bind_cache->path_count++;
SET_FLAG(pi->flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND);
bmnc->last_update = monotime(NULL);
/* Add or update the selected nexthop */
if (!bmnc->nh)
bmnc->nh = nexthop_dup(pi->nexthop->nexthop, NULL);
else if (!nexthop_same(pi->nexthop->nexthop, bmnc->nh)) {
nexthop_free(bmnc->nh);
bmnc->nh = nexthop_dup(pi->nexthop->nexthop, NULL);
if (bmnc->new_label != MPLS_INVALID_LABEL)
bgp_mplsvpn_nh_label_bind_send_nexthop_label(
bmnc, ZEBRA_MPLS_LABELS_REPLACE);
}
}
static void show_bgp_mplsvpn_nh_label_bind_internal(struct vty *vty,
struct bgp *bgp,
bool detail)
{
struct bgp_mplsvpn_nh_label_bind_cache_head *tree;
struct bgp_mplsvpn_nh_label_bind_cache *iter;
afi_t afi;
safi_t safi;
struct bgp_dest *dest;
struct bgp_path_info *path;
struct bgp *bgp_path;
struct bgp_table *table;
time_t tbuf;
char buf[32];
vty_out(vty, "Current BGP mpls-vpn nexthop label bind cache, %s\n",
bgp->name_pretty);
tree = &bgp->mplsvpn_nh_label_bind;
frr_each (bgp_mplsvpn_nh_label_bind_cache, tree, iter) {
if (iter->nexthop.family == AF_INET)
vty_out(vty, " %pI4", &iter->nexthop.u.prefix4);
else
vty_out(vty, " %pI6", &iter->nexthop.u.prefix6);
vty_out(vty, ", label %u, local label %u #paths %u\n",
iter->orig_label, iter->new_label, iter->path_count);
if (iter->nh)
vty_out(vty, " interface %s\n",
ifindex2ifname(iter->nh->ifindex,
iter->nh->vrf_id));
tbuf = time(NULL) - (monotime(NULL) - iter->last_update);
vty_out(vty, " Last update: %s", ctime_r(&tbuf, buf));
if (!detail)
continue;
vty_out(vty, " Paths:\n");
LIST_FOREACH (path, &(iter->paths),
mplsvpn.bmnc.nh_label_bind_thread) {
dest = path->net;
table = bgp_dest_table(dest);
assert(dest && table);
afi = family2afi(bgp_dest_get_prefix(dest)->family);
safi = table->safi;
bgp_path = table->bgp;
vty_out(vty, " %d/%d %pBD %s flags 0x%x\n", afi,
safi, dest, bgp_path->name_pretty, path->flags);
}
}
}
DEFUN(show_bgp_mplsvpn_nh_label_bind, show_bgp_mplsvpn_nh_label_bind_cmd,
"show bgp [<view|vrf> VIEWVRFNAME] mplsvpn-nh-label-bind [detail]",
SHOW_STR BGP_STR BGP_INSTANCE_HELP_STR
"BGP mplsvpn nexthop label binding entries\n"
"Show detailed information\n")
{
int idx = 0;
char *vrf = NULL;
struct bgp *bgp;
bool detail = false;
if (argv_find(argv, argc, "vrf", &idx)) {
vrf = argv[++idx]->arg;
bgp = bgp_lookup_by_name(vrf);
} else
bgp = bgp_get_default();
if (!bgp)
return CMD_SUCCESS;
if (argv_find(argv, argc, "detail", &idx))
detail = true;
show_bgp_mplsvpn_nh_label_bind_internal(vty, bgp, detail);
return CMD_SUCCESS;
}
void bgp_mplsvpn_nexthop_init(void)
{
install_element(VIEW_NODE, &show_bgp_mplsvpn_nh_label_bind_cmd);
}