2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2002-12-13 21:15:29 +01:00
|
|
|
/* MPLS-VPN
|
2017-05-13 10:25:29 +02:00
|
|
|
* 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"
|
2015-05-20 03:03:47 +02:00
|
|
|
#include "queue.h"
|
2016-01-07 16:03:01 +01:00
|
|
|
#include "filter.h"
|
2018-03-09 21:52:55 +01:00
|
|
|
#include "mpls.h"
|
2018-03-16 19:11:37 +01:00
|
|
|
#include "json.h"
|
|
|
|
#include "zclient.h"
|
2017-06-16 21:12:57 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "bgpd/bgpd.h"
|
2018-03-09 21:52:55 +01:00
|
|
|
#include "bgpd/bgp_debug.h"
|
2018-06-15 23:08:53 +02:00
|
|
|
#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"
|
2017-06-16 21:12:57 +02:00
|
|
|
#include "bgpd/bgp_label.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "bgpd/bgp_mplsvpn.h"
|
2016-01-27 17:37:33 +01:00
|
|
|
#include "bgpd/bgp_packet.h"
|
2017-01-08 18:09:04 +01:00
|
|
|
#include "bgpd/bgp_vty.h"
|
2017-01-09 18:26:24 +01:00
|
|
|
#include "bgpd/bgp_vpn.h"
|
2022-09-18 21:18:13 +02:00
|
|
|
#include "bgpd/bgp_community.h"
|
2018-03-09 21:52:55 +01:00
|
|
|
#include "bgpd/bgp_ecommunity.h"
|
|
|
|
#include "bgpd/bgp_zebra.h"
|
|
|
|
#include "bgpd/bgp_nexthop.h"
|
2018-03-24 00:57:03 +01:00
|
|
|
#include "bgpd/bgp_nht.h"
|
2019-02-28 12:11:01 +01:00
|
|
|
#include "bgpd/bgp_evpn.h"
|
2020-12-19 03:04:40 +01:00
|
|
|
#include "bgpd/bgp_memory.h"
|
2021-06-09 22:50:20 +02:00
|
|
|
#include "bgpd/bgp_aspath.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2020-04-01 21:05:26 +02:00
|
|
|
#ifdef ENABLE_BGP_VNC
|
2016-09-29 00:03:43 +02:00
|
|
|
#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
|
|
|
|
|
2023-05-02 16:38:53 +02:00
|
|
|
DEFINE_MTYPE_STATIC(BGPD, MPLSVPN_NH_LABEL_BIND_CACHE,
|
|
|
|
"BGP MPLSVPN nexthop label bind cache");
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* Definitions and external declarations.
|
|
|
|
*/
|
|
|
|
extern struct zclient *zclient;
|
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t decode_label(mpls_label_t *label_pnt)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t l;
|
|
|
|
uint8_t *pnt = (uint8_t *)label_pnt;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2018-03-27 21:13:34 +02: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;
|
|
|
|
}
|
|
|
|
|
2017-06-16 21:12:57 +02:00
|
|
|
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
|
|
|
{
|
2018-03-27 21:13:34 +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;
|
2018-04-25 16:23:22 +02:00
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
2016-01-12 19:41:55 +01:00
|
|
|
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;
|
2020-09-03 19:22:17 +02:00
|
|
|
uint8_t psize = 0;
|
|
|
|
uint8_t prefixlen;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t type;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rd_as rd_as;
|
|
|
|
struct rd_ip rd_ip;
|
2019-10-10 14:52:13 +02:00
|
|
|
struct prefix_rd prd = {0};
|
2018-03-09 21:52:55 +01:00
|
|
|
mpls_label_t label = {0};
|
2015-05-20 03:03:45 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2022-01-27 08:51:59 +01:00
|
|
|
bool addpath_capable;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t addpath_id;
|
2020-09-03 19:22:17 +02:00
|
|
|
int ret = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Make prefix_rd */
|
|
|
|
prd.family = AF_UNSPEC;
|
|
|
|
prd.prefixlen = 64;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-09-03 19:22:17 +02:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-27 08:51:59 +01:00
|
|
|
addpath_capable = bgp_addpath_encode_rx(peer, afi, safi);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-01-27 17:54:45 +01:00
|
|
|
#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */
|
2020-09-03 19:22:17 +02:00
|
|
|
while (STREAM_READABLE(data) > 0) {
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Clear prefix structure. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&p, 0, sizeof(p));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-27 08:51:59 +01:00
|
|
|
if (addpath_capable) {
|
2020-09-03 19:22:17 +02:00
|
|
|
STREAM_GET(&addpath_id, data, BGP_ADDPATH_ID_LEN);
|
2020-01-07 16:47:13 +01:00
|
|
|
addpath_id = ntohl(addpath_id);
|
2020-09-03 19:22:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-27 13:54:56 +02:00
|
|
|
/* Fetch prefix length. */
|
2020-09-03 19:22:17 +02:00
|
|
|
STREAM_GETC(data, prefixlen);
|
2016-09-27 13:54:56 +02:00
|
|
|
p.family = afi2family(packet->afi);
|
|
|
|
psize = PSIZE(prefixlen);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-27 17:37:33 +01:00
|
|
|
if (prefixlen < VPN_PREFIXLEN_MIN_BYTES * 8) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_UPDATE_RCV,
|
2017-01-18 12:27:52 +01:00
|
|
|
"%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",
|
2016-01-27 17:37:33 +01:00
|
|
|
peer->host, prefixlen);
|
2020-09-03 19:22:17 +02:00
|
|
|
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
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-27 17:54:45 +01:00
|
|
|
/* sanity check against packet data */
|
2020-09-03 19:22:17 +02:00
|
|
|
if (STREAM_READABLE(data) < psize) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_UPDATE_RCV,
|
2017-01-18 12:27:52 +01:00
|
|
|
"%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)",
|
2020-09-03 19:22:17 +02:00
|
|
|
peer->host, prefixlen, packet->length);
|
|
|
|
ret = BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
|
|
|
|
goto done;
|
2016-01-27 17:54:45 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-27 17:54:45 +01:00
|
|
|
/* sanity check against storage for the IP address portion */
|
|
|
|
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t)sizeof(p.u)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_UPDATE_RCV,
|
2017-01-18 12:27:52 +01:00
|
|
|
"%s [Error] Update packet error / VPN (psize %d exceeds storage size %zu)",
|
2016-01-27 17:37:33 +01:00
|
|
|
peer->host,
|
2016-01-27 17:54:45 +01:00
|
|
|
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
|
|
|
|
sizeof(p.u));
|
2020-09-03 19:22:17 +02:00
|
|
|
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
|
|
|
|
goto done;
|
2016-01-27 17:54:45 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-27 17:54:45 +01:00
|
|
|
/* Sanity check against max bitlen of the address family */
|
|
|
|
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen(&p)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_UPDATE_RCV,
|
2017-01-18 12:27:52 +01:00
|
|
|
"%s [Error] Update packet error / VPN (psize %d exceeds family (%u) max byte len %u)",
|
2016-01-27 17:37:33 +01:00
|
|
|
peer->host,
|
2016-01-27 17:54:45 +01:00
|
|
|
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
|
|
|
|
p.family, prefix_blen(&p));
|
2020-09-03 19:22:17 +02:00
|
|
|
ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
|
|
|
|
goto done;
|
2016-01-27 17:54:45 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-16 21:12:57 +02:00
|
|
|
/* Copy label to prefix. */
|
2020-09-03 19:22:17 +02:00
|
|
|
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);
|
2017-06-16 21:12:57 +02:00
|
|
|
bgp_set_valid_label(&label);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Copy routing distinguisher to rd. */
|
2020-09-03 19:22:17 +02:00
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Decode RD type. */
|
2020-09-03 19:22:17 +02:00
|
|
|
type = decode_rd_type(prd.val);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-12 19:41:54 +01:00
|
|
|
switch (type) {
|
|
|
|
case RD_TYPE_AS:
|
2020-09-03 19:22:17 +02:00
|
|
|
decode_rd_as(&prd.val[2], &rd_as);
|
2016-01-12 19:41:54 +01:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-12 19:41:54 +01:00
|
|
|
case RD_TYPE_AS4:
|
2020-09-03 19:22:17 +02:00
|
|
|
decode_rd_as4(&prd.val[2], &rd_as);
|
2016-01-12 19:41:54 +01:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-01-12 19:41:54 +01:00
|
|
|
case RD_TYPE_IP:
|
2020-09-03 19:22:17 +02:00
|
|
|
decode_rd_ip(&prd.val[2], &rd_ip);
|
2016-01-12 19:41:54 +01:00
|
|
|
break;
|
|
|
|
|
2020-04-01 21:05:26 +02:00
|
|
|
#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
|
|
|
|
|
2016-01-12 19:41:59 +01:00
|
|
|
default:
|
2018-09-13 21:38:57 +02:00
|
|
|
flog_err(EC_BGP_UPDATE_RCV, "Unknown RD type %d", type);
|
2016-01-12 19:41:59 +01:00
|
|
|
break; /* just report */
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-09-03 19:22:17 +02:00
|
|
|
/* exclude label & RD */
|
|
|
|
p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8;
|
|
|
|
STREAM_GET(p.u.val, data, psize - VPN_PREFIXLEN_MIN_BYTES);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (attr) {
|
2017-01-16 20:09:12 +01:00
|
|
|
bgp_update(peer, &p, addpath_id, attr, packet->afi,
|
2017-06-16 21:12:57 +02:00
|
|
|
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
2017-11-21 11:42:05 +01:00
|
|
|
BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL);
|
2002-12-13 21:15:29 +01:00
|
|
|
} else {
|
2023-02-21 10:35:59 +01:00
|
|
|
bgp_withdraw(peer, &p, addpath_id, packet->afi,
|
2017-06-16 21:12:57 +02:00
|
|
|
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
2024-08-11 12:59:13 +02:00
|
|
|
BGP_ROUTE_NORMAL, &prd, &label, 1);
|
2017-01-16 20:09:12 +01:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
/* Packet length consistency check. */
|
2020-09-03 19:22:17 +02:00
|
|
|
if (STREAM_READABLE(data) != 0) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_UPDATE_RCV,
|
2020-11-03 23:07:08 +01:00
|
|
|
"%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
|
2020-09-03 19:22:17 +02:00
|
|
|
peer->host, STREAM_READABLE(data));
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
|
2016-01-27 17:37:33 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-09-03 19:22:17 +02: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;
|
|
|
|
|
2016-01-27 17:54:45 +01:00
|
|
|
#undef VPN_PREFIXLEN_MIN_BYTES
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +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
|
2024-07-16 14:03:11 +02:00
|
|
|
* are set), b) whether vpn-policy label is set and c) the vrf loopback
|
|
|
|
* interface is up.
|
2018-03-09 21:52:55 +01:00
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
{
|
2024-07-16 14:03:11 +02:00
|
|
|
struct interface *ifp;
|
2018-03-09 21:52:55 +01:00
|
|
|
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(
|
2020-03-27 12:35:23 +01:00
|
|
|
"%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp->name_pretty, afi2str(afi));
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-28 17:05:43 +02:00
|
|
|
if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) {
|
2024-07-16 14:03:11 +02:00
|
|
|
ifp = if_get_vrf_loopback(bgp->vrf_id);
|
2024-09-03 18:36:25 +02:00
|
|
|
if (ifp && if_is_up(ifp))
|
2024-07-16 14:03:11 +02:00
|
|
|
label = bgp->vpn_policy[afi].tovpn_label;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
zlog_debug("%s: vrf %s: afi %s: setting label %d for vrf id %d",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp->name_pretty, afi2str(afi), label,
|
|
|
|
bgp->vrf_id);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2019-01-09 14:48:37 +01:00
|
|
|
if (label == BGP_PREVENT_VRF_2_VRF_LEAK)
|
|
|
|
label = MPLS_LABEL_NONE;
|
2018-03-09 21:52:55 +01:00
|
|
|
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__,
|
2018-03-24 00:57:03 +01:00
|
|
|
bgp->name_pretty, bgp->vrf_id);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
|
|
|
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
|
|
|
|
}
|
|
|
|
|
2020-12-19 03:04:40 +01:00
|
|
|
/*
|
|
|
|
* 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."
|
|
|
|
*/
|
2022-07-23 11:49:56 +02:00
|
|
|
void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
|
2020-12-19 03:04:40 +01:00
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
|
|
|
enum seg6local_action_t act;
|
2021-03-22 01:31:56 +01:00
|
|
|
struct seg6local_context ctx = {};
|
2020-12-19 03:04:40 +01:00
|
|
|
struct in6_addr *tovpn_sid = NULL;
|
|
|
|
struct in6_addr *tovpn_sid_ls = NULL;
|
|
|
|
struct vrf *vrf;
|
|
|
|
|
|
|
|
if (bgp->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug)
|
2021-02-24 11:10:06 +01:00
|
|
|
zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label",
|
2020-12-19 03:04:40 +01:00
|
|
|
__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;
|
|
|
|
}
|
|
|
|
|
2022-10-30 08:25:07 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: vrf %s: afi %s: setting sid %pI6 for vrf id %d",
|
|
|
|
__func__, bgp->name_pretty, afi2str(afi), tovpn_sid,
|
2020-12-19 03:04:40 +01:00
|
|
|
bgp->vrf_id);
|
|
|
|
|
|
|
|
vrf = vrf_lookup_by_id(bgp->vrf_id);
|
|
|
|
if (!vrf)
|
|
|
|
return;
|
|
|
|
|
2024-09-15 18:53:35 +02:00
|
|
|
if (bgp->vpn_policy[afi].tovpn_sid_locator) {
|
|
|
|
ctx.block_len =
|
|
|
|
bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
|
|
|
|
ctx.node_len =
|
|
|
|
bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
|
|
|
|
ctx.function_len =
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->function_bits_length;
|
|
|
|
ctx.argument_len =
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->argument_bits_length;
|
|
|
|
}
|
2020-12-19 03:04:40 +01:00
|
|
|
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;
|
2024-03-29 08:35:34 +01:00
|
|
|
if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
|
|
|
|
XFREE(MTYPE_BGP_SRV6_SID,
|
|
|
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
|
2020-12-19 03:04:40 +01:00
|
|
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
|
|
|
|
}
|
|
|
|
|
2022-07-23 11:49:56 +02:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2024-09-15 18:54:55 +02:00
|
|
|
if (bgp->tovpn_sid_locator) {
|
|
|
|
ctx.block_len = bgp->tovpn_sid_locator->block_bits_length;
|
|
|
|
ctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
|
|
|
|
ctx.function_len = bgp->tovpn_sid_locator->function_bits_length;
|
|
|
|
ctx.argument_len = bgp->tovpn_sid_locator->argument_bits_length;
|
|
|
|
}
|
2022-07-23 11:49:56 +02:00
|
|
|
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;
|
2024-03-29 08:35:34 +01:00
|
|
|
if (bgp->tovpn_zebra_vrf_sid_last_sent)
|
|
|
|
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
|
2022-07-23 11:49:56 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2020-12-19 03:04:40 +01:00
|
|
|
/*
|
|
|
|
* If zebra tells us vrf has become unconfigured, tell zebra not to
|
|
|
|
* use this srv6-function to forward to the vrf anymore
|
|
|
|
*/
|
2022-07-23 11:49:56 +02:00
|
|
|
void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
|
2020-12-19 03:04:40 +01:00
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
2024-03-23 19:23:52 +01:00
|
|
|
struct srv6_sid_ctx ctx = {};
|
2024-09-15 18:56:21 +02:00
|
|
|
struct seg6local_context seg6localctx = {};
|
2020-12-19 03:04:40 +01:00
|
|
|
|
|
|
|
if (bgp->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug)
|
2021-02-24 11:10:06 +01:00
|
|
|
zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label",
|
2020-12-19 03:04:40 +01:00
|
|
|
__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);
|
|
|
|
|
2024-09-15 18:56:21 +02:00
|
|
|
if (bgp->vpn_policy[afi].tovpn_sid_locator) {
|
|
|
|
seg6localctx.block_len =
|
|
|
|
bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
|
|
|
|
seg6localctx.node_len =
|
|
|
|
bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
|
|
|
|
seg6localctx.function_len =
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->function_bits_length;
|
|
|
|
seg6localctx.argument_len =
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->argument_bits_length;
|
|
|
|
}
|
2020-12-19 03:04:40 +01:00
|
|
|
zclient_send_localsid(zclient,
|
2024-09-15 18:56:21 +02:00
|
|
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
|
|
|
|
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
|
|
|
|
&seg6localctx);
|
2020-12-19 03:04:40 +01:00
|
|
|
XFREE(MTYPE_BGP_SRV6_SID,
|
|
|
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
|
2024-03-29 08:35:34 +01:00
|
|
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL;
|
2024-03-23 19:23:52 +01:00
|
|
|
|
|
|
|
ctx.vrf_id = bgp->vrf_id;
|
|
|
|
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
|
|
|
|
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
|
|
|
|
bgp_zebra_release_srv6_sid(&ctx);
|
2020-12-19 03:04:40 +01:00
|
|
|
}
|
|
|
|
|
2022-07-23 11:49:56 +02:00
|
|
|
/*
|
|
|
|
* 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);
|
2024-03-23 19:23:52 +01:00
|
|
|
struct srv6_sid_ctx ctx = {};
|
2024-09-15 18:56:48 +02:00
|
|
|
struct seg6local_context seg6localctx = {};
|
2022-07-23 11:49:56 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2024-09-15 18:56:48 +02:00
|
|
|
if (bgp->tovpn_sid_locator) {
|
|
|
|
seg6localctx.block_len =
|
|
|
|
bgp->tovpn_sid_locator->block_bits_length;
|
|
|
|
seg6localctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
|
|
|
|
seg6localctx.function_len =
|
|
|
|
bgp->tovpn_sid_locator->function_bits_length;
|
|
|
|
seg6localctx.argument_len =
|
|
|
|
bgp->tovpn_sid_locator->argument_bits_length;
|
|
|
|
}
|
2022-07-23 11:49:56 +02:00
|
|
|
zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
|
|
|
|
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
|
2024-09-15 18:56:48 +02:00
|
|
|
&seg6localctx);
|
2022-07-23 11:49:56 +02:00
|
|
|
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
|
2024-03-29 08:35:34 +01:00
|
|
|
bgp->tovpn_zebra_vrf_sid_last_sent = NULL;
|
2024-03-23 19:23:52 +01:00
|
|
|
|
|
|
|
ctx.vrf_id = bgp->vrf_id;
|
|
|
|
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
|
|
|
|
bgp_zebra_release_srv6_sid(&ctx);
|
2022-07-23 11:49:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2018-04-07 20:32:52 +02:00
|
|
|
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 */
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_LABEL,
|
2018-09-13 21:38:57 +02:00
|
|
|
"%s: %s had label %u but got new assignment %u",
|
|
|
|
__func__, vp->bgp->name_pretty, vp->tovpn_label,
|
|
|
|
label);
|
2018-04-07 20:32:52 +02:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2024-05-10 12:50:27 +02:00
|
|
|
void sid_register(struct bgp *bgp, const struct in6_addr *sid,
|
|
|
|
const char *locator_name)
|
2020-12-19 03:04:40 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-11-29 12:49:58 +01:00
|
|
|
void srv6_function_free(struct bgp_srv6_function *func)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_BGP_SRV6_FUNCTION, func);
|
|
|
|
}
|
|
|
|
|
2023-06-27 08:59:09 +02:00
|
|
|
void sid_unregister(struct bgp *bgp, const struct in6_addr *sid)
|
2022-08-23 16:04:06 +02:00
|
|
|
{
|
|
|
|
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);
|
2023-11-29 12:49:58 +01:00
|
|
|
srv6_function_free(func);
|
2022-08-23 16:04:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 03:04:40 +01:00
|
|
|
static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct bgp_srv6_function *func;
|
2021-02-24 11:10:06 +01:00
|
|
|
|
2020-12-19 03:04:40 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func))
|
|
|
|
if (sid_same(&func->sid, sid))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
/**
|
|
|
|
* Return the SRv6 SID value obtained by composing the LOCATOR and FUNCTION.
|
|
|
|
*
|
|
|
|
* @param sid_value SRv6 SID value returned
|
|
|
|
* @param locator Parent locator of the SRv6 SID
|
|
|
|
* @param sid_func Function part of the SID
|
|
|
|
* @return True if success, False otherwise
|
|
|
|
*/
|
|
|
|
static bool srv6_sid_compose(struct in6_addr *sid_value,
|
|
|
|
struct srv6_locator *locator, uint32_t sid_func)
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
|
|
|
int label = 0;
|
|
|
|
uint8_t offset = 0;
|
|
|
|
uint8_t func_len = 0, shift_len = 0;
|
|
|
|
uint32_t sid_func_max = 0;
|
|
|
|
|
|
|
|
if (!locator || !sid_value)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (locator->function_bits_length >
|
|
|
|
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length must be less or equal to %d",
|
|
|
|
__func__, &locator->prefix,
|
|
|
|
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Max value that can be encoded in the Function part of the SID */
|
|
|
|
sid_func_max = (1 << locator->function_bits_length) - 1;
|
|
|
|
|
|
|
|
if (sid_func > sid_func_max) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length is too short to support specified function (%u)",
|
|
|
|
__func__, &locator->prefix, sid_func);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Let's build the SID value.
|
|
|
|
* sid_value = LOC:FUNC::
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* First, we put the locator (LOC) in the most significant bits of sid_value */
|
|
|
|
*sid_value = locator->prefix.prefix;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Then, we compute the offset at which we have to place the function (FUNC).
|
|
|
|
* FUNC will be placed immediately after LOC, i.e. at block_bits_length + node_bits_length
|
|
|
|
*/
|
|
|
|
offset = locator->block_bits_length + locator->node_bits_length;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The FUNC part of the SID is advertised in the label field of SRv6 Service TLV.
|
|
|
|
* (see SID Transposition Scheme, RFC 9252 section #4).
|
|
|
|
* Therefore, we need to encode the FUNC in the most significant bits of the
|
|
|
|
* 20-bit label.
|
|
|
|
*/
|
|
|
|
func_len = locator->function_bits_length;
|
|
|
|
shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
|
|
|
|
|
|
|
|
label = sid_func << 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__, &locator->prefix, label);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sid_exist(bgp_get_default(), sid_value)) {
|
|
|
|
zlog_warn("%s: skipped to allocate SRv6 SID (%pFX): SID %pI6 already in use",
|
|
|
|
__func__, &locator->prefix, sid_value);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, we put the FUNC in sid_value at the computed offset */
|
|
|
|
transpose_sid(sid_value, label, offset, func_len);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-23 11:49:56 +02:00
|
|
|
void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
|
|
|
|
afi_t afi)
|
2020-12-19 03:04:40 +01:00
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
2024-03-23 19:24:59 +01:00
|
|
|
struct in6_addr tovpn_sid = {};
|
|
|
|
uint32_t tovpn_sid_index = 0;
|
2020-12-19 03:04:40 +01:00
|
|
|
bool tovpn_sid_auto = false;
|
2024-03-23 19:24:59 +01:00
|
|
|
struct srv6_sid_ctx ctx = {};
|
|
|
|
uint32_t sid_func;
|
2020-12-19 03:04:40 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2021-02-24 11:10:06 +01:00
|
|
|
/*
|
|
|
|
* skip when bgp vpn instance ins't allocated
|
2024-05-09 15:45:10 +02:00
|
|
|
* or srv6 locator isn't allocated
|
2021-02-24 11:10:06 +01:00
|
|
|
*/
|
2024-05-09 15:45:10 +02:00
|
|
|
if (!bgp_vpn || !bgp_vpn->srv6_locator)
|
2020-12-19 03:04:40 +01:00
|
|
|
return;
|
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
|
|
|
|
__func__, bgp_vrf->name_pretty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-19 03:04:40 +01:00
|
|
|
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 */
|
2021-08-06 04:51:44 +02:00
|
|
|
if (tovpn_sid_index != 0 && tovpn_sid_auto) {
|
2020-12-19 03:04:40 +01:00
|
|
|
zlog_err("%s: index-mode and auto-mode both selected. ignored.",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
if (!tovpn_sid_auto) {
|
|
|
|
if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
|
|
|
|
tovpn_sid_index)) {
|
|
|
|
zlog_err("%s: failed to compose sid for vrf %s: afi %s",
|
|
|
|
__func__, bgp_vrf->name_pretty, afi2str(afi));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-04-07 09:09:02 +02:00
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
ctx.vrf_id = bgp_vrf->vrf_id;
|
|
|
|
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
|
|
|
|
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
|
|
|
|
if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
|
|
|
|
bgp_vpn->srv6_locator_name, &sid_func)) {
|
|
|
|
zlog_err("%s: failed to request sid for vrf %s: afi %s",
|
|
|
|
__func__, bgp_vrf->name_pretty, afi2str(afi));
|
2020-12-19 03:04:40 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-23 11:49:56 +02:00
|
|
|
void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
2024-03-23 19:24:59 +01:00
|
|
|
struct in6_addr tovpn_sid = {};
|
|
|
|
uint32_t tovpn_sid_index = 0;
|
2022-07-23 11:49:56 +02:00
|
|
|
bool tovpn_sid_auto = false;
|
2024-03-23 19:24:59 +01:00
|
|
|
struct srv6_sid_ctx ctx = {};
|
|
|
|
uint32_t sid_func;
|
2022-07-23 11:49:56 +02:00
|
|
|
|
|
|
|
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
|
2024-05-09 15:45:10 +02:00
|
|
|
* or srv6 locator isn't allocated
|
2022-07-23 11:49:56 +02:00
|
|
|
*/
|
2024-05-09 15:45:10 +02:00
|
|
|
if (!bgp_vpn || !bgp_vpn->srv6_locator)
|
2022-07-23 11:49:56 +02:00
|
|
|
return;
|
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
|
|
|
|
__func__, bgp_vrf->name_pretty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-23 11:49:56 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
if (!tovpn_sid_auto) {
|
|
|
|
if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
|
|
|
|
bgp_vrf->tovpn_sid_index)) {
|
|
|
|
zlog_err("%s: failed to compose new sid for vrf %s",
|
|
|
|
__func__, bgp_vrf->name_pretty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-07-23 11:49:56 +02:00
|
|
|
|
2024-03-23 19:24:59 +01:00
|
|
|
ctx.vrf_id = bgp_vrf->vrf_id;
|
|
|
|
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
|
|
|
|
if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
|
|
|
|
bgp_vpn->srv6_locator_name, &sid_func)) {
|
|
|
|
zlog_err("%s: failed to request new sid for vrf %s", __func__,
|
|
|
|
bgp_vrf->name_pretty);
|
2022-07-23 11:49:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-08-23 16:04:06 +02:00
|
|
|
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;
|
2024-03-23 19:23:52 +01:00
|
|
|
struct srv6_sid_ctx ctx = {};
|
2022-08-23 16:04:06 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2024-03-23 19:23:52 +01:00
|
|
|
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
|
|
|
|
__func__, bgp_vrf->name_pretty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-05-09 15:45:10 +02:00
|
|
|
srv6_locator_free(bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
|
|
|
|
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = NULL;
|
2022-08-23 16:04:06 +02:00
|
|
|
|
|
|
|
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
|
2024-03-23 19:23:52 +01:00
|
|
|
ctx.vrf_id = bgp_vrf->vrf_id;
|
|
|
|
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
|
|
|
|
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
|
|
|
|
bgp_zebra_release_srv6_sid(&ctx);
|
|
|
|
|
2022-12-04 08:53:48 +01:00
|
|
|
sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
|
2022-08-23 16:04:06 +02:00
|
|
|
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;
|
2024-03-23 19:23:52 +01:00
|
|
|
struct srv6_sid_ctx ctx = {};
|
2022-08-23 16:04:06 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2024-03-23 19:23:52 +01:00
|
|
|
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
|
|
|
|
__func__, bgp_vrf->name_pretty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-05-09 15:45:10 +02:00
|
|
|
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
|
|
|
|
bgp_vrf->tovpn_sid_locator = NULL;
|
2022-08-23 16:04:06 +02:00
|
|
|
|
|
|
|
if (bgp_vrf->tovpn_sid) {
|
2024-03-23 19:23:52 +01:00
|
|
|
ctx.vrf_id = bgp_vrf->vrf_id;
|
|
|
|
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
|
|
|
|
bgp_zebra_release_srv6_sid(&ctx);
|
|
|
|
|
2022-12-04 08:53:48 +01:00
|
|
|
sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
|
2022-08-23 16:04:06 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-04-25 10:17:28 +02:00
|
|
|
/*
|
2022-09-21 05:58:18 +02:00
|
|
|
* This function embeds upper `len` bits of `label` in `sid`,
|
|
|
|
* starting at offset `offset` as seen from the MSB of `sid`.
|
2022-04-25 10:17:28 +02:00
|
|
|
*
|
2022-09-21 05:58:18 +02:00
|
|
|
* e.g. Given that `label` is 0x12345 and `len` is 16,
|
|
|
|
* then `label` will be embedded in `sid` as follows:
|
2022-04-25 10:17:28 +02:00
|
|
|
*
|
|
|
|
* <---- len ----->
|
2022-09-21 05:58:18 +02:00
|
|
|
* label: 0001 0002 0003 0004 0005
|
|
|
|
* sid: .... 0001 0002 0003 0004
|
2022-04-25 10:17:28 +02:00
|
|
|
* <---- len ----->
|
|
|
|
* ^
|
|
|
|
* |
|
|
|
|
* offset from MSB
|
2022-09-21 05:58:18 +02:00
|
|
|
*
|
|
|
|
* 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
|
2022-04-25 10:17:28 +02:00
|
|
|
*/
|
2021-08-31 08:31:44 +02:00
|
|
|
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));
|
2022-09-21 05:58:18 +02:00
|
|
|
if (label >> (19 - idx) & 0x1)
|
2021-08-31 08:31:44 +02:00
|
|
|
sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
|
2022-04-27 14:15:13 +02:00
|
|
|
struct attr *new_attr, afi_t afi,
|
|
|
|
safi_t safi,
|
|
|
|
struct bgp_path_info *source_bpi,
|
|
|
|
struct bgp_path_info *bpi,
|
2022-05-05 18:46:35 +02:00
|
|
|
struct bgp *bgp_orig,
|
2022-04-27 14:15:13 +02:00
|
|
|
const struct prefix *p, int debug)
|
|
|
|
{
|
|
|
|
struct bgp_path_info *bpi_ultimate;
|
2022-05-05 18:46:35 +02:00
|
|
|
struct bgp *bgp_nexthop;
|
2022-04-28 17:01:35 +02:00
|
|
|
struct bgp_table *table;
|
2024-11-06 13:52:03 +01:00
|
|
|
struct interface *ifp;
|
2022-04-27 14:15:13 +02:00
|
|
|
bool nh_valid;
|
|
|
|
|
|
|
|
bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
|
2022-04-28 17:01:35 +02:00
|
|
|
table = bgp_dest_table(bpi_ultimate->net);
|
2022-04-27 14:15:13 +02:00
|
|
|
|
2023-08-08 12:47:29 +02:00
|
|
|
if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig)
|
|
|
|
bgp_nexthop = bpi->extra->vrfleak->bgp_orig;
|
2022-05-05 18:46:35 +02:00
|
|
|
else
|
|
|
|
bgp_nexthop = bgp_orig;
|
2022-04-27 14:15:13 +02:00
|
|
|
|
2024-11-06 13:52:03 +01:00
|
|
|
/* The nexthop is invalid if its VRF does not exist */
|
|
|
|
if (bgp_nexthop->vrf_id == VRF_UNKNOWN)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* The nexthop is invalid if its VRF interface is down*/
|
|
|
|
ifp = if_get_vrf_loopback(bgp_nexthop->vrf_id);
|
|
|
|
if (ifp && !if_is_up(ifp))
|
|
|
|
return false;
|
|
|
|
|
2022-04-27 14:15:13 +02:00
|
|
|
/*
|
2023-01-13 11:04:01 +01:00
|
|
|
* No nexthop tracking for redistributed routes, for
|
|
|
|
* EVPN-imported routes that get leaked, or for routes
|
|
|
|
* leaked between VRFs with accept-own community.
|
2022-04-27 14:15:13 +02:00
|
|
|
*/
|
|
|
|
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
|
2023-01-13 11:04:01 +01:00
|
|
|
is_pi_family_evpn(bpi_ultimate) ||
|
|
|
|
CHECK_FLAG(bpi_ultimate->flags, BGP_PATH_ACCEPT_OWN))
|
|
|
|
nh_valid = true;
|
2022-04-28 17:01:35 +02:00
|
|
|
else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table &&
|
|
|
|
(table->safi == SAFI_UNICAST ||
|
2022-04-28 18:32:20 +02:00
|
|
|
table->safi == SAFI_LABELED_UNICAST)) {
|
|
|
|
/* the route is defined with the "network <prefix>" command */
|
|
|
|
|
|
|
|
if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK))
|
bgpd: fix check validity of a VPN SRv6 route with modified nexthop
When exporting a VPN SRv6 route, the path may not be considered valid if
the nexthop is not valid. This is the case when the 'nexthop vpn export'
command is used. The below example illustrates that the VPN path to
2001:1::/64 is not selected, as the expected nexthop to find in vrf10 is
the one configured:
> # show running-config
> router bgp 1 vrf vrf10
> address-family ipv6 unicast
> nexthop vpn export 2001::1
> # show bgp ipv6 vpn
> [..]
> Route Distinguisher: 1:10
> 2001:1::/64 2001::1@4 0 0 65001 i
> UN=2001::1 EC{99:99} label=16 sid=2001:db8:1:1:: sid_structure=[40,24,16,0] type=bgp, subtype=5
The analysis indicates that the 2001::1 nexthop is considered.
> 2025/03/20 21:47:53.751853 BGP: [RD1WY-YE9EC] leak_update: entry: leak-to=VRF default, p=2001:1::/64, type=10, sub_type=0
> 2025/03/20 21:47:53.751855 BGP: [VWNP2-DNMFV] Found existing bnc 2001::1/128(0)(VRF vrf10) flags 0x82 ifindex 0 #paths 2 peer 0x0, resolved prefix UNK prefix
> 2025/03/20 21:47:53.751856 BGP: [VWC2R-4REXZ] leak_update_nexthop_valid: 2001:1::/64 nexthop is not valid (in VRF vrf10)
> 2025/03/20 21:47:53.751857 BGP: [HX87B-ZXWX9] leak_update: ->VRF default: 2001:1::/64: Found route, no change
Actually, to check the nexthop validity, only the source path in the VRF
has the correct nexthop. Fix this by reusing the source path information
instead of the current one.
> 2025/03/20 22:43:51.703521 BGP: [RD1WY-YE9EC] leak_update: entry: leak-to=VRF default, p=2001:1::/64, type=10, sub_type=0
> 2025/03/20 22:43:51.703523 BGP: [VWNP2-DNMFV] Found existing bnc fe80::b812:37ff:fe13:d441/128(0)(VRF vrf10) flags 0x87 ifindex 0 #paths 2 peer 0x0, resolved prefix fe80::/64
> 2025/03/20 22:43:51.703525 BGP: [VWC2R-4REXZ] leak_update_nexthop_valid: 2001:1::/64 nexthop is valid (in VRF vrf10)
> 2025/03/20 22:43:51.703526 BGP: [HX87B-ZXWX9] leak_update: ->VRF default: 2001:1::/64: Found route, no change
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2025-03-20 23:15:30 +01:00
|
|
|
nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, afi, SAFI_UNICAST,
|
|
|
|
bpi_ultimate, NULL, 0, p, bpi_ultimate);
|
2022-04-28 18:32:20 +02:00
|
|
|
else
|
|
|
|
/* if "no bgp network import-check" is set,
|
|
|
|
* then mark the nexthop as valid.
|
|
|
|
*/
|
|
|
|
nh_valid = true;
|
bgpd: fix export, and selects l3vpn aggregated prefix
On a L3VPN setup, an aggretated prefix can not be exported and selected.
The below example illustrates the 172.31.0.0/24 aggregated prefix, which
is valid as a VRF prefix, but invalid as a VPN prefix:
> r1# show bgp ipv4 vpn 172.31.0.0/24
> BGP routing table entry for 444:1:172.31.0.0/24, version 0
> not allocated
> Paths: (1 available, no best path)
> Not advertised to any peer
> Local, (aggregated by 65500 192.0.2.1)
> 0.0.0.0 from 0.0.0.0 (192.0.2.1) vrf vrf1(4) announce-nh-self
> Origin incomplete, metric 0, weight 32768, invalid, sourced,
local, atomic-aggregate
> Extended Community: RT:52:100
> Originator: 192.0.2.1
> Remote label: 101
> Last update: Mon Mar 3 14:35:04 2025
> r1# show bgp vrf vrf1 ipv4 172.31.0.0/24
> BGP routing table entry for 172.31.0.0/24, version 1
> Paths: (1 available, best #1, vrf vrf1)
> Not advertised to any peer
> Local, (aggregated by 65500 192.0.2.1)
> 0.0.0.0 from 0.0.0.0 (192.0.2.1)
> Origin incomplete, metric 0, weight 32768, valid, aggregated,
local, atomic-aggregate, best (First path received)
> Last update: Mon Mar 3 14:35:03 2025
> r1#
Actually, the aggregated prefix nexthop is considered, and 0.0.0.0 is
an invalid nexthop.
> r1# show bgp vrf vrf1 nexthop
> Current BGP nexthop cache:
> 0.0.0.0 invalid, #paths 1
> Is not Registered
> Last update: Thu Feb 13 18:33:43 2025
Fix this by considering the L3VPN prefix selected, if the VRF prefix
is selected too.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2025-03-03 14:40:42 +01:00
|
|
|
} else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
bpi_ultimate->sub_type == BGP_ROUTE_AGGREGATE) {
|
|
|
|
nh_valid = true;
|
2022-04-28 17:01:35 +02:00
|
|
|
} else
|
2022-04-27 14:15:13 +02:00
|
|
|
/*
|
|
|
|
* TBD do we need to do anything about the
|
|
|
|
* 'connected' parameter?
|
|
|
|
*/
|
bgpd: fix check validity of a VPN SRv6 route with modified nexthop
When exporting a VPN SRv6 route, the path may not be considered valid if
the nexthop is not valid. This is the case when the 'nexthop vpn export'
command is used. The below example illustrates that the VPN path to
2001:1::/64 is not selected, as the expected nexthop to find in vrf10 is
the one configured:
> # show running-config
> router bgp 1 vrf vrf10
> address-family ipv6 unicast
> nexthop vpn export 2001::1
> # show bgp ipv6 vpn
> [..]
> Route Distinguisher: 1:10
> 2001:1::/64 2001::1@4 0 0 65001 i
> UN=2001::1 EC{99:99} label=16 sid=2001:db8:1:1:: sid_structure=[40,24,16,0] type=bgp, subtype=5
The analysis indicates that the 2001::1 nexthop is considered.
> 2025/03/20 21:47:53.751853 BGP: [RD1WY-YE9EC] leak_update: entry: leak-to=VRF default, p=2001:1::/64, type=10, sub_type=0
> 2025/03/20 21:47:53.751855 BGP: [VWNP2-DNMFV] Found existing bnc 2001::1/128(0)(VRF vrf10) flags 0x82 ifindex 0 #paths 2 peer 0x0, resolved prefix UNK prefix
> 2025/03/20 21:47:53.751856 BGP: [VWC2R-4REXZ] leak_update_nexthop_valid: 2001:1::/64 nexthop is not valid (in VRF vrf10)
> 2025/03/20 21:47:53.751857 BGP: [HX87B-ZXWX9] leak_update: ->VRF default: 2001:1::/64: Found route, no change
Actually, to check the nexthop validity, only the source path in the VRF
has the correct nexthop. Fix this by reusing the source path information
instead of the current one.
> 2025/03/20 22:43:51.703521 BGP: [RD1WY-YE9EC] leak_update: entry: leak-to=VRF default, p=2001:1::/64, type=10, sub_type=0
> 2025/03/20 22:43:51.703523 BGP: [VWNP2-DNMFV] Found existing bnc fe80::b812:37ff:fe13:d441/128(0)(VRF vrf10) flags 0x87 ifindex 0 #paths 2 peer 0x0, resolved prefix fe80::/64
> 2025/03/20 22:43:51.703525 BGP: [VWC2R-4REXZ] leak_update_nexthop_valid: 2001:1::/64 nexthop is valid (in VRF vrf10)
> 2025/03/20 22:43:51.703526 BGP: [HX87B-ZXWX9] leak_update: ->VRF default: 2001:1::/64: Found route, no change
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2025-03-20 23:15:30 +01:00
|
|
|
/* VPN paths: the new bpi may be altered like
|
|
|
|
* with 'nexthop vpn export' command. Use the bpi_ultimate
|
|
|
|
* to find the original nexthop
|
|
|
|
*/
|
|
|
|
nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p,
|
|
|
|
bpi_ultimate);
|
2022-04-27 14:15:13 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
2025-03-20 16:11:59 +01:00
|
|
|
* If the SID per VRF is not available, also consider the rib as
|
|
|
|
* invalid.
|
2022-04-27 14:15:13 +02:00
|
|
|
*/
|
2025-03-20 16:11:59 +01:00
|
|
|
if (to_bgp->srv6_enabled && nh_valid)
|
|
|
|
nh_valid = is_pi_srv6_valid(bpi, bgp_nexthop, afi, safi);
|
2022-04-27 14:15:13 +02:00
|
|
|
|
|
|
|
if (debug)
|
2023-01-16 20:36:08 +01:00
|
|
|
zlog_debug("%s: %pFX nexthop is %svalid (in %s)", __func__, p,
|
|
|
|
(nh_valid ? "" : "not "), bgp_nexthop->name_pretty);
|
2022-04-27 14:15:13 +02:00
|
|
|
|
|
|
|
return nh_valid;
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
2018-10-03 00:15:34 +02:00
|
|
|
* returns pointer to new bgp_path_info upon success
|
2018-03-09 21:52:55 +01:00
|
|
|
*/
|
2018-10-02 22:41:30 +02:00
|
|
|
static struct bgp_path_info *
|
2022-07-08 12:37:57 +02:00
|
|
|
leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
|
|
|
|
struct attr *new_attr, /* already interned */
|
2018-10-03 02:43:07 +02:00
|
|
|
afi_t afi, safi_t safi, struct bgp_path_info *source_bpi,
|
2024-02-26 18:11:09 +01:00
|
|
|
mpls_label_t *label, uint8_t num_labels, struct bgp *bgp_orig,
|
2022-05-05 14:19:53 +02:00
|
|
|
struct prefix *nexthop_orig, int nexthop_self_flag, int debug)
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
const struct prefix *p = bgp_dest_get_prefix(bn);
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *bpi;
|
2018-10-02 22:41:30 +02:00
|
|
|
struct bgp_path_info *new;
|
2021-09-09 06:51:21 +02:00
|
|
|
struct bgp_path_info_extra *extra;
|
2024-02-26 18:23:11 +01:00
|
|
|
struct bgp_labels bgp_labels = {};
|
2024-11-06 15:25:35 +01:00
|
|
|
struct bgp *bgp_nexthop;
|
2024-02-26 18:23:11 +01:00
|
|
|
bool labelssame;
|
|
|
|
uint8_t i;
|
2021-02-24 11:10:06 +01:00
|
|
|
|
2020-03-22 05:02:18 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
2020-06-23 16:00:41 +02:00
|
|
|
"%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d",
|
2022-07-08 12:37:57 +02:00
|
|
|
__func__, to_bgp->name_pretty, bn, source_bpi->type,
|
2020-03-22 05:02:18 +01:00
|
|
|
source_bpi->sub_type);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-06-24 21:39:03 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
2018-06-24 21:39:03 +02:00
|
|
|
*
|
2018-10-03 02:43:07 +02:00
|
|
|
* As of now, source_bpi may at most be a second-generation route
|
2018-06-24 21:39:03 +02:00
|
|
|
* (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.
|
2018-06-29 23:55:59 +02:00
|
|
|
*
|
2018-06-24 21:39:03 +02:00
|
|
|
*/
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* match parent
|
|
|
|
*/
|
2020-03-27 00:11:58 +01:00
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
|
2024-11-14 15:45:25 +01:00
|
|
|
if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->parent == source_bpi)
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-02-26 18:23:11 +01:00
|
|
|
bgp_labels.num_labels = num_labels;
|
|
|
|
for (i = 0; i < num_labels; i++) {
|
|
|
|
bgp_labels.label[i] = label[i];
|
|
|
|
bgp_set_valid_label(&bgp_labels.label[i]);
|
|
|
|
}
|
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
if (bpi) {
|
2024-02-26 18:23:11 +01:00
|
|
|
labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label,
|
|
|
|
bgp_labels.num_labels);
|
2018-04-11 06:03:05 +02:00
|
|
|
|
2024-11-06 15:25:35 +01:00
|
|
|
bgp_nexthop = bpi->extra->vrfleak->bgp_orig ?: bgp_orig;
|
|
|
|
if (bgp_nexthop->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug) {
|
|
|
|
zlog_debug("%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, origin VRF does not exist, not leaking",
|
|
|
|
__func__, to_bgp->name_pretty, source_bpi->flags,
|
|
|
|
bpi->flags, p);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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",
|
2022-07-08 12:37:57 +02:00
|
|
|
__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;
|
|
|
|
}
|
|
|
|
|
2025-02-11 17:00:25 +01:00
|
|
|
if (labelssame && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) &&
|
|
|
|
attrhash_cmp(bpi->attr, new_attr) &&
|
2024-11-05 15:53:43 +01:00
|
|
|
leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, source_bpi, bpi,
|
|
|
|
bgp_orig, p,
|
|
|
|
debug) == !!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
bgp_attr_unintern(&new_attr);
|
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
2020-06-23 16:00:41 +02:00
|
|
|
"%s: ->%s: %pBD: Found route, no change",
|
2022-07-08 12:37:57 +02:00
|
|
|
__func__, to_bgp->name_pretty, bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-07 21:12:07 +02:00
|
|
|
/* 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))) {
|
2023-02-06 17:40:44 +01:00
|
|
|
vpn_leak_to_vrf_withdraw(bpi);
|
2022-07-08 12:37:57 +02:00
|
|
|
bgp_aggregate_decrement(to_bgp, p, bpi, afi,
|
|
|
|
safi);
|
2022-06-07 21:12:07 +02:00
|
|
|
bgp_path_info_delete(bn, bpi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/* attr is changed */
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ATTR_CHANGED);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
/* Rewrite BGP route information. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
|
|
|
|
bgp_path_info_restore(bn, bpi);
|
2018-03-09 21:52:55 +01:00
|
|
|
else
|
2022-07-08 12:37:57 +02:00
|
|
|
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_attr_unintern(&bpi->attr);
|
|
|
|
bpi->attr = new_attr;
|
2022-08-18 00:27:54 +02:00
|
|
|
bpi->uptime = monotime(NULL);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-04-11 06:03:05 +02:00
|
|
|
/*
|
2024-02-26 18:23:11 +01:00
|
|
|
* update labels
|
2018-04-11 06:03:05 +02:00
|
|
|
*/
|
2024-02-26 18:23:11 +01:00
|
|
|
if (!labelssame) {
|
|
|
|
bgp_path_info_extra_get(bpi);
|
|
|
|
bgp_labels_unintern(&bpi->extra->labels);
|
|
|
|
bpi->extra->labels = bgp_labels_intern(&bgp_labels);
|
|
|
|
}
|
2020-12-19 03:07:16 +01:00
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
if (nexthop_self_flag)
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
|
2018-03-24 00:57:03 +01:00
|
|
|
|
2022-09-18 21:18:13 +02:00
|
|
|
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
|
|
|
|
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN);
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
|
2022-05-05 18:46:35 +02:00
|
|
|
source_bpi, bpi, bgp_orig, p,
|
|
|
|
debug))
|
2022-04-28 17:00:50 +02:00
|
|
|
bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID);
|
|
|
|
else
|
|
|
|
bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID);
|
2018-03-24 00:57:03 +01:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/* Process change. */
|
2022-07-08 12:37:57 +02:00
|
|
|
bgp_aggregate_increment(to_bgp, p, bpi, afi, safi);
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(to_bgp, bn, bpi, afi, safi);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
if (debug)
|
2020-06-23 16:00:41 +02:00
|
|
|
zlog_debug("%s: ->%s: %pBD Found route, changed attr",
|
2022-07-08 12:37:57 +02:00
|
|
|
__func__, to_bgp->name_pretty, bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2023-09-19 21:48:57 +02:00
|
|
|
bgp_dest_unlock_node(bn);
|
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
return bpi;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
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",
|
2022-07-08 12:37:57 +02:00
|
|
|
__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;
|
|
|
|
}
|
|
|
|
|
2024-11-06 15:25:35 +01:00
|
|
|
if (bgp_orig->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug) {
|
|
|
|
zlog_debug("%s: ->%s(s_flags: 0x%x): %pFX: New route, origin VRF does not exist, not leaking",
|
|
|
|
__func__, to_bgp->name_pretty, source_bpi->flags, p);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-12-07 21:55:06 +01:00
|
|
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
|
2022-07-08 12:37:57 +02:00
|
|
|
to_bgp->peer_self, new_attr, bn);
|
2018-03-24 00:57:03 +01:00
|
|
|
|
2023-08-08 12:47:29 +02:00
|
|
|
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));
|
|
|
|
|
2022-08-17 11:52:51 +02:00
|
|
|
if (source_bpi->peer) {
|
|
|
|
extra = bgp_path_info_extra_get(new);
|
2023-08-08 12:47:29 +02:00
|
|
|
extra->vrfleak->peer_orig = peer_lock(source_bpi->peer);
|
2022-08-17 11:52:51 +02:00
|
|
|
}
|
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
if (nexthop_self_flag)
|
2018-10-03 00:15:34 +02:00
|
|
|
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-09-18 21:18:13 +02:00
|
|
|
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
|
|
|
|
bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN);
|
|
|
|
|
2024-02-26 18:23:11 +01:00
|
|
|
if (bgp_labels.num_labels)
|
|
|
|
new->extra->labels = bgp_labels_intern(&bgp_labels);
|
2018-04-11 06:03:05 +02:00
|
|
|
|
2024-11-14 15:45:25 +01:00
|
|
|
new->extra->vrfleak->parent = bgp_path_info_lock(source_bpi);
|
|
|
|
bgp_dest_lock_node((struct bgp_dest *)source_bpi->net);
|
2023-10-12 15:36:45 +02:00
|
|
|
|
|
|
|
new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
if (nexthop_orig)
|
2023-08-08 12:47:29 +02:00
|
|
|
new->extra->vrfleak->nexthop_orig = *nexthop_orig;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
|
2022-05-05 18:46:35 +02:00
|
|
|
source_bpi, new, bgp_orig, p, debug))
|
2022-04-28 17:00:50 +02:00
|
|
|
bgp_path_info_set_flag(bn, new, BGP_PATH_VALID);
|
|
|
|
else
|
|
|
|
bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID);
|
2018-03-24 00:57:03 +01:00
|
|
|
|
2018-10-03 00:15:34 +02:00
|
|
|
bgp_path_info_add(bn, new);
|
2025-01-14 19:29:22 +01:00
|
|
|
bgp_aggregate_increment(to_bgp, p, new, afi, safi);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(to_bgp, bn, new, afi, safi);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
if (debug)
|
2020-06-23 16:00:41 +02:00
|
|
|
zlog_debug("%s: ->%s: %pBD: Added new route", __func__,
|
2022-07-08 12:37:57 +02:00
|
|
|
to_bgp->name_pretty, bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2023-09-10 15:56:53 +02:00
|
|
|
bgp_dest_unlock_node(bn);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
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;
|
|
|
|
|
2023-05-24 17:26:13 +02:00
|
|
|
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;
|
|
|
|
|
2023-05-24 17:26:13 +02:00
|
|
|
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)
|
2023-05-11 15:42:08 +02:00
|
|
|
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
|
|
|
|
2023-05-24 17:26:13 +02: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
|
|
|
|
*/
|
2023-05-24 13:50:37 +02:00
|
|
|
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
|
|
|
|
*/
|
2025-02-10 18:02:00 +01:00
|
|
|
bgp_lp_get(LP_TYPE_NEXTHOP, blnc, from_bgp->vrf_id,
|
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_get_label_per_nexthop_cb);
|
|
|
|
}
|
|
|
|
|
2023-05-24 17:26:13 +02:00
|
|
|
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);
|
2023-05-31 01:44:36 +02:00
|
|
|
|
|
|
|
/* updates NHT pi list reference */
|
2023-05-24 17:26:13 +02:00
|
|
|
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);
|
2023-05-31 01:44:36 +02:00
|
|
|
blnc->last_update = monotime(NULL);
|
2023-02-16 10:39:40 +01:00
|
|
|
|
|
|
|
/* 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,
|
2023-05-11 15:42:08 +02:00
|
|
|
ZEBRA_LSP_BGP, &blnc->nexthop, 0, NULL);
|
2023-02-16 10:39:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-04-09 17:09:39 +02:00
|
|
|
static mpls_label_t bgp_mplsvpn_get_vpn_label(struct vpn_policy *bgp_policy)
|
|
|
|
{
|
|
|
|
if (bgp_policy->tovpn_label == MPLS_LABEL_NONE &&
|
|
|
|
CHECK_FLAG(bgp_policy->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
|
2025-02-10 18:02:00 +01:00
|
|
|
bgp_lp_get(LP_TYPE_VRF, bgp_policy, bgp_policy->bgp->vrf_id,
|
|
|
|
vpn_leak_label_callback);
|
2024-04-09 17:09:39 +02:00
|
|
|
return MPLS_INVALID_LABEL;
|
|
|
|
}
|
|
|
|
return bgp_policy->tovpn_label;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
/* 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.
|
|
|
|
*/
|
2023-05-24 13:50:37 +02:00
|
|
|
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);
|
2024-04-09 17:09:39 +02:00
|
|
|
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2024-04-09 17:09:39 +02:00
|
|
|
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2024-04-09 17:09:39 +02:00
|
|
|
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the next-hop reachability.
|
|
|
|
* Get the bgp instance where the bgp_path_info originates.
|
|
|
|
*/
|
2023-08-08 12:47:29 +02:00
|
|
|
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);
|
bgpd: fix check validity of a VPN SRv6 route with modified nexthop
When exporting a VPN SRv6 route, the path may not be considered valid if
the nexthop is not valid. This is the case when the 'nexthop vpn export'
command is used. The below example illustrates that the VPN path to
2001:1::/64 is not selected, as the expected nexthop to find in vrf10 is
the one configured:
> # show running-config
> router bgp 1 vrf vrf10
> address-family ipv6 unicast
> nexthop vpn export 2001::1
> # show bgp ipv6 vpn
> [..]
> Route Distinguisher: 1:10
> 2001:1::/64 2001::1@4 0 0 65001 i
> UN=2001::1 EC{99:99} label=16 sid=2001:db8:1:1:: sid_structure=[40,24,16,0] type=bgp, subtype=5
The analysis indicates that the 2001::1 nexthop is considered.
> 2025/03/20 21:47:53.751853 BGP: [RD1WY-YE9EC] leak_update: entry: leak-to=VRF default, p=2001:1::/64, type=10, sub_type=0
> 2025/03/20 21:47:53.751855 BGP: [VWNP2-DNMFV] Found existing bnc 2001::1/128(0)(VRF vrf10) flags 0x82 ifindex 0 #paths 2 peer 0x0, resolved prefix UNK prefix
> 2025/03/20 21:47:53.751856 BGP: [VWC2R-4REXZ] leak_update_nexthop_valid: 2001:1::/64 nexthop is not valid (in VRF vrf10)
> 2025/03/20 21:47:53.751857 BGP: [HX87B-ZXWX9] leak_update: ->VRF default: 2001:1::/64: Found route, no change
Actually, to check the nexthop validity, only the source path in the VRF
has the correct nexthop. Fix this by reusing the source path information
instead of the current one.
> 2025/03/20 22:43:51.703521 BGP: [RD1WY-YE9EC] leak_update: entry: leak-to=VRF default, p=2001:1::/64, type=10, sub_type=0
> 2025/03/20 22:43:51.703523 BGP: [VWNP2-DNMFV] Found existing bnc fe80::b812:37ff:fe13:d441/128(0)(VRF vrf10) flags 0x87 ifindex 0 #paths 2 peer 0x0, resolved prefix fe80::/64
> 2025/03/20 22:43:51.703525 BGP: [VWC2R-4REXZ] leak_update_nexthop_valid: 2001:1::/64 nexthop is valid (in VRF vrf10)
> 2025/03/20 22:43:51.703526 BGP: [HX87B-ZXWX9] leak_update: ->VRF default: 2001:1::/64: Found route, no change
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2025-03-20 23:15:30 +01:00
|
|
|
nh_valid = bgp_find_or_add_nexthop(from_bgp, bgp_nexthop, nh_afi, SAFI_UNICAST, pi, NULL, 0,
|
|
|
|
NULL, 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);
|
2024-04-09 17:09:39 +02:00
|
|
|
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2024-04-09 17:09:39 +02:00
|
|
|
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
}
|
|
|
|
|
2024-10-02 14:47:18 +02:00
|
|
|
if (is_bgp_static_route && pi->nexthop->nexthop->type == NEXTHOP_TYPE_IFINDEX) {
|
|
|
|
/* "network" imported prefixes from vrf
|
|
|
|
* fallback to per-vrf label.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bgp_mplsvpn_path_nh_label_unlink(pi);
|
|
|
|
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp,
|
2023-05-24 13:50:37 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */
|
2022-07-08 12:37:57 +02:00
|
|
|
void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
|
|
|
|
struct bgp *from_bgp, /* from */
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *path_vrf) /* route */
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
2020-03-27 00:11:58 +01:00
|
|
|
const struct prefix *p = bgp_dest_get_prefix(path_vrf->net);
|
2018-03-09 21:52:55 +01:00
|
|
|
afi_t afi = family2afi(p->family);
|
|
|
|
struct attr static_attr = {0};
|
|
|
|
struct attr *new_attr = NULL;
|
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
2024-10-22 18:08:13 +02:00
|
|
|
mpls_label_t label_val = { 0 };
|
|
|
|
mpls_label_t label = { 0 };
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2018-03-09 21:52:55 +01:00
|
|
|
const char *debugmsg;
|
2018-03-24 00:57:03 +01:00
|
|
|
int nexthop_self_flag = 0;
|
2023-09-28 17:05:43 +02:00
|
|
|
struct ecommunity *old_ecom;
|
|
|
|
struct ecommunity *new_ecom = NULL;
|
|
|
|
struct ecommunity *rtlist_ecom;
|
2018-03-24 00:57:03 +01:00
|
|
|
|
|
|
|
if (debug)
|
2022-07-08 12:37:57 +02:00
|
|
|
zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
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);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__,
|
2022-07-08 12:37:57 +02:00
|
|
|
from_bgp->name, path_vrf->type, s);
|
2018-03-20 23:57:08 +01:00
|
|
|
XFREE(MTYPE_ECOMMUNITY_STR, s);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (!to_bgp)
|
2018-03-09 21:52:55 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!afi) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: can't get afi of prefix", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-28 09:30:51 +01:00
|
|
|
/* Is this route exportable into the VPN table? */
|
|
|
|
if (!is_route_injectable_into_vpn(path_vrf))
|
2018-03-09 21:52:55 +01:00
|
|
|
return;
|
|
|
|
|
2023-09-28 17:05:43 +02:00
|
|
|
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, false)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
2018-03-19 20:41:17 +01:00
|
|
|
zlog_debug("%s: %s skipping: %s", __func__,
|
2022-07-08 12:37:57 +02:00
|
|
|
from_bgp->name, debugmsg);
|
2018-03-09 21:52:55 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-03-03 17:11:33 +01:00
|
|
|
/* Aggregate-address suppress check. */
|
|
|
|
if (bgp_path_suppressed(path_vrf)) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: %s skipping: suppressed path will not be exported",
|
|
|
|
__func__, from_bgp->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-03 22:01:19 +01:00
|
|
|
/* shallow copy */
|
|
|
|
static_attr = *path_vrf->attr;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
if (debug && bgp_attr_get_ecommunity(&static_attr)) {
|
|
|
|
char *s = ecommunity_ecom2str(
|
|
|
|
bgp_attr_get_ecommunity(&static_attr),
|
|
|
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
zlog_debug("%s: post route map static_attr.ecommunity{%s}",
|
|
|
|
__func__, s);
|
2018-03-20 23:57:08 +01:00
|
|
|
XFREE(MTYPE_ECOMMUNITY_STR, s);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the vpn-policy rt-list
|
|
|
|
*/
|
|
|
|
|
2020-03-18 04:36:05 +01:00
|
|
|
/* Export with the 'from' instance's export RTs. */
|
|
|
|
/* If doing VRF-to-VRF leaking, strip existing RTs first. */
|
2022-02-04 14:56:20 +01:00
|
|
|
old_ecom = bgp_attr_get_ecommunity(&static_attr);
|
2023-09-28 17:05:43 +02:00
|
|
|
rtlist_ecom = from_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN];
|
2018-03-09 21:52:55 +01:00
|
|
|
if (old_ecom) {
|
2020-03-18 04:36:05 +01:00
|
|
|
new_ecom = ecommunity_dup(old_ecom);
|
2022-07-08 12:37:57 +02:00
|
|
|
if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
|
|
|
|
BGP_CONFIG_VRF_TO_VRF_EXPORT))
|
2020-03-18 04:36:05 +01:00
|
|
|
ecommunity_strip_rts(new_ecom);
|
2023-09-28 17:05:43 +02:00
|
|
|
if (rtlist_ecom)
|
|
|
|
new_ecom = ecommunity_merge(new_ecom, rtlist_ecom);
|
2018-03-09 21:52:55 +01:00
|
|
|
if (!old_ecom->refcnt)
|
|
|
|
ecommunity_free(&old_ecom);
|
2023-09-28 17:05:43 +02:00
|
|
|
} else if (rtlist_ecom) {
|
|
|
|
new_ecom = ecommunity_dup(rtlist_ecom);
|
2018-03-09 21:52:55 +01:00
|
|
|
} else {
|
2023-11-20 17:23:05 +01:00
|
|
|
new_ecom = NULL;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
2023-09-28 17:05:43 +02:00
|
|
|
|
2023-11-20 17:23:05 +01:00
|
|
|
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);
|
2023-09-28 17:05:43 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
if (debug && bgp_attr_get_ecommunity(&static_attr)) {
|
|
|
|
char *s = ecommunity_ecom2str(
|
|
|
|
bgp_attr_get_ecommunity(&static_attr),
|
|
|
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
zlog_debug("%s: post merge static_attr.ecommunity{%s}",
|
|
|
|
__func__, s);
|
2018-03-20 23:57:08 +01:00
|
|
|
XFREE(MTYPE_ECOMMUNITY_STR, s);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2022-09-18 21:18:13 +02:00
|
|
|
community_strip_accept_own(&static_attr);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/* Nexthop */
|
|
|
|
/* if policy nexthop not set, use 0 */
|
2022-07-08 12:37:57 +02:00
|
|
|
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
|
2018-03-09 21:52:55 +01:00
|
|
|
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
|
|
|
|
struct prefix *nexthop =
|
2022-07-08 12:37:57 +02:00
|
|
|
&from_bgp->vpn_policy[afi].tovpn_nexthop;
|
2018-03-19 20:41:17 +01:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
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;
|
2019-09-13 10:43:44 +02:00
|
|
|
static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
static_attr.mp_nexthop_global = nexthop->u.prefix6;
|
2019-09-13 10:43:44 +02:00
|
|
|
static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
} else {
|
2022-07-08 12:37:57 +02:00
|
|
|
if (!CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
|
2018-03-19 20:41:17 +01:00
|
|
|
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
|
2022-12-04 15:51:45 +01:00
|
|
|
if (afi == AFI_IP &&
|
|
|
|
!BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
|
2018-04-11 15:40:50 +02:00
|
|
|
/*
|
|
|
|
* For ipv4, copy to multiprotocol
|
|
|
|
* nexthop field
|
|
|
|
*/
|
|
|
|
static_attr.mp_nexthop_global_in =
|
|
|
|
static_attr.nexthop;
|
2019-09-13 10:43:44 +02:00
|
|
|
static_attr.mp_nexthop_len =
|
|
|
|
BGP_ATTR_NHLEN_IPV4;
|
2018-04-11 15:40:50 +02:00
|
|
|
/*
|
|
|
|
* XXX Leave static_attr.nexthop
|
|
|
|
* intact for NHT
|
|
|
|
*/
|
|
|
|
static_attr.flag &=
|
|
|
|
~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
2018-03-19 20:41:17 +01:00
|
|
|
}
|
|
|
|
} else {
|
2018-04-05 19:42:27 +02:00
|
|
|
/* 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.
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (afi == AFI_IP
|
|
|
|
&& !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
|
2018-03-19 20:41:17 +01:00
|
|
|
static_attr.mp_nexthop_global_in.s_addr =
|
|
|
|
static_attr.nexthop.s_addr;
|
2019-09-13 10:43:44 +02:00
|
|
|
static_attr.mp_nexthop_len =
|
|
|
|
BGP_ATTR_NHLEN_IPV4;
|
2018-03-19 20:41:17 +01:00
|
|
|
static_attr.flag |=
|
|
|
|
ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
|
|
|
}
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
2018-03-24 00:57:03 +01:00
|
|
|
nexthop_self_flag = 1;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
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(
|
2023-05-24 13:50:37 +02:00
|
|
|
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
|
2024-04-09 17:09:39 +02:00
|
|
|
label_val =
|
|
|
|
bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[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
|
|
|
|
2024-04-09 17:09:39 +02:00
|
|
|
if (label_val == MPLS_INVALID_LABEL) {
|
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 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);
|
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;
|
|
|
|
}
|
2023-03-19 18:26:41 +01:00
|
|
|
if (label_val == MPLS_LABEL_NONE)
|
2018-04-11 04:03:01 +02:00
|
|
|
encode_label(MPLS_LABEL_IMPLICIT_NULL, &label);
|
2023-03-19 18:26:41 +01:00
|
|
|
else
|
2018-03-09 21:52:55 +01:00
|
|
|
encode_label(label_val, &label);
|
|
|
|
|
|
|
|
/* Set originator ID to "me" */
|
|
|
|
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
|
2022-07-08 12:37:57 +02:00
|
|
|
static_attr.originator_id = to_bgp->router_id;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2020-12-19 03:07:16 +01:00
|
|
|
/* Set SID for SRv6 VPN */
|
2022-07-08 12:37:57 +02:00
|
|
|
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
|
2024-05-09 15:45:10 +02:00
|
|
|
struct srv6_locator *locator =
|
2022-10-27 19:47:11 +02:00
|
|
|
from_bgp->vpn_policy[afi].tovpn_sid_locator;
|
2024-05-09 15:45:10 +02:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
encode_label(
|
|
|
|
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
|
|
|
|
&label);
|
2020-12-19 03:07:16 +01:00
|
|
|
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
|
2020-12-30 02:19:20 +01:00
|
|
|
sizeof(struct bgp_attr_srv6_l3vpn));
|
2020-12-19 03:07:16 +01:00
|
|
|
static_attr.srv6_l3vpn->sid_flags = 0x00;
|
2022-10-27 19:47:11 +02:00
|
|
|
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);
|
2021-08-31 08:13:17 +02:00
|
|
|
static_attr.srv6_l3vpn->loc_block_len =
|
2022-09-20 11:41:55 +02:00
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->block_bits_length;
|
2021-08-31 08:13:17 +02:00
|
|
|
static_attr.srv6_l3vpn->loc_node_len =
|
2022-09-20 11:41:55 +02:00
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->node_bits_length;
|
2021-08-31 08:13:17 +02:00
|
|
|
static_attr.srv6_l3vpn->func_len =
|
2022-09-20 11:41:55 +02:00
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->function_bits_length;
|
2021-08-31 08:13:17 +02:00
|
|
|
static_attr.srv6_l3vpn->arg_len =
|
2022-09-20 11:41:55 +02:00
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->argument_bits_length;
|
2021-08-31 08:13:17 +02:00
|
|
|
static_attr.srv6_l3vpn->transposition_len =
|
2022-09-20 11:41:55 +02:00
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->function_bits_length;
|
2021-08-31 08:13:17 +02:00
|
|
|
static_attr.srv6_l3vpn->transposition_offset =
|
2022-09-20 11:41:55 +02:00
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->block_bits_length +
|
|
|
|
from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->node_bits_length;
|
|
|
|
;
|
2020-12-19 03:07:16 +01:00
|
|
|
memcpy(&static_attr.srv6_l3vpn->sid,
|
2022-09-20 11:41:55 +02:00
|
|
|
&from_bgp->vpn_policy[afi]
|
|
|
|
.tovpn_sid_locator->prefix.prefix,
|
2022-02-25 14:42:32 +01:00
|
|
|
sizeof(struct in6_addr));
|
2022-07-23 11:49:56 +02:00
|
|
|
} else if (from_bgp->tovpn_sid_locator) {
|
2024-05-09 15:45:10 +02:00
|
|
|
struct srv6_locator *locator = from_bgp->tovpn_sid_locator;
|
|
|
|
|
2022-07-23 11:49:56 +02:00
|
|
|
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;
|
2022-10-27 19:47:11 +02:00
|
|
|
static_attr.srv6_l3vpn->endpoint_behavior =
|
|
|
|
CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
|
|
|
|
? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID
|
|
|
|
: SRV6_ENDPOINT_BEHAVIOR_END_DT46;
|
2022-07-23 11:49:56 +02:00
|
|
|
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));
|
2020-12-19 03:07:16 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
new_attr = bgp_attr_intern(
|
|
|
|
&static_attr); /* hashed refcounted everything */
|
|
|
|
bgp_attr_flush(&static_attr); /* free locally-allocated parts */
|
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
if (debug && bgp_attr_get_ecommunity(new_attr)) {
|
|
|
|
char *s = ecommunity_ecom2str(bgp_attr_get_ecommunity(new_attr),
|
2018-03-19 03:12:45 +01:00
|
|
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s);
|
2018-03-19 03:12:45 +01:00
|
|
|
XFREE(MTYPE_ECOMMUNITY_STR, s);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now new_attr is an allocated interned attr */
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p,
|
|
|
|
&(from_bgp->vpn_policy[afi].tovpn_rd));
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-10-02 22:41:30 +02:00
|
|
|
struct bgp_path_info *new_info;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-05-05 14:19:53 +02:00
|
|
|
new_info =
|
2022-07-08 12:37:57 +02:00
|
|
|
leak_update(to_bgp, bn, new_attr, afi, safi, path_vrf, &label,
|
|
|
|
1, from_bgp, NULL, nexthop_self_flag, debug);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
2025-01-08 18:03:55 +01:00
|
|
|
vpn_leak_to_vrf_update(from_bgp, new_info, NULL, path_vrf->peer);
|
2023-03-15 13:52:21 +01:00
|
|
|
else
|
|
|
|
bgp_dest_unlock_node(bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
|
|
|
|
struct bgp *from_bgp, /* from */
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *path_vrf) /* route */
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
2020-03-27 00:11:58 +01:00
|
|
|
const struct prefix *p = bgp_dest_get_prefix(path_vrf->net);
|
2018-03-09 21:52:55 +01:00
|
|
|
afi_t afi = family2afi(p->family);
|
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *bpi;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2018-03-09 21:52:55 +01:00
|
|
|
const char *debugmsg;
|
2018-03-24 00:57:03 +01:00
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
zlog_debug(
|
2020-06-23 16:00:41 +02:00
|
|
|
"%s: entry: leak-from=%s, p=%pBD, type=%d, sub_type=%d",
|
2022-07-08 12:37:57 +02:00
|
|
|
__func__, from_bgp->name_pretty, path_vrf->net,
|
2018-10-03 02:43:07 +02:00
|
|
|
path_vrf->type, path_vrf->sub_type);
|
2018-03-24 00:57:03 +01:00
|
|
|
}
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (!to_bgp)
|
2018-03-09 21:52:55 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!afi) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: can't get afi of prefix", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-28 09:30:51 +01:00
|
|
|
/* Is this route exportable into the VPN table? */
|
|
|
|
if (!is_route_injectable_into_vpn(path_vrf))
|
|
|
|
return;
|
|
|
|
|
2023-09-28 17:05:43 +02:00
|
|
|
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, true)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-28 17:59:22 +02:00
|
|
|
bn = bgp_safi_node_lookup(to_bgp->rib[afi][safi], safi, p,
|
|
|
|
&(from_bgp->vpn_policy[afi].tovpn_rd));
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-07-30 17:40:02 +02:00
|
|
|
if (!bn)
|
|
|
|
return;
|
2023-09-28 17:59:22 +02:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* vrf -> vpn
|
2018-10-03 02:43:07 +02:00
|
|
|
* match original bpi imported from
|
2018-03-09 21:52:55 +01:00
|
|
|
*/
|
2020-03-27 00:11:58 +01:00
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
|
2023-08-08 12:47:29 +02:00
|
|
|
if (bpi->extra && bpi->extra->vrfleak &&
|
|
|
|
bpi->extra->vrfleak->parent == path_vrf) {
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
if (bpi) {
|
2018-03-09 21:52:55 +01:00
|
|
|
/* withdraw from looped vrfs as well */
|
2023-02-06 17:40:44 +01:00
|
|
|
vpn_leak_to_vrf_withdraw(bpi);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_path_info_delete(bn, bpi);
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(to_bgp, bn, bpi, afi, safi);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
|
2018-03-09 21:52:55 +01:00
|
|
|
afi_t afi)
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *pdest;
|
2018-03-09 21:52:55 +01:00
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
|
|
|
|
|
|
|
/*
|
2022-07-08 12:37:57 +02:00
|
|
|
* Walk vpn table, delete bpi with bgp_orig == from_bgp
|
2018-03-09 21:52:55 +01:00
|
|
|
*/
|
2022-07-08 12:37:57 +02:00
|
|
|
for (pdest = bgp_table_top(to_bgp->rib[afi][safi]); pdest;
|
2020-03-27 00:11:58 +01:00
|
|
|
pdest = bgp_route_next(pdest)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
struct bgp_table *table;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2024-03-19 17:26:14 +01:00
|
|
|
struct bgp_path_info *bpi, *next;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
/* This is the per-RD table of prefixes */
|
2020-03-27 00:11:58 +01:00
|
|
|
table = bgp_dest_get_bgp_table_info(pdest);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
|
2020-03-27 00:11:58 +01:00
|
|
|
bpi = bgp_dest_get_bgp_path_info(bn);
|
2018-07-30 17:40:02 +02:00
|
|
|
if (debug && bpi) {
|
2020-06-23 16:00:41 +02:00
|
|
|
zlog_debug("%s: looking at prefix %pBD",
|
2020-03-22 05:02:18 +01:00
|
|
|
__func__, bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2024-03-19 17:26:14 +01:00
|
|
|
for (; (bpi != NULL) && (next = bpi->next, 1);
|
|
|
|
bpi = next) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: type %d, sub_type %d",
|
2018-10-03 02:43:07 +02:00
|
|
|
__func__, bpi->type,
|
|
|
|
bpi->sub_type);
|
|
|
|
if (bpi->sub_type != BGP_ROUTE_IMPORTED)
|
2018-03-09 21:52:55 +01:00
|
|
|
continue;
|
2023-08-08 12:47:29 +02:00
|
|
|
if (!bpi->extra || !bpi->extra->vrfleak)
|
2018-03-09 21:52:55 +01:00
|
|
|
continue;
|
2023-08-08 12:47:29 +02:00
|
|
|
if ((struct bgp *)bpi->extra->vrfleak->bgp_orig ==
|
2022-07-08 12:37:57 +02:00
|
|
|
from_bgp) {
|
2018-03-09 21:52:55 +01:00
|
|
|
/* delete route */
|
|
|
|
if (debug)
|
2019-03-14 19:41:15 +01:00
|
|
|
zlog_debug("%s: deleting it",
|
2018-03-09 21:52:55 +01:00
|
|
|
__func__);
|
2021-03-31 13:32:57 +02:00
|
|
|
/* withdraw from leak-to vrfs as well */
|
2023-02-06 17:40:44 +01:00
|
|
|
vpn_leak_to_vrf_withdraw(bpi);
|
2020-03-22 05:02:18 +01:00
|
|
|
bgp_aggregate_decrement(
|
2022-07-08 12:37:57 +02:00
|
|
|
to_bgp, bgp_dest_get_prefix(bn),
|
|
|
|
bpi, afi, safi);
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_path_info_delete(bn, bpi);
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(to_bgp, bn, bpi, 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(
|
2023-08-08 12:47:29 +02:00
|
|
|
bpi->extra->vrfleak->parent);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
|
2018-03-09 21:52:55 +01:00
|
|
|
afi_t afi)
|
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *bpi;
|
2018-03-09 21:52:55 +01:00
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
|
2022-07-08 12:37:57 +02:00
|
|
|
from_bgp->name_pretty);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
for (bn = bgp_table_top(from_bgp->rib[afi][SAFI_UNICAST]); bn;
|
2018-03-09 21:52:55 +01:00
|
|
|
bn = bgp_route_next(bn)) {
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: node=%p", __func__, bn);
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
|
2018-07-30 17:40:02 +02:00
|
|
|
bpi = bpi->next) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: calling vpn_leak_from_vrf_update",
|
|
|
|
__func__);
|
2022-07-08 12:37:57 +02:00
|
|
|
vpn_leak_from_vrf_update(to_bgp, from_bgp, bpi);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-18 21:18:13 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-01-08 18:03:55 +01:00
|
|
|
static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
|
2022-09-18 21:18:13 +02:00
|
|
|
struct bgp *from_bgp, /* from */
|
2025-01-08 18:03:55 +01:00
|
|
|
struct bgp_path_info *path_vpn, struct prefix_rd *prd,
|
|
|
|
struct peer *from)
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
|
2018-03-09 21:52:55 +01:00
|
|
|
afi_t afi = family2afi(p->family);
|
|
|
|
|
|
|
|
struct attr static_attr = {0};
|
|
|
|
struct attr *new_attr = NULL;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2018-03-09 21:52:55 +01:00
|
|
|
safi_t safi = SAFI_UNICAST;
|
|
|
|
const char *debugmsg;
|
|
|
|
struct prefix nexthop_orig;
|
2024-02-26 10:42:42 +01:00
|
|
|
mpls_label_t *label_pnt = NULL;
|
2024-02-26 18:11:09 +01:00
|
|
|
uint8_t num_labels = 0;
|
2018-03-24 00:57:03 +01:00
|
|
|
int nexthop_self_flag = 1;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *bpi_ultimate = NULL;
|
2022-04-29 14:26:04 +02:00
|
|
|
struct bgp_path_info *bpi;
|
2018-04-11 19:58:03 +02:00
|
|
|
int origin_local = 0;
|
2018-04-22 05:04:29 +02:00
|
|
|
struct bgp *src_vrf;
|
2022-04-26 16:57:45 +02:00
|
|
|
struct interface *ifp = NULL;
|
2022-11-22 09:57:10 +01:00
|
|
|
char rd_buf[RD_ADDRSTRLEN];
|
2021-06-09 22:50:20 +02:00
|
|
|
struct aspath *new_aspath;
|
2024-12-08 20:46:59 +01:00
|
|
|
int32_t aspath_loop_count = 0;
|
|
|
|
struct peer *peer = path_vpn->peer;
|
2022-04-26 16:57:45 +02:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
2023-02-06 17:41:19 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: from vpn (%s) to vrf (%s), skipping: %s",
|
|
|
|
__func__, from_bgp->name_pretty,
|
|
|
|
to_bgp->name_pretty, debugmsg);
|
2023-06-06 14:02:42 +02:00
|
|
|
return;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 11:04:01 +01:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2023-08-08 12:47:29 +02:00
|
|
|
if (path_vpn->extra && path_vpn->extra->vrfleak &&
|
|
|
|
path_vpn->extra->vrfleak->bgp_orig)
|
|
|
|
src_vrf = path_vpn->extra->vrfleak->bgp_orig;
|
2023-01-13 11:04:01 +01:00
|
|
|
else if (src_bgp)
|
|
|
|
src_vrf = src_bgp;
|
|
|
|
else
|
|
|
|
src_vrf = from_bgp;
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/* Check for intersection of route targets */
|
2022-08-19 11:50:29 +02:00
|
|
|
if (!ecommunity_include(
|
2022-07-08 12:37:57 +02:00
|
|
|
to_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_get_ecommunity(path_vpn->attr))) {
|
2021-04-01 07:39:57 +02:00
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
2022-06-07 21:24:40 +02:00
|
|
|
"from vpn (%s) to vrf (%s), skipping after no intersection of route targets",
|
2022-07-08 12:37:57 +02:00
|
|
|
from_bgp->name_pretty, to_bgp->name_pretty);
|
2023-06-06 14:02:42 +02:00
|
|
|
return;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2023-02-10 18:12:48 +01:00
|
|
|
rd_buf[0] = '\0';
|
|
|
|
if (debug && prd)
|
2022-11-22 09:57:10 +01:00
|
|
|
prefix_rd2str(prd, rd_buf, sizeof(rd_buf), to_bgp->asnotation);
|
|
|
|
|
2022-09-18 21:18:13 +02:00
|
|
|
/* 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) {
|
2022-09-18 21:18:13 +02:00
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
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);
|
2023-06-06 14:02:42 +02:00
|
|
|
return;
|
2022-09-18 21:18:13 +02:00
|
|
|
}
|
|
|
|
|
2021-06-09 22:50:20 +02:00
|
|
|
bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
|
|
|
|
|
|
|
|
/* Check if leaked route has our asn. If so, don't import it. */
|
2024-12-08 20:46:59 +01:00
|
|
|
if (CHECK_FLAG(peer->af_flags[afi][SAFI_MPLS_VPN], PEER_FLAG_ALLOWAS_IN))
|
|
|
|
aspath_loop_count = peer->allowas_in[afi][SAFI_MPLS_VPN];
|
2025-01-08 18:03:55 +01:00
|
|
|
else if (peer == peer->bgp->peer_self && from)
|
|
|
|
/* If this is an import from one VRF to another and the source
|
|
|
|
* VRF's peer has allowas-in applied, respect it.
|
|
|
|
*/
|
|
|
|
aspath_loop_count = from->allowas_in[afi][SAFI_UNICAST];
|
|
|
|
|
2024-12-08 20:46:59 +01:00
|
|
|
if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as) > aspath_loop_count) {
|
2021-06-09 22:50:20 +02:00
|
|
|
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: blocking import of %p, as-path match",
|
|
|
|
__func__, bpi);
|
|
|
|
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
|
|
|
|
bgp_path_info_delete(bn, bpi);
|
|
|
|
bgp_process(to_bgp, bn, bpi, afi, safi);
|
|
|
|
}
|
|
|
|
bgp_dest_unlock_node(bn);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-18 13:33:54 +02:00
|
|
|
if (debug)
|
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);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2019-12-03 22:01:19 +01:00
|
|
|
/* shallow copy */
|
|
|
|
static_attr = *path_vpn->attr;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2020-03-18 04:36:05 +01:00
|
|
|
struct ecommunity *old_ecom;
|
|
|
|
struct ecommunity *new_ecom;
|
|
|
|
|
|
|
|
/* If doing VRF-to-VRF leaking, strip RTs. */
|
2022-02-04 14:56:20 +01:00
|
|
|
old_ecom = bgp_attr_get_ecommunity(&static_attr);
|
2022-07-08 12:37:57 +02:00
|
|
|
if (old_ecom && CHECK_FLAG(to_bgp->af_flags[afi][safi],
|
|
|
|
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
|
2020-03-18 04:36:05 +01:00
|
|
|
new_ecom = ecommunity_dup(old_ecom);
|
|
|
|
ecommunity_strip_rts(new_ecom);
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(&static_attr, new_ecom);
|
2020-06-08 20:05:40 +02:00
|
|
|
|
|
|
|
if (new_ecom->size == 0) {
|
|
|
|
ecommunity_free(&new_ecom);
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(&static_attr, NULL);
|
2020-06-08 20:05:40 +02:00
|
|
|
}
|
|
|
|
|
2020-03-18 04:36:05 +01:00
|
|
|
if (!old_ecom->refcnt)
|
|
|
|
ecommunity_free(&old_ecom);
|
|
|
|
}
|
|
|
|
|
2022-09-18 21:18:13 +02:00
|
|
|
community_strip_accept_own(&static_attr);
|
|
|
|
|
2022-04-29 14:26:04 +02:00
|
|
|
bn = bgp_afi_node_get(to_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 &&
|
|
|
|
bpi->extra->vrfleak->parent == path_vpn)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-03-20 16:11:59 +01:00
|
|
|
if (bpi && leak_update_nexthop_valid(to_bgp, bn, &static_attr, afi, safi, path_vpn, bpi,
|
|
|
|
src_vrf, p, debug))
|
2022-04-29 14:26:04 +02:00
|
|
|
SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
memset(&nexthop_orig, 0, sizeof(nexthop_orig));
|
|
|
|
nexthop_orig.family = nhfamily;
|
|
|
|
|
2023-01-13 11:04:01 +01:00
|
|
|
/* 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.
|
bgpd: fix interface on leaks from network statement
Leaked routes from prefixes defined with 'network <prefix>' are inactive
because they have no valid nexthop interface.
> vrf r1-cust1
> ip route 172.16.29.0/24 192.168.1.2
> router bgp 5227 vrf r1-cust1
> no bgp network import-check
> address-family ipv4 unicast
> network 172.16.29.0/24
> rd vpn export 10:1
> rt vpn import 52:100
> rt vpn export 52:101
> export vpn
> import vpn
> exit-address-family
> exit
> !
> router bgp 5227 vrf r1-cust4
> bgp router-id 192.168.1.1
> !
> address-family ipv4 unicast
> network 192.0.2/24
> rd vpn export 10:1
> rt vpn import 52:101
> rt vpn export 52:100
> export vpn
> import vpn
> exit-address-family
> exit
Extract from the routing table:
> VRF r1-cust1:
> S>* 172.16.29.0/24 [1/0] via 192.168.1.2, r1-eth4, weight 1, 00:47:53
>
> VRF r1-cust4:
> B 172.16.29.0/24 [20/0] is directly connected, unknown (vrf r1-cust1) inactive, weight 1, 00:03:40
Routes imported through the "network" command, as opposed to those
redistributed from the routing table, do not associate with any specific
interface.
When leaking prefix from other VRFs, if the route was imported from the
network statement (ie. static sub-type), set nh_ifindex to the index of
the VRF master interface of the incoming BGP instance.
The result is:
> VRF r1-cust4:
> B>* 172.16.29.0/24 [20/0] is directly connected, r1-cust1 (vrf r1-cust1), weight 1, 00:00:08
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2022-04-25 15:14:49 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (src_bgp)
|
|
|
|
subgroup_announce_reset_nhop(nhfamily, &static_attr);
|
|
|
|
|
|
|
|
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
|
|
|
|
|
|
|
|
/* The nh ifindex may not be defined (when the route is
|
|
|
|
* imported from the network statement => BGP_ROUTE_STATIC)
|
|
|
|
* or to the real interface.
|
|
|
|
* Rewrite the nh ifindex to VRF's interface.
|
2023-01-15 11:43:37 +01:00
|
|
|
* Let the kernel to decide with double lookup the real next-hop
|
|
|
|
* interface when installing the route.
|
2023-01-13 11:04:01 +01:00
|
|
|
*/
|
bgpd, tests: fix route leaking from the default l3vrf
Leaked route from the l3VRF are installed with the loopback as the
nexthop interface instead of the real interface.
> B>* 10.0.0.0/30 [20/0] is directly connected, lo (vrf default), weight 1, 00:21:01
Routing of packet from a L3VRF to the default L3VRF destined to a leak
prefix fails because of the default routing rules on Linux.
> 0: from all lookup local
> 1000: from all lookup [l3mdev-table]
> 32766: from all lookup main
> 32767: from all lookup default
When the packet is received in the loopback interface, the local rules
are checked without match, then the l3mdev-table says to route to the
loopback. A routing loop occurs (TTL is decreasing).
> 12:26:27.928748 ens37 In IP (tos 0x0, ttl 64, id 26402, offset 0, flags [DF], proto ICMP (1), length 84)
> 10.0.0.2 > 10.0.1.2: ICMP echo request, id 47463, seq 1, length 64
> 12:26:27.928784 red Out IP (tos 0x0, ttl 63, id 26402, offset 0, flags [DF], proto ICMP (1), length 84)
> 10.0.0.2 > 10.0.1.2: ICMP echo request, id 47463, seq 1, length 64
> 12:26:27.928797 ens38 Out IP (tos 0x0, ttl 63, id 26402, offset 0, flags [DF], proto ICMP (1), length 84)
> 10.0.0.2 > 10.0.1.2: ICMP echo request, id 47463, seq 1, length 64
Do not set the lo interface as a nexthop interface. Keep the real
interface where possible.
Fixes: db7cf73a33 ("bgpd: fix interface on leaks from redistribute connected")
Fixes: 067fbab4e4 ("bgpd: fix interface on leaks from network statement")
Fixes: 8a02d9fe1e ("bgpd: Set nh ifindex to VRF's interface, not the real")
Fixes: https://github.com/FRRouting/frr/issues/15909
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-05-17 17:57:46 +02:00
|
|
|
if (src_vrf->vrf_id != VRF_DEFAULT &&
|
|
|
|
(src_bgp || bpi_ultimate->sub_type == BGP_ROUTE_STATIC ||
|
|
|
|
bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)) {
|
2023-01-15 11:43:37 +01:00
|
|
|
ifp = if_get_vrf_loopback(src_vrf->vrf_id);
|
|
|
|
if (ifp)
|
|
|
|
static_attr.nh_ifindex = ifp->ifindex;
|
|
|
|
}
|
2023-01-13 11:04:01 +01:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
switch (nhfamily) {
|
|
|
|
case AF_INET:
|
|
|
|
/* save */
|
2018-10-03 02:43:07 +02:00
|
|
|
nexthop_orig.u.prefix4 = path_vpn->attr->mp_nexthop_global_in;
|
2021-07-01 17:05:11 +02:00
|
|
|
nexthop_orig.prefixlen = IPV4_MAX_BITLEN;
|
2018-03-19 20:41:17 +01:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
|
2018-03-19 20:41:17 +01:00
|
|
|
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
|
|
|
|
static_attr.nexthop.s_addr =
|
|
|
|
nexthop_orig.u.prefix4.s_addr;
|
|
|
|
|
|
|
|
static_attr.mp_nexthop_global_in =
|
2018-10-03 02:43:07 +02:00
|
|
|
path_vpn->attr->mp_nexthop_global_in;
|
2018-03-19 20:41:17 +01:00
|
|
|
static_attr.mp_nexthop_len =
|
2018-10-03 02:43:07 +02:00
|
|
|
path_vpn->attr->mp_nexthop_len;
|
2018-03-19 20:41:17 +01:00
|
|
|
}
|
2019-02-26 22:22:10 +01:00
|
|
|
static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
/* save */
|
2018-10-03 02:43:07 +02:00
|
|
|
nexthop_orig.u.prefix6 = path_vpn->attr->mp_nexthop_global;
|
2021-07-01 16:53:21 +02:00
|
|
|
nexthop_orig.prefixlen = IPV6_MAX_BITLEN;
|
2018-03-19 20:41:17 +01:00
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
|
2018-03-19 20:41:17 +01:00
|
|
|
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
|
|
|
|
static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
|
|
|
|
}
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-04-26 16:57:45 +02:00
|
|
|
if (!ifp && static_attr.nh_ifindex)
|
|
|
|
ifp = if_lookup_by_index(static_attr.nh_ifindex,
|
|
|
|
src_vrf->vrf_id);
|
|
|
|
|
|
|
|
if (ifp && if_is_operative(ifp))
|
|
|
|
SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* route map handling
|
|
|
|
*/
|
2022-07-08 12:37:57 +02:00
|
|
|
if (to_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
|
2018-10-02 22:41:30 +02:00
|
|
|
struct bgp_path_info info;
|
2018-03-09 21:52:55 +01:00
|
|
|
route_map_result_t ret;
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
2022-07-08 12:37:57 +02:00
|
|
|
info.peer = to_bgp->peer_self;
|
2018-03-09 21:52:55 +01:00
|
|
|
info.attr = &static_attr;
|
2019-02-15 03:07:27 +01:00
|
|
|
info.extra = path_vpn->extra; /* Used for source-vrf filter */
|
2022-07-08 12:37:57 +02:00
|
|
|
ret = route_map_apply(to_bgp->vpn_policy[afi]
|
2018-03-09 21:52:55 +01:00
|
|
|
.rmap[BGP_VPN_POLICY_DIR_FROMVPN],
|
2020-11-14 01:35:20 +01:00
|
|
|
p, &info);
|
2018-03-09 21:52:55 +01:00
|
|
|
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",
|
2022-07-08 12:37:57 +02:00
|
|
|
__func__, to_bgp->name_pretty,
|
|
|
|
to_bgp->vpn_policy[afi]
|
2018-03-09 21:52:55 +01:00
|
|
|
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
|
|
|
|
->name);
|
2023-06-06 14:02:42 +02:00
|
|
|
return;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
2018-03-24 00:57:03 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2021-06-09 22:50:20 +02:00
|
|
|
/*
|
|
|
|
* if the asn values are different, copy the asn of the source vrf
|
|
|
|
* into the entry before importing. This helps with as-path loop
|
|
|
|
* detection
|
|
|
|
*/
|
|
|
|
if (path_vpn->extra && path_vpn->extra->vrfleak &&
|
2021-07-19 16:29:42 +02:00
|
|
|
path_vpn->extra->vrfleak->bgp_orig &&
|
2021-06-09 22:50:20 +02:00
|
|
|
(to_bgp->as != path_vpn->extra->vrfleak->bgp_orig->as)) {
|
|
|
|
new_aspath = aspath_dup(static_attr.aspath);
|
|
|
|
new_aspath =
|
|
|
|
aspath_add_seq(new_aspath,
|
|
|
|
path_vpn->extra->vrfleak->bgp_orig->as);
|
|
|
|
static_attr.aspath = new_aspath;
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
new_attr = bgp_attr_intern(&static_attr);
|
|
|
|
bgp_attr_flush(&static_attr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ensure labels are copied
|
2018-04-11 19:58:03 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2018-03-09 21:52:55 +01:00
|
|
|
*/
|
2022-07-08 12:37:57 +02:00
|
|
|
if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
|
2018-03-19 20:41:17 +01:00
|
|
|
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
|
|
|
|
/*
|
|
|
|
* if original route was unicast,
|
|
|
|
* then it did not arrive over vpn
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (bpi_ultimate->net) {
|
2018-03-19 20:41:17 +01:00
|
|
|
struct bgp_table *table;
|
2018-04-11 19:58:03 +02:00
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
table = bgp_dest_table(bpi_ultimate->net);
|
2018-03-19 20:41:17 +01:00
|
|
|
if (table && (table->safi == SAFI_UNICAST))
|
|
|
|
origin_local = 1;
|
|
|
|
}
|
2018-04-11 19:58:03 +02:00
|
|
|
|
2024-02-26 10:42:42 +01:00
|
|
|
num_labels = origin_local ? 0
|
2024-08-26 10:23:12 +02:00
|
|
|
: BGP_PATH_INFO_NUM_LABELS(path_vpn);
|
2024-02-26 18:23:11 +01:00
|
|
|
label_pnt = num_labels ? path_vpn->extra->labels->label : NULL;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
2018-04-11 19:58:03 +02:00
|
|
|
|
2020-03-22 05:02:18 +01:00
|
|
|
if (debug)
|
2020-06-23 16:00:41 +02:00
|
|
|
zlog_debug("%s: pfx %pBD: num_labels %d", __func__,
|
2020-03-22 05:02:18 +01:00
|
|
|
path_vpn->net, num_labels);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2024-02-26 10:42:42 +01:00
|
|
|
if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, label_pnt,
|
2023-03-15 13:52:21 +01:00
|
|
|
num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
|
|
|
|
debug))
|
|
|
|
bgp_dest_unlock_node(bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2023-06-06 12:46:21 +02:00
|
|
|
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));
|
2023-03-15 13:52:21 +01:00
|
|
|
|
2022-07-01 14:50:40 +02:00
|
|
|
return true;
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
2025-01-08 18:03:55 +01:00
|
|
|
void vpn_leak_to_vrf_update(struct bgp *from_bgp, struct bgp_path_info *path_vpn,
|
|
|
|
struct prefix_rd *prd, struct peer *peer)
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
|
|
|
struct listnode *mnode, *mnnode;
|
|
|
|
struct bgp *bgp;
|
2024-12-08 20:48:14 +01:00
|
|
|
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
|
|
|
if (debug)
|
2024-12-08 20:48:14 +01:00
|
|
|
zlog_debug("%s: start (path_vpn=%p, prefix=%pFX)", __func__, path_vpn, p);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
/* Loop over VRFs */
|
|
|
|
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
|
2023-08-08 12:47:29 +02:00
|
|
|
if (!path_vpn->extra || !path_vpn->extra->vrfleak ||
|
|
|
|
path_vpn->extra->vrfleak->bgp_orig != bgp) { /* no loop */
|
2025-01-08 18:03:55 +01:00
|
|
|
vpn_leak_to_vrf_update_onevrf(bgp, from_bgp, path_vpn, prd, peer);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-06 17:40:44 +01:00
|
|
|
void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn)
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
2020-03-22 05:02:18 +01:00
|
|
|
const struct prefix *p;
|
2018-03-22 02:20:39 +01:00
|
|
|
afi_t afi;
|
2018-03-09 21:52:55 +01:00
|
|
|
safi_t safi = SAFI_UNICAST;
|
|
|
|
struct bgp *bgp;
|
|
|
|
struct listnode *mnode, *mnnode;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *bpi;
|
2018-03-09 21:52:55 +01:00
|
|
|
const char *debugmsg;
|
|
|
|
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
2020-03-22 05:02:18 +01:00
|
|
|
if (debug)
|
2020-06-23 16:00:41 +02:00
|
|
|
zlog_debug("%s: entry: p=%pBD, type=%d, sub_type=%d", __func__,
|
2020-03-22 05:02:18 +01:00
|
|
|
path_vpn->net, path_vpn->type, path_vpn->sub_type);
|
2018-03-24 00:57:03 +01:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
2018-10-03 02:43:07 +02:00
|
|
|
zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!path_vpn->net) {
|
2020-04-01 21:05:26 +02:00
|
|
|
#ifdef ENABLE_BGP_VNC
|
2018-10-03 02:43:07 +02:00
|
|
|
/* 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) {
|
2018-03-22 02:20:39 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2018-03-22 05:18:25 +01:00
|
|
|
#endif
|
2018-03-22 02:20:39 +01:00
|
|
|
if (debug)
|
2018-10-03 02:43:07 +02:00
|
|
|
zlog_debug(
|
|
|
|
"%s: path_vpn->net unexpectedly NULL, no prefix, bailing",
|
2018-03-22 02:20:39 +01:00
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
p = bgp_dest_get_prefix(path_vpn->net);
|
2018-03-22 02:20:39 +01:00
|
|
|
afi = family2afi(p->family);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
/* Loop over VRFs */
|
|
|
|
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
|
2018-03-16 19:11:37 +01:00
|
|
|
if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
2023-02-06 17:41:19 +01:00
|
|
|
zlog_debug("%s: from %s, skipping: %s",
|
|
|
|
__func__, bgp->name_pretty,
|
2018-03-09 21:52:55 +01:00
|
|
|
debugmsg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for intersection of route targets */
|
2022-08-19 11:50:29 +02:00
|
|
|
if (!ecommunity_include(
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
|
|
|
|
bgp_attr_get_ecommunity(path_vpn->attr))) {
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: withdrawing from vrf %s", __func__,
|
2018-03-24 00:57:03 +01:00
|
|
|
bgp->name_pretty);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, NULL);
|
2018-07-30 17:40:02 +02:00
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
|
2018-07-30 17:40:02 +02:00
|
|
|
bpi = bpi->next) {
|
2023-08-08 12:47:29 +02:00
|
|
|
if (bpi->extra && bpi->extra->vrfleak &&
|
|
|
|
(struct bgp_path_info *)bpi->extra->vrfleak->parent ==
|
|
|
|
path_vpn) {
|
2018-03-09 21:52:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
if (bpi) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
2018-10-03 02:43:07 +02:00
|
|
|
zlog_debug("%s: deleting bpi %p", __func__,
|
|
|
|
bpi);
|
|
|
|
bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
|
|
|
|
bgp_path_info_delete(bn, bpi);
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, bn, bpi, afi, safi);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(bn);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2024-03-19 17:26:14 +01:00
|
|
|
struct bgp_path_info *bpi, *next;
|
2018-03-09 21:52:55 +01:00
|
|
|
safi_t safi = SAFI_UNICAST;
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: entry", __func__);
|
|
|
|
/*
|
2018-10-03 02:43:07 +02:00
|
|
|
* Walk vrf table, delete bpi with bgp_orig in a different vrf
|
2018-03-09 21:52:55 +01:00
|
|
|
*/
|
2022-07-08 12:37:57 +02:00
|
|
|
for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn;
|
2018-03-09 21:52:55 +01:00
|
|
|
bn = bgp_route_next(bn)) {
|
2024-03-19 17:26:14 +01:00
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn);
|
|
|
|
(bpi != NULL) && (next = bpi->next, 1); bpi = next) {
|
2023-08-08 12:47:29 +02:00
|
|
|
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)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
/* delete route */
|
2022-07-08 12:37:57 +02:00
|
|
|
bgp_aggregate_decrement(to_bgp,
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_get_prefix(bn),
|
2020-03-22 05:02:18 +01:00
|
|
|
bpi, afi, safi);
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_path_info_delete(bn, bpi);
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(to_bgp, bn, bpi, afi, safi);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-07 12:46:30 +02:00
|
|
|
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)) {
|
2024-03-19 17:26:14 +01:00
|
|
|
struct bgp_path_info *next;
|
|
|
|
|
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn);
|
|
|
|
(bpi != NULL) && (next = bpi->next, 1);
|
|
|
|
bpi = next) {
|
2023-08-08 12:47:29 +02:00
|
|
|
if (bpi->extra && bpi->extra->vrfleak &&
|
|
|
|
bpi->extra->vrfleak->bgp_orig == to_bgp)
|
2023-06-07 12:46:30 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
|
2018-03-09 21:52:55 +01:00
|
|
|
afi_t afi)
|
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *pdest;
|
2018-03-09 21:52:55 +01:00
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
|
|
|
|
2022-07-08 12:37:57 +02:00
|
|
|
assert(vpn_from);
|
bgpd: vpn null check
Can be reproduced with following vtysh sequence (an intentionaly wrong
sequence):
['configure terminal\n router bgp 255 vrf l3vrf-6\n',
'configure terminal\n router bgp 255 vrf l3vrf-6\nbgp router-id 10.255.255.1\n',
'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nlabel vpn export 45000\n',
'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nrd vpn export 255:5\n',
'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nredistribute isis\n', 'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nredistribute ospf\n', 'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nredistribute connected\n', 'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nimport vpn\n', 'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nexport vpn\n', 'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nrt vpn import 255:1\n', 'configure terminal\n router bgp 255 vrf l3vrf-6\n address-family ipv4\nrt vpn export 255:1\n'
]
Signed-off-by: F. Aragon <paco@voltanet.io>
2018-06-18 15:52:57 +02:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* Walk vpn table
|
|
|
|
*/
|
2022-07-08 12:37:57 +02:00
|
|
|
for (pdest = bgp_table_top(vpn_from->rib[afi][safi]); pdest;
|
2020-03-27 00:11:58 +01:00
|
|
|
pdest = bgp_route_next(pdest)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
struct bgp_table *table;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *bn;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *bpi;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
/* This is the per-RD table of prefixes */
|
2020-03-27 00:11:58 +01:00
|
|
|
table = bgp_dest_get_bgp_table_info(pdest);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
|
2018-07-30 17:40:02 +02:00
|
|
|
bpi = bpi->next) {
|
2023-08-08 12:47:29 +02:00
|
|
|
if (bpi->extra && bpi->extra->vrfleak &&
|
|
|
|
bpi->extra->vrfleak->bgp_orig == to_bgp)
|
2018-03-09 21:52:55 +01:00
|
|
|
continue;
|
|
|
|
|
2025-01-08 18:03:55 +01:00
|
|
|
vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from, bpi, NULL,
|
|
|
|
bpi->peer);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-18 07:30:38 +02:00
|
|
|
/*
|
|
|
|
* This function is called for definition/deletion/change to a route-map
|
|
|
|
*/
|
2018-03-09 21:52:55 +01:00
|
|
|
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) {
|
|
|
|
|
2018-04-18 07:30:38 +02:00
|
|
|
if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]
|
|
|
|
&& !strcmp(rmap_name,
|
2018-03-09 21:52:55 +01:00
|
|
|
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__);
|
|
|
|
|
2018-04-18 07:30:38 +02:00
|
|
|
/* in case of definition/deletion */
|
|
|
|
bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] =
|
|
|
|
rmap;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
|
|
|
|
bgp_get_default(), bgp);
|
2018-04-18 07:30:38 +02:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: after vpn_leak_postchange",
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
|
2018-04-18 07:30:38 +02:00
|
|
|
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])) {
|
2018-03-16 19:11:37 +01:00
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s",
|
2018-03-09 21:52:55 +01:00
|
|
|
__func__, rmap_name, bgp->as,
|
|
|
|
afi2str(afi));
|
2018-03-16 19:11:37 +01:00
|
|
|
}
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
|
|
|
|
bgp_get_default(), bgp);
|
|
|
|
|
2018-04-18 07:30:38 +02:00
|
|
|
/* in case of definition/deletion */
|
|
|
|
bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
|
|
|
|
rmap;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
|
|
|
|
bgp_get_default(), bgp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
/* This API is used during router-id change, reflect VPNs
|
|
|
|
* auto RD and RT values and readvertise routes to VPN table.
|
|
|
|
*/
|
2019-06-11 19:47:15 +02:00
|
|
|
void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
|
|
|
|
bool is_config)
|
2019-03-08 06:26:14 +01:00
|
|
|
{
|
|
|
|
afi_t afi;
|
2021-04-01 07:39:57 +02:00
|
|
|
int debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)
|
|
|
|
| BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
|
2019-03-08 06:26:14 +01:00
|
|
|
char *vname;
|
|
|
|
const char *export_name;
|
|
|
|
char buf[RD_ADDRSTRLEN];
|
|
|
|
struct bgp *bgp_import;
|
|
|
|
struct listnode *node;
|
|
|
|
struct ecommunity *ecom;
|
2022-04-12 10:34:27 +02:00
|
|
|
enum vpn_policy_direction idir, edir;
|
2019-03-08 06:26:14 +01:00
|
|
|
|
2021-04-01 07:39:57 +02:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
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) {
|
2023-09-28 17:05:43 +02:00
|
|
|
if (!vpn_leak_to_vpn_active(bgp, afi, NULL, false))
|
2019-03-08 06:26:14 +01:00
|
|
|
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)) {
|
2019-09-17 03:28:44 +02:00
|
|
|
if (strcmp(vname, VRF_DEFAULT_NAME) == 0)
|
|
|
|
bgp_import = bgp_get_default();
|
|
|
|
else
|
|
|
|
bgp_import = bgp_lookup_by_name(vname);
|
2019-03-08 06:26:14 +01:00
|
|
|
if (!bgp_import)
|
|
|
|
continue;
|
|
|
|
|
2021-04-01 07:39:57 +02:00
|
|
|
ecommunity_del_val(
|
|
|
|
bgp_import->vpn_policy[afi]
|
|
|
|
.rtlist[idir],
|
2019-03-08 06:26:14 +01:00
|
|
|
(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,
|
2022-11-22 09:57:10 +01:00
|
|
|
sizeof(buf), bgp->asnotation);
|
2022-09-21 09:54:14 +02:00
|
|
|
|
|
|
|
/* 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);
|
2019-03-08 06:26:14 +01:00
|
|
|
|
|
|
|
/* 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)) {
|
2019-09-17 03:28:44 +02:00
|
|
|
if (strcmp(vname, VRF_DEFAULT_NAME) == 0)
|
|
|
|
bgp_import = bgp_get_default();
|
|
|
|
else
|
|
|
|
bgp_import = bgp_lookup_by_name(vname);
|
2019-03-08 06:26:14 +01:00
|
|
|
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);
|
|
|
|
}
|
2019-06-11 19:47:15 +02:00
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:21:03 +02:00
|
|
|
void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
2018-03-27 02:24:47 +02:00
|
|
|
afi_t afi, safi_t safi)
|
|
|
|
{
|
|
|
|
const char *export_name;
|
2022-04-12 10:34:27 +02:00
|
|
|
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];
|
2018-03-27 02:24:47 +02:00
|
|
|
struct ecommunity *ecom;
|
|
|
|
bool first_export = false;
|
2019-03-08 06:26:14 +01:00
|
|
|
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;
|
2018-03-27 02:24:47 +02:00
|
|
|
|
2018-07-20 17:02:15 +02:00
|
|
|
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
|
2018-03-27 02:24:47 +02:00
|
|
|
idir = BGP_VPN_POLICY_DIR_FROMVPN;
|
|
|
|
edir = BGP_VPN_POLICY_DIR_TOVPN;
|
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
|
|
|
|
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
|
|
|
|
|
2018-04-17 14:21:03 +02:00
|
|
|
/*
|
|
|
|
* Cross-ref both VRFs. Also, note if this is the first time
|
2018-03-27 02:24:47 +02:00
|
|
|
* any VRF is importing from "import_vrf".
|
|
|
|
*/
|
2018-03-30 22:44:39 +02:00
|
|
|
vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
|
2018-07-20 17:02:15 +02:00
|
|
|
: XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
|
2018-03-30 22:44:39 +02:00
|
|
|
|
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);
|
2020-11-18 18:10:22 +01:00
|
|
|
else
|
|
|
|
XFREE(MTYPE_TMP, vname);
|
2018-03-27 02:24:47 +02:00
|
|
|
|
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;
|
2018-03-27 02:24:47 +02:00
|
|
|
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);
|
2020-11-18 18:10:22 +01:00
|
|
|
else
|
|
|
|
XFREE(MTYPE_TMP, vname);
|
|
|
|
|
2018-03-27 02:24:47 +02:00
|
|
|
/* 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) {
|
2018-04-17 14:21:03 +02:00
|
|
|
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,
|
2018-03-27 02:24:47 +02:00
|
|
|
BGP_VPN_POLICY_TOVPN_RD_SET);
|
2022-11-22 09:57:10 +01:00
|
|
|
prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd, buf,
|
|
|
|
sizeof(buf), from_bgp->asnotation);
|
2018-04-17 14:21:03 +02:00
|
|
|
from_bgp->vpn_policy[afi].rtlist[edir] =
|
2018-03-27 02:24:47 +02:00
|
|
|
ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
|
2018-04-17 14:21:03 +02:00
|
|
|
SET_FLAG(from_bgp->af_flags[afi][safi],
|
2018-03-27 02:24:47 +02:00
|
|
|
BGP_CONFIG_VRF_TO_VRF_EXPORT);
|
2018-04-25 16:23:22 +02:00
|
|
|
from_bgp->vpn_policy[afi].tovpn_label =
|
|
|
|
BGP_PREVENT_VRF_2_VRF_LEAK;
|
2018-03-27 02:24:47 +02:00
|
|
|
}
|
2018-04-17 14:21:03 +02:00
|
|
|
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]
|
2018-03-27 02:24:47 +02:00
|
|
|
.rtlist[idir], ecom);
|
|
|
|
else
|
2018-04-17 14:21:03 +02:00
|
|
|
to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom);
|
|
|
|
SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT);
|
2018-03-27 02:24:47 +02:00
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
if (debug) {
|
|
|
|
const char *from_name;
|
2020-11-18 18:50:48 +01:00
|
|
|
char *ecom1, *ecom2;
|
2019-03-08 06:26:14 +01:00
|
|
|
|
|
|
|
from_name = from_bgp->name ? from_bgp->name :
|
|
|
|
VRF_DEFAULT_NAME;
|
2020-11-18 18:50:48 +01:00
|
|
|
|
|
|
|
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);
|
2019-03-08 06:26:14 +01:00
|
|
|
}
|
|
|
|
|
2018-03-27 02:24:47 +02:00
|
|
|
/* 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)
|
2018-04-17 14:21:03 +02:00
|
|
|
vpn_leak_postchange(edir, afi, bgp_get_default(), from_bgp);
|
2018-03-27 02:24:47 +02:00
|
|
|
else
|
2018-04-17 14:21:03 +02:00
|
|
|
vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
|
2018-03-27 02:24:47 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 14:21:03 +02:00
|
|
|
void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
2018-03-27 02:24:47 +02:00
|
|
|
afi_t afi, safi_t safi)
|
|
|
|
{
|
2018-03-30 22:44:39 +02:00
|
|
|
const char *export_name, *tmp_name;
|
2022-04-12 10:34:27 +02:00
|
|
|
enum vpn_policy_direction idir, edir;
|
2018-03-27 02:24:47 +02:00
|
|
|
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;
|
2018-03-27 02:24:47 +02:00
|
|
|
struct listnode *node;
|
2019-03-08 06:26:14 +01:00
|
|
|
int debug;
|
2018-03-27 02:24:47 +02:00
|
|
|
|
2018-07-20 17:02:15 +02:00
|
|
|
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
|
|
|
|
tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
|
2018-03-27 02:24:47 +02:00
|
|
|
idir = BGP_VPN_POLICY_DIR_FROMVPN;
|
|
|
|
edir = BGP_VPN_POLICY_DIR_TOVPN;
|
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
|
|
|
|
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
|
|
|
|
|
2018-03-27 02:24:47 +02:00
|
|
|
/* Were we importing from "import_vrf"? */
|
2018-04-17 14:21:03 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node,
|
|
|
|
vname)) {
|
2018-03-30 22:44:39 +02:00
|
|
|
if (strcmp(vname, tmp_name) == 0)
|
2018-04-11 15:40:50 +02:00
|
|
|
break;
|
2018-03-27 02:24:47 +02:00
|
|
|
}
|
2018-04-17 14:21:03 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-03-27 02:24:47 +02:00
|
|
|
if (!vname)
|
|
|
|
return;
|
|
|
|
|
2019-03-08 06:26:14 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s from %s to %s", __func__, tmp_name, export_name);
|
|
|
|
|
2018-03-27 02:24:47 +02:00
|
|
|
/* Remove "import_vrf" from our import list. */
|
2018-04-17 14:21:03 +02:00
|
|
|
listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname);
|
2018-03-27 02:24:47 +02:00
|
|
|
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
|
|
|
|
*/
|
2018-04-17 14:21:03 +02:00
|
|
|
vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp);
|
2018-03-27 02:24:47 +02:00
|
|
|
|
2018-04-17 14:21:03 +02:00
|
|
|
if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
|
2020-03-09 19:34:53 +01:00
|
|
|
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]);
|
2018-03-27 02:24:47 +02:00
|
|
|
} else {
|
2018-04-17 14:21:03 +02:00
|
|
|
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],
|
2018-03-27 02:24:47 +02:00
|
|
|
(struct ecommunity_val *)ecom->val);
|
2018-04-17 14:21:03 +02:00
|
|
|
vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
|
2018-03-27 02:24:47 +02:00
|
|
|
}
|
|
|
|
|
2018-04-11 18:41:55 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-04-17 14:21:03 +02:00
|
|
|
assert(from_bgp->vpn_policy[afi].export_vrf);
|
2018-04-11 18:41:55 +02:00
|
|
|
|
2018-03-27 02:24:47 +02:00
|
|
|
/* Remove us from "import_vrf's" export list. If no other VRF
|
|
|
|
* is importing from "import_vrf", cleanup appropriately.
|
|
|
|
*/
|
2018-04-17 14:21:03 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf,
|
2018-03-27 02:24:47 +02:00
|
|
|
node, vname)) {
|
|
|
|
if (strcmp(vname, export_name) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:21:03 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
2018-04-17 14:21:03 +02:00
|
|
|
*/
|
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;
|
2018-04-17 14:21:03 +02:00
|
|
|
|
|
|
|
listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname);
|
2018-03-27 02:24:47 +02:00
|
|
|
XFREE(MTYPE_TMP, vname);
|
|
|
|
|
2018-04-17 14:21:03 +02:00
|
|
|
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],
|
2018-03-27 02:24:47 +02:00
|
|
|
BGP_CONFIG_VRF_TO_VRF_EXPORT);
|
2018-04-17 14:21:03 +02:00
|
|
|
memset(&from_bgp->vpn_policy[afi].tovpn_rd, 0,
|
2018-03-27 02:24:47 +02:00
|
|
|
sizeof(struct prefix_rd));
|
2018-04-17 14:21:03 +02:00
|
|
|
UNSET_FLAG(from_bgp->vpn_policy[afi].flags,
|
2018-03-27 02:24:47 +02:00
|
|
|
BGP_VPN_POLICY_TOVPN_RD_SET);
|
2018-04-25 16:23:22 +02:00
|
|
|
from_bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
|
|
|
|
|
2018-03-27 02:24:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* For testing purpose, static route of MPLS-VPN. */
|
|
|
|
DEFUN (vpnv4_network,
|
|
|
|
vpnv4_network_cmd,
|
2017-09-14 20:07:30 +02:00
|
|
|
"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"
|
2016-10-28 01:18:26 +02:00
|
|
|
"IPv4 prefix\n"
|
2002-12-13 21:15:29 +01:00
|
|
|
"Specify Route Distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2017-05-18 14:56:26 +02:00
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"Label value\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ipv4_prefixlen = 1;
|
|
|
|
int idx_ext_community = 3;
|
2017-05-18 14:56:26 +02:00
|
|
|
int idx_label = 5;
|
2023-08-10 10:37:40 +02:00
|
|
|
|
|
|
|
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);
|
2016-01-12 19:41:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN (vpnv4_network_route_map,
|
|
|
|
vpnv4_network_route_map_cmd,
|
2022-06-13 11:18:36 +02:00
|
|
|
"network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) route-map RMAP_NAME",
|
2016-01-12 19:41:53 +01:00
|
|
|
"Specify a network to announce via BGP\n"
|
2016-10-28 01:18:26 +02:00
|
|
|
"IPv4 prefix\n"
|
2016-01-12 19:41:53 +01:00
|
|
|
"Specify Route Distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2017-05-18 14:56:26 +02:00
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"Label value\n"
|
2016-01-12 19:41:53 +01:00
|
|
|
"route map\n"
|
|
|
|
"route map name\n")
|
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ipv4_prefixlen = 1;
|
|
|
|
int idx_ext_community = 3;
|
2017-05-18 14:56:26 +02:00
|
|
|
int idx_label = 5;
|
2023-08-10 10:37:40 +02:00
|
|
|
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,
|
2017-09-14 20:07:30 +02:00
|
|
|
"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"
|
2016-10-28 01:18:26 +02:00
|
|
|
"IPv4 prefix\n"
|
2002-12-13 21:15:29 +01:00
|
|
|
"Specify Route Distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2017-05-18 14:56:26 +02:00
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"Label value\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ipv4_prefixlen = 2;
|
|
|
|
int idx_ext_community = 4;
|
2017-05-18 14:56:26 +02:00
|
|
|
int idx_label = 6;
|
2023-08-10 10:37:40 +02:00
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-12-19 10:53:38 +01:00
|
|
|
DEFUN (vpnv6_network,
|
|
|
|
vpnv6_network_cmd,
|
2022-06-13 11:18:36 +02:00
|
|
|
"network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) [route-map RMAP_NAME]",
|
2016-12-19 10:53:38 +01:00
|
|
|
"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"
|
2017-05-18 14:56:26 +02:00
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"Label value\n"
|
2017-01-16 01:01:56 +01:00
|
|
|
"route map\n"
|
|
|
|
"route map name\n")
|
2016-12-19 10:53:38 +01:00
|
|
|
{
|
|
|
|
int idx_ipv6_prefix = 1;
|
|
|
|
int idx_ext_community = 3;
|
2017-05-18 14:56:26 +02:00
|
|
|
int idx_label = 5;
|
2023-08-10 10:37:40 +02:00
|
|
|
int idx_rmap = 7;
|
|
|
|
|
2017-05-04 04:49:50 +02:00
|
|
|
if (argc == 8)
|
2023-08-10 10:37:40 +02:00
|
|
|
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);
|
2017-01-09 19:29:43 +01:00
|
|
|
else
|
2023-08-10 10:37:40 +02:00
|
|
|
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);
|
2016-12-19 10:53:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For testing purpose, static route of MPLS-VPN. */
|
|
|
|
DEFUN (no_vpnv6_network,
|
|
|
|
no_vpnv6_network_cmd,
|
2017-09-14 20:07:30 +02:00
|
|
|
"no network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)",
|
2016-12-19 10:53:38 +01:00
|
|
|
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"
|
2017-05-18 14:56:26 +02:00
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"VPN NLRI label (tag)\n"
|
|
|
|
"Label value\n")
|
2016-12-19 10:53:38 +01:00
|
|
|
{
|
|
|
|
int idx_ipv6_prefix = 2;
|
|
|
|
int idx_ext_community = 4;
|
2017-05-18 14:56:26 +02:00
|
|
|
int idx_label = 6;
|
2023-08-10 10:37:40 +02:00
|
|
|
|
|
|
|
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);
|
2016-12-19 10:53:38 +01:00
|
|
|
}
|
|
|
|
|
2016-09-21 15:51:30 +02:00
|
|
|
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,
|
2018-08-29 14:19:54 +02:00
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
bgp = bgp_get_default();
|
|
|
|
if (bgp == NULL) {
|
2015-08-12 15:59:18 +02:00
|
|
|
if (!use_json)
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "No BGP process is configured\n");
|
2017-07-26 17:27:37 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "{}\n");
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
2017-09-29 00:51:31 +02:00
|
|
|
table = bgp->rib[afi][SAFI_MPLS_VPN];
|
2023-09-21 15:08:50 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-01-24 20:52:06 +01:00
|
|
|
DEFUN (show_bgp_ip_vpn_all_rd,
|
|
|
|
show_bgp_ip_vpn_all_rd_cmd,
|
2021-03-09 05:28:04 +01:00
|
|
|
"show bgp "BGP_AFI_CMD_STR" vpn all [rd <ASN:NN_OR_IP-ADDRESS:NN|all>] [json]",
|
2016-09-21 15:51:30 +02:00
|
|
|
SHOW_STR
|
|
|
|
BGP_STR
|
2017-01-13 14:29:20 +01:00
|
|
|
BGP_VPNVX_HELP_STR
|
2016-09-21 15:51:30 +02:00
|
|
|
"Display VPN NLRI specific information\n"
|
2017-09-29 17:54:31 +02:00
|
|
|
"Display VPN NLRI specific information\n"
|
2016-09-21 15:51:30 +02:00
|
|
|
"Display information for a route distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2021-03-09 05:28:04 +01:00
|
|
|
"All VPN Route Distinguishers\n"
|
2016-09-21 15:51:30 +02:00
|
|
|
JSON_STR)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct prefix_rd prd;
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
|
2021-03-09 05:28:04 +01:00
|
|
|
/* Constrain search if user supplies RD && RD != "all" */
|
|
|
|
if (argv_find(argv, argc, "rd", &idx)
|
|
|
|
&& strcmp(argv[idx + 1]->arg, "all")) {
|
2018-02-09 19:22:50 +01:00
|
|
|
ret = str2prefix_rd(argv[idx + 1]->arg, &prd);
|
2017-01-08 18:09:04 +01:00
|
|
|
if (!ret) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"%% Malformed Route Distinguisher\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
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));
|
|
|
|
}
|
2016-09-21 15:51:30 +02:00
|
|
|
}
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:54:31 +02:00
|
|
|
ALIAS(show_bgp_ip_vpn_all_rd,
|
|
|
|
show_bgp_ip_vpn_rd_cmd,
|
2021-03-09 05:28:04 +01:00
|
|
|
"show bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> [json]",
|
2017-09-29 17:54:31 +02:00
|
|
|
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"
|
2021-03-09 05:28:04 +01:00
|
|
|
"All VPN Route Distinguishers\n"
|
2017-09-29 17:54:31 +02:00
|
|
|
JSON_STR)
|
|
|
|
|
|
|
|
#ifdef KEEP_OLD_VPN_COMMANDS
|
2017-01-08 18:09:04 +01:00
|
|
|
DEFUN (show_ip_bgp_vpn_rd,
|
|
|
|
show_ip_bgp_vpn_rd_cmd,
|
2021-03-09 05:28:04 +01:00
|
|
|
"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
|
2017-01-24 20:52:06 +01:00
|
|
|
BGP_AFI_HELP_STR
|
2022-07-18 09:05:35 +02:00
|
|
|
BGP_AF_MODIFIER_STR
|
2002-12-13 21:15:29 +01:00
|
|
|
"Display information for a route distinguisher\n"
|
2021-03-09 05:28:04 +01:00
|
|
|
"VPN Route Distinguisher\n"
|
|
|
|
"All VPN Route Distinguishers\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-01-24 20:52:06 +01:00
|
|
|
int idx_ext_community = argc - 1;
|
2002-12-13 21:15:29 +01:00
|
|
|
int ret;
|
|
|
|
struct prefix_rd prd;
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
2021-03-09 05:28:04 +01:00
|
|
|
if (!strcmp(argv[idx_ext_community]->arg, "all"))
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, NULL,
|
|
|
|
bgp_show_type_normal, NULL, 0,
|
|
|
|
0);
|
2017-01-08 18:09:04 +01:00
|
|
|
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
|
|
|
if (!ret) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%% Malformed Route Distinguisher\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
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
|
|
|
}
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-01-24 20:52:06 +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;
|
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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
|
2017-01-08 18:09:04 +01:00
|
|
|
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")
|
|
|
|
{
|
2017-01-08 18:09:04 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
DEFUN (show_ip_bgp_vpn_rd_tags,
|
|
|
|
show_ip_bgp_vpn_rd_tags_cmd,
|
2021-03-09 05:28:04 +01:00
|
|
|
"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
|
2017-01-08 18:09:04 +01:00
|
|
|
BGP_VPNVX_HELP_STR
|
2002-12-13 21:15:29 +01:00
|
|
|
"Display information for a route distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2021-03-09 05:28:04 +01:00
|
|
|
"All VPN Route Distinguishers\n"
|
2002-12-13 21:15:29 +01:00
|
|
|
"Display BGP tags for prefixes\n")
|
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ext_community = 5;
|
2002-12-13 21:15:29 +01:00
|
|
|
int ret;
|
|
|
|
struct prefix_rd prd;
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
2021-03-09 05:28:04 +01:00
|
|
|
if (!strcmp(argv[idx_ext_community]->arg, "all"))
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, NULL,
|
|
|
|
bgp_show_type_normal, NULL, 1,
|
|
|
|
0);
|
2017-01-08 18:09:04 +01:00
|
|
|
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
|
|
|
if (!ret) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%% Malformed Route Distinguisher\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
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
|
|
|
}
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +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
|
2017-01-08 18:09:04 +01:00
|
|
|
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"
|
2015-08-12 15:59:18 +02:00
|
|
|
"Display routes learned from neighbor\n"
|
2016-11-30 00:26:03 +01:00
|
|
|
JSON_STR)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ipv4 = 6;
|
2012-04-10 16:57:24 +02:00
|
|
|
union sockunion su;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct peer *peer;
|
2012-04-10 16:57:24 +02:00
|
|
|
int ret;
|
2018-08-29 14:19:54 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
|
|
|
argv[idx_ipv4]->arg);
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
DEFUN (show_ip_bgp_vpn_rd_neighbor_routes,
|
|
|
|
show_ip_bgp_vpn_rd_neighbor_routes_cmd,
|
2021-03-09 05:28:04 +01:00
|
|
|
"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
|
2017-01-08 18:09:04 +01:00
|
|
|
BGP_VPNVX_HELP_STR
|
2002-12-13 21:15:29 +01:00
|
|
|
"Display information for a route distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2021-03-09 05:28:04 +01:00
|
|
|
"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"
|
2015-08-12 15:59:18 +02:00
|
|
|
"Display routes learned from neighbor\n"
|
2016-11-30 00:26:03 +01:00
|
|
|
JSON_STR)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ext_community = 5;
|
|
|
|
int idx_ipv4 = 7;
|
2002-12-13 21:15:29 +01:00
|
|
|
int ret;
|
2012-04-10 16:57:24 +02:00
|
|
|
union sockunion su;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct peer *peer;
|
|
|
|
struct prefix_rd prd;
|
2021-03-09 05:28:04 +01:00
|
|
|
bool prefix_rd_all = false;
|
2018-08-29 14:19:54 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
2021-03-09 05:28:04 +01:00
|
|
|
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;
|
|
|
|
}
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
argv[idx_ext_community]->arg);
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-03-09 05:28:04 +01:00
|
|
|
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);
|
2017-01-08 18:09:04 +01:00
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +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
|
2017-01-08 18:09:04 +01:00
|
|
|
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"
|
2015-08-12 15:59:18 +02:00
|
|
|
"Display the routes advertised to a BGP neighbor\n"
|
2016-11-30 00:26:03 +01:00
|
|
|
JSON_STR)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 21:45:50 +02:00
|
|
|
int idx_ipv4 = 6;
|
2002-12-13 21:15:29 +01:00
|
|
|
int ret;
|
|
|
|
struct peer *peer;
|
|
|
|
union sockunion su;
|
2018-08-29 14:19:54 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
|
|
|
argv[idx_ipv4]->arg);
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-01-09 18:26:24 +01:00
|
|
|
return show_adj_route_vpn(vty, peer, NULL, AFI_IP,
|
|
|
|
SAFI_MPLS_VPN, uj);
|
2017-01-08 18:09:04 +01:00
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes,
|
|
|
|
show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd,
|
2021-03-09 05:28:04 +01:00
|
|
|
"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
|
2017-01-08 18:09:04 +01:00
|
|
|
BGP_VPNVX_HELP_STR
|
2002-12-13 21:15:29 +01:00
|
|
|
"Display information for a route distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
2021-03-09 05:28:04 +01:00
|
|
|
"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"
|
2015-08-12 15:59:18 +02:00
|
|
|
"Display the routes advertised to a BGP neighbor\n"
|
2016-11-30 00:26:03 +01:00
|
|
|
JSON_STR)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 21:45:50 +02: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;
|
2018-08-29 14:19:54 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
2017-01-08 18:09:04 +01:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
argv[idx_ext_community]->arg);
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-03-09 05:28:04 +01:00
|
|
|
if (!strcmp(argv[idx_ext_community]->arg, "all"))
|
|
|
|
return show_adj_route_vpn(vty, peer, NULL, AFI_IP,
|
|
|
|
SAFI_MPLS_VPN, uj);
|
2017-01-08 18:09:04 +01:00
|
|
|
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");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
2017-01-08 18:09:04 +01:00
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"%% Malformed Route Distinguisher\n");
|
2017-01-08 18:09:04 +01:00
|
|
|
return CMD_WARNING;
|
2015-08-12 15:59:18 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-09 18:26:24 +01:00
|
|
|
return show_adj_route_vpn(vty, peer, &prd, AFI_IP,
|
|
|
|
SAFI_MPLS_VPN, uj);
|
2017-01-08 18:09:04 +01:00
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-01-18 12:27:52 +01:00
|
|
|
#endif /* KEEP_OLD_VPN_COMMANDS */
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2005-06-28 14:44:16 +02:00
|
|
|
void bgp_mplsvpn_init(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
install_element(BGP_VPNV4_NODE, &vpnv4_network_cmd);
|
2016-01-12 19:41:53 +01:00
|
|
|
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);
|
|
|
|
|
2016-12-19 10:53:38 +01:00
|
|
|
install_element(BGP_VPNV6_NODE, &vpnv6_network_cmd);
|
|
|
|
install_element(BGP_VPNV6_NODE, &no_vpnv6_network_cmd);
|
|
|
|
|
2017-01-24 20:52:06 +01:00
|
|
|
install_element(VIEW_NODE, &show_bgp_ip_vpn_all_rd_cmd);
|
2017-09-29 17:54:31 +02:00
|
|
|
install_element(VIEW_NODE, &show_bgp_ip_vpn_rd_cmd);
|
2017-01-18 12:27:52 +01:00
|
|
|
#ifdef KEEP_OLD_VPN_COMMANDS
|
2017-09-29 17:54:31 +02:00
|
|
|
install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_cmd);
|
2017-01-08 18:09:04 +01:00
|
|
|
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);
|
2017-01-18 12:27:52 +01:00
|
|
|
#endif /* KEEP_OLD_VPN_COMMANDS */
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2018-01-23 18:09:12 +01:00
|
|
|
|
|
|
|
vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey)
|
|
|
|
{
|
|
|
|
struct listnode *mnode, *mnnode;
|
|
|
|
struct bgp *bgp;
|
2019-10-17 16:08:16 +02:00
|
|
|
afi_t afi = AFI_IP;
|
|
|
|
|
|
|
|
if (eckey->unit_size == IPV6_ECOMMUNITY_SIZE)
|
|
|
|
afi = AFI_IP6;
|
2018-01-23 18:09:12 +01:00
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
|
|
|
|
struct ecommunity *ec;
|
|
|
|
|
|
|
|
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
|
|
|
|
continue;
|
|
|
|
|
2019-10-17 16:08:16 +02:00
|
|
|
ec = bgp->vpn_policy[afi].import_redirect_rtlist;
|
|
|
|
|
|
|
|
if (ec && eckey->unit_size != ec->unit_size)
|
|
|
|
continue;
|
2018-01-23 18:09:12 +01:00
|
|
|
|
2022-08-19 11:50:29 +02:00
|
|
|
if (ecommunity_include(ec, eckey))
|
2018-01-23 18:09:12 +01:00
|
|
|
return bgp->vrf_id;
|
|
|
|
}
|
|
|
|
return VRF_UNKNOWN;
|
|
|
|
}
|
2018-06-29 23:55:59 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
bgpd: Do not process VRF import/export to/from auto created VRF instances
Fixes the crash:
```
(gdb) bt
0 __pthread_kill_implementation (no_tid=0, signo=11, threadid=124583315603008) at ./nptl/pthread_kill.c:44
1 __pthread_kill_internal (signo=11, threadid=124583315603008) at ./nptl/pthread_kill.c:78
2 __GI___pthread_kill (threadid=124583315603008, signo=signo@entry=11) at ./nptl/pthread_kill.c:89
3 0x0000714ed0242476 in __GI_raise (sig=11) at ../sysdeps/posix/raise.c:26
4 0x0000714ed074cfb7 in core_handler (signo=11, siginfo=0x7ffe6d9792b0, context=0x7ffe6d979180) at lib/sigevent.c:258
5 <signal handler called>
6 0x000060f55e33ffdd in route_table_get_info (table=0x0) at ./lib/table.h:177
7 0x000060f55e340053 in bgp_dest_table (dest=0x60f56dabb840) at ./bgpd/bgp_table.h:156
8 0x000060f55e340c9f in is_route_injectable_into_vpn (pi=0x60f56dbc4a60) at ./bgpd/bgp_mplsvpn.h:331
9 0x000060f55e34507c in vpn_leak_from_vrf_update (to_bgp=0x60f56da52070, from_bgp=0x60f56da75af0, path_vrf=0x60f56dbc4a60) at bgpd/bgp_mplsvpn.c:1575
10 0x000060f55e346657 in vpn_leak_from_vrf_update_all (to_bgp=0x60f56da52070, from_bgp=0x60f56da75af0, afi=AFI_IP) at bgpd/bgp_mplsvpn.c:2028
11 0x000060f55e340c10 in vpn_leak_postchange (direction=BGP_VPN_POLICY_DIR_TOVPN, afi=AFI_IP, bgp_vpn=0x60f56da52070, bgp_vrf=0x60f56da75af0) at ./bgpd/bgp_mplsvpn.h:310
12 0x000060f55e34a692 in vpn_leak_postchange_all () at bgpd/bgp_mplsvpn.c:3737
13 0x000060f55e3d91fc in router_bgp (self=0x60f55e5cbc20 <router_bgp_cmd>, vty=0x60f56e2d7660, argc=3, argv=0x60f56da19830) at bgpd/bgp_vty.c:1601
14 0x0000714ed069ddf5 in cmd_execute_command_real (vline=0x60f56da32a80, vty=0x60f56e2d7660, cmd=0x0, up_level=0) at lib/command.c:1002
15 0x0000714ed069df6e in cmd_execute_command (vline=0x60f56da32a80, vty=0x60f56e2d7660, cmd=0x0, vtysh=0) at lib/command.c:1061
16 0x0000714ed069e51e in cmd_execute (vty=0x60f56e2d7660, cmd=0x60f56dbf07d0 "router bgp 100\n", matched=0x0, vtysh=0) at lib/command.c:1227
17 0x0000714ed076faa0 in vty_command (vty=0x60f56e2d7660, buf=0x60f56dbf07d0 "router bgp 100\n") at lib/vty.c:616
18 0x0000714ed07719c4 in vty_execute (vty=0x60f56e2d7660) at lib/vty.c:1379
19 0x0000714ed07740f0 in vtysh_read (thread=0x7ffe6d97c700) at lib/vty.c:2374
20 0x0000714ed07685c4 in event_call (thread=0x7ffe6d97c700) at lib/event.c:1995
21 0x0000714ed06e3351 in frr_run (master=0x60f56d1d2e40) at lib/libfrr.c:1232
22 0x000060f55e2c4b44 in main (argc=7, argv=0x7ffe6d97c978) at bgpd/bgp_main.c:555
(gdb)
```
Fixes https://github.com/FRRouting/frr/issues/16484
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
2024-07-28 13:26:13 +02:00
|
|
|
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
|
|
|
|
continue;
|
|
|
|
|
2018-06-29 23:55:59 +02:00
|
|
|
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;
|
|
|
|
|
bgpd: Do not process VRF import/export to/from auto created VRF instances
Fixes the crash:
```
(gdb) bt
0 __pthread_kill_implementation (no_tid=0, signo=11, threadid=124583315603008) at ./nptl/pthread_kill.c:44
1 __pthread_kill_internal (signo=11, threadid=124583315603008) at ./nptl/pthread_kill.c:78
2 __GI___pthread_kill (threadid=124583315603008, signo=signo@entry=11) at ./nptl/pthread_kill.c:89
3 0x0000714ed0242476 in __GI_raise (sig=11) at ../sysdeps/posix/raise.c:26
4 0x0000714ed074cfb7 in core_handler (signo=11, siginfo=0x7ffe6d9792b0, context=0x7ffe6d979180) at lib/sigevent.c:258
5 <signal handler called>
6 0x000060f55e33ffdd in route_table_get_info (table=0x0) at ./lib/table.h:177
7 0x000060f55e340053 in bgp_dest_table (dest=0x60f56dabb840) at ./bgpd/bgp_table.h:156
8 0x000060f55e340c9f in is_route_injectable_into_vpn (pi=0x60f56dbc4a60) at ./bgpd/bgp_mplsvpn.h:331
9 0x000060f55e34507c in vpn_leak_from_vrf_update (to_bgp=0x60f56da52070, from_bgp=0x60f56da75af0, path_vrf=0x60f56dbc4a60) at bgpd/bgp_mplsvpn.c:1575
10 0x000060f55e346657 in vpn_leak_from_vrf_update_all (to_bgp=0x60f56da52070, from_bgp=0x60f56da75af0, afi=AFI_IP) at bgpd/bgp_mplsvpn.c:2028
11 0x000060f55e340c10 in vpn_leak_postchange (direction=BGP_VPN_POLICY_DIR_TOVPN, afi=AFI_IP, bgp_vpn=0x60f56da52070, bgp_vrf=0x60f56da75af0) at ./bgpd/bgp_mplsvpn.h:310
12 0x000060f55e34a692 in vpn_leak_postchange_all () at bgpd/bgp_mplsvpn.c:3737
13 0x000060f55e3d91fc in router_bgp (self=0x60f55e5cbc20 <router_bgp_cmd>, vty=0x60f56e2d7660, argc=3, argv=0x60f56da19830) at bgpd/bgp_vty.c:1601
14 0x0000714ed069ddf5 in cmd_execute_command_real (vline=0x60f56da32a80, vty=0x60f56e2d7660, cmd=0x0, up_level=0) at lib/command.c:1002
15 0x0000714ed069df6e in cmd_execute_command (vline=0x60f56da32a80, vty=0x60f56e2d7660, cmd=0x0, vtysh=0) at lib/command.c:1061
16 0x0000714ed069e51e in cmd_execute (vty=0x60f56e2d7660, cmd=0x60f56dbf07d0 "router bgp 100\n", matched=0x0, vtysh=0) at lib/command.c:1227
17 0x0000714ed076faa0 in vty_command (vty=0x60f56e2d7660, buf=0x60f56dbf07d0 "router bgp 100\n") at lib/vty.c:616
18 0x0000714ed07719c4 in vty_execute (vty=0x60f56e2d7660) at lib/vty.c:1379
19 0x0000714ed07740f0 in vtysh_read (thread=0x7ffe6d97c700) at lib/vty.c:2374
20 0x0000714ed07685c4 in event_call (thread=0x7ffe6d97c700) at lib/event.c:1995
21 0x0000714ed06e3351 in frr_run (master=0x60f56d1d2e40) at lib/libfrr.c:1232
22 0x000060f55e2c4b44 in main (argc=7, argv=0x7ffe6d97c978) at bgpd/bgp_main.c:555
(gdb)
```
Fixes https://github.com/FRRouting/frr/issues/16484
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
2024-07-28 13:26:13 +02:00
|
|
|
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
|
|
|
|
continue;
|
|
|
|
|
2018-06-29 23:55:59 +02:00
|
|
|
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.
|
|
|
|
*/
|
2020-08-12 22:30:24 +02:00
|
|
|
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
|
|
|
{
|
2023-06-07 12:46:30 +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;
|
|
|
|
|
2021-07-16 20:36:10 +02:00
|
|
|
if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF &&
|
|
|
|
from_bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
|
2020-08-12 22:30:24 +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
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-06-07 12:46:30 +02:00
|
|
|
|
|
|
|
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
|
|
|
}
|
2020-08-12 22:30:24 +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
|
|
|
}
|
2019-06-11 02:19:26 +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;
|
2022-04-12 10:34:27 +02:00
|
|
|
enum vpn_policy_direction idir, edir;
|
2019-06-11 02:19:26 +02:00
|
|
|
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;
|
|
|
|
|
2020-10-27 06:18:46 +01:00
|
|
|
export_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
|
2019-06-11 02:19:26 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-02 16:38:53 +02:00
|
|
|
|
2024-12-12 13:27:02 +01:00
|
|
|
/* It releases the label from labelpool which
|
|
|
|
* was previously assigned and unsets the flag based on reset arg
|
|
|
|
* This also used in vty to release the label and to change the allocation mode as well
|
|
|
|
*/
|
|
|
|
void bgp_vpn_release_label(struct bgp *bgp, afi_t afi, bool reset)
|
|
|
|
{
|
|
|
|
if (!CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO))
|
|
|
|
return;
|
|
|
|
/*
|
|
|
|
* label has previously been automatically
|
|
|
|
* assigned by labelpool: release it
|
|
|
|
*
|
|
|
|
* NB if tovpn_label == MPLS_LABEL_NONE it
|
|
|
|
* means the automatic assignment is in flight
|
|
|
|
* and therefore the labelpool callback must
|
|
|
|
* detect that the auto label is not needed.
|
|
|
|
*/
|
|
|
|
if (bgp->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)
|
|
|
|
return;
|
|
|
|
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP))
|
|
|
|
return;
|
|
|
|
|
|
|
|
bgp_lp_release(LP_TYPE_VRF, &bgp->vpn_policy[afi], bgp->vpn_policy[afi].tovpn_label);
|
|
|
|
bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
|
|
|
|
|
|
|
|
if (reset)
|
|
|
|
UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
|
|
|
|
}
|
|
|
|
|
2023-05-02 16:38:53 +02:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2023-05-11 15:42:08 +02:00
|
|
|
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;
|
2024-02-26 18:11:09 +01:00
|
|
|
uint8_t num_labels = 0, lsp_num_labels;
|
2023-05-11 15:42:08 +02:00
|
|
|
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) {
|
2023-06-27 18:21:53 +02:00
|
|
|
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;
|
2023-05-11 15:42:08 +02:00
|
|
|
for (i = 0; i < lsp_num_labels; i++)
|
|
|
|
label[num_labels + i] = nh->nh_label->label[i];
|
2023-06-27 18:21:53 +02:00
|
|
|
num_labels = lsp_num_labels;
|
2023-05-11 15:42:08 +02:00
|
|
|
}
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2023-05-02 16:38:53 +02:00
|
|
|
void bgp_mplsvpn_nh_label_bind_free(
|
|
|
|
struct bgp_mplsvpn_nh_label_bind_cache *bmnc)
|
|
|
|
{
|
2023-05-11 13:56:16 +02:00
|
|
|
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;
|
|
|
|
}
|
2023-05-11 15:42:08 +02:00
|
|
|
if (bmnc->new_label != MPLS_INVALID_LABEL) {
|
|
|
|
bgp_mplsvpn_nh_label_bind_send_nexthop_label(
|
|
|
|
bmnc, ZEBRA_MPLS_LABELS_DELETE);
|
2023-05-02 16:38:53 +02:00
|
|
|
bgp_lp_release(LP_TYPE_BGP_L3VPN_BIND, bmnc, bmnc->new_label);
|
2023-05-11 15:42:08 +02:00
|
|
|
}
|
2023-05-02 16:38:53 +02:00
|
|
|
bgp_mplsvpn_nh_label_bind_cache_del(
|
|
|
|
&bmnc->bgp_vpn->mplsvpn_nh_label_bind, bmnc);
|
2023-07-04 12:13:15 +02:00
|
|
|
|
|
|
|
if (bmnc->nh)
|
|
|
|
nexthop_free(bmnc->nh);
|
|
|
|
|
2023-05-02 16:38:53 +02:00
|
|
|
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);
|
|
|
|
}
|
2023-05-11 13:56:16 +02:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2024-02-14 17:32:06 +01:00
|
|
|
if (!bgp_path_info_has_valid_label(pi))
|
2023-05-11 13:56:16 +02:00
|
|
|
/* invalid MPLS label */
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-11 15:26:50 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-05-11 13:56:16 +02:00
|
|
|
/* 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;
|
2023-05-11 15:26:50 +02:00
|
|
|
struct bgp_table *table;
|
|
|
|
struct bgp_path_info *pi;
|
2023-05-11 13:56:16 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2023-05-11 15:42:08 +02:00
|
|
|
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);
|
|
|
|
|
2023-05-11 15:26:50 +02:00
|
|
|
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);
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(table->bgp, pi->net, pi, table->afi, table->safi);
|
2023-05-11 15:26:50 +02:00
|
|
|
}
|
|
|
|
|
2023-05-11 13:56:16 +02:00
|
|
|
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;
|
bgpd: check and set extra num_labels
The handling of MPLS labels in BGP faces an issue due to the way labels
are stored in memory. They are stored in bgp_path_info but not in
bgp_adj_in and bgp_adj_out structures. As a consequence, some
configuration changes result in losing labels or even a bgpd crash. For
example, when retrieving routes from the Adj-RIB-in table
("soft-reconfiguration inbound" enabled), labels are missing.
bgp_path_info stores the MPLS labels, as shown below:
> struct bgp_path_info {
> struct bgp_path_info_extra *extra;
> [...]
> struct bgp_path_info_extra {
> mpls_label_t label[BGP_MAX_LABELS];
> uint32_t num_labels;
> [...]
To solve those issues, a solution would be to set label data to the
bgp_adj_in and bgp_adj_out structures in addition to the
bgp_path_info_extra structure. The idea is to reference a common label
pointer in all these three structures. And to store the data in a hash
list in order to save memory.
However, an issue in the code prevents us from setting clean data
without a rework. The extra->num_labels field, which is intended to
indicate the number of labels in extra->label[], is not reliably checked
or set. The code often incorrectly assumes that if the extra pointer is
present, then a label must also be present, leading to direct access to
extra->label[] without verifying extra->num_labels. This assumption
usually works because extra->label[0] is set to MPLS_INVALID_LABEL when
a new bgp_path_info_extra is created, but it is technically incorrect.
Cleanup the label code by setting num_labels each time values are set in
extra->label[] and checking extra->num_labels before accessing the
labels.
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-02-05 17:05:20 +01:00
|
|
|
mpls_label_t label;
|
|
|
|
|
2024-08-26 10:23:12 +02:00
|
|
|
label = BGP_PATH_INFO_NUM_LABELS(pi)
|
2024-02-26 18:23:11 +01:00
|
|
|
? decode_label(&pi->extra->labels->label[0])
|
2024-02-26 10:42:42 +01:00
|
|
|
: MPLS_INVALID_LABEL;
|
2023-05-11 13:56:16 +02:00
|
|
|
|
|
|
|
tree = &bgp->mplsvpn_nh_label_bind;
|
bgpd: check and set extra num_labels
The handling of MPLS labels in BGP faces an issue due to the way labels
are stored in memory. They are stored in bgp_path_info but not in
bgp_adj_in and bgp_adj_out structures. As a consequence, some
configuration changes result in losing labels or even a bgpd crash. For
example, when retrieving routes from the Adj-RIB-in table
("soft-reconfiguration inbound" enabled), labels are missing.
bgp_path_info stores the MPLS labels, as shown below:
> struct bgp_path_info {
> struct bgp_path_info_extra *extra;
> [...]
> struct bgp_path_info_extra {
> mpls_label_t label[BGP_MAX_LABELS];
> uint32_t num_labels;
> [...]
To solve those issues, a solution would be to set label data to the
bgp_adj_in and bgp_adj_out structures in addition to the
bgp_path_info_extra structure. The idea is to reference a common label
pointer in all these three structures. And to store the data in a hash
list in order to save memory.
However, an issue in the code prevents us from setting clean data
without a rework. The extra->num_labels field, which is intended to
indicate the number of labels in extra->label[], is not reliably checked
or set. The code often incorrectly assumes that if the extra pointer is
present, then a label must also be present, leading to direct access to
extra->label[] without verifying extra->num_labels. This assumption
usually works because extra->label[0] is set to MPLS_INVALID_LABEL when
a new bgp_path_info_extra is created, but it is technically incorrect.
Cleanup the label code by setting num_labels each time values are set in
extra->label[] and checking extra->num_labels before accessing the
labels.
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-02-05 17:05:20 +01:00
|
|
|
bmnc = bgp_mplsvpn_nh_label_bind_find(tree, &pi->nexthop->prefix, label);
|
2023-05-11 13:56:16 +02:00
|
|
|
if (!bmnc) {
|
bgpd: check and set extra num_labels
The handling of MPLS labels in BGP faces an issue due to the way labels
are stored in memory. They are stored in bgp_path_info but not in
bgp_adj_in and bgp_adj_out structures. As a consequence, some
configuration changes result in losing labels or even a bgpd crash. For
example, when retrieving routes from the Adj-RIB-in table
("soft-reconfiguration inbound" enabled), labels are missing.
bgp_path_info stores the MPLS labels, as shown below:
> struct bgp_path_info {
> struct bgp_path_info_extra *extra;
> [...]
> struct bgp_path_info_extra {
> mpls_label_t label[BGP_MAX_LABELS];
> uint32_t num_labels;
> [...]
To solve those issues, a solution would be to set label data to the
bgp_adj_in and bgp_adj_out structures in addition to the
bgp_path_info_extra structure. The idea is to reference a common label
pointer in all these three structures. And to store the data in a hash
list in order to save memory.
However, an issue in the code prevents us from setting clean data
without a rework. The extra->num_labels field, which is intended to
indicate the number of labels in extra->label[], is not reliably checked
or set. The code often incorrectly assumes that if the extra pointer is
present, then a label must also be present, leading to direct access to
extra->label[] without verifying extra->num_labels. This assumption
usually works because extra->label[0] is set to MPLS_INVALID_LABEL when
a new bgp_path_info_extra is created, but it is technically incorrect.
Cleanup the label code by setting num_labels each time values are set in
extra->label[] and checking extra->num_labels before accessing the
labels.
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-02-05 17:05:20 +01:00
|
|
|
bmnc = bgp_mplsvpn_nh_label_bind_new(tree, &pi->nexthop->prefix,
|
|
|
|
label);
|
2023-05-11 13:56:16 +02:00
|
|
|
bmnc->bgp_vpn = bgp;
|
|
|
|
bmnc->allocation_in_progress = true;
|
2025-02-10 18:02:00 +01:00
|
|
|
bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc, bgp->vrf_id,
|
2023-05-11 13:56:16 +02:00
|
|
|
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);
|
2023-06-27 18:12:39 +02:00
|
|
|
|
|
|
|
/* 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);
|
2023-05-11 13:56:16 +02:00
|
|
|
|
|
|
|
/* Add or update the selected nexthop */
|
2023-05-11 15:42:08 +02:00
|
|
|
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);
|
|
|
|
}
|
2023-05-11 13:56:16 +02:00
|
|
|
}
|
2023-05-02 17:23:58 +02:00
|
|
|
|
|
|
|
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;
|
2023-09-19 19:15:21 +02:00
|
|
|
char buf[32];
|
2023-05-02 17:23:58 +02:00
|
|
|
|
|
|
|
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));
|
2024-12-20 16:13:19 +01:00
|
|
|
vty_out(vty, " Last update: %s", time_to_string(iter->last_update, buf));
|
2023-05-02 17:23:58 +02:00
|
|
|
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);
|
|
|
|
}
|