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>
|
|
|
|
*
|
|
|
|
* This file is part of GNU Zebra.
|
|
|
|
*
|
|
|
|
* GNU Zebra is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
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"
|
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"
|
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"
|
2002-12-13 21:15:29 +01:00
|
|
|
|
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 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
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* Definitions and external declarations.
|
|
|
|
*/
|
|
|
|
extern struct zclient *zclient;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc,
|
|
|
|
int *index, afi_t *afi)
|
2017-01-08 18:09:04 +01:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
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;
|
2017-01-08 18:09:04 +01:00
|
|
|
}
|
|
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
return l;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +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;
|
2017-07-17 14:03:14 +02:00
|
|
|
if (pnt == NULL)
|
|
|
|
return;
|
|
|
|
*pnt++ = (label >> 12) & 0xff;
|
|
|
|
*pnt++ = (label >> 4) & 0xff;
|
|
|
|
*pnt++ = ((label << 4) + 1) & 0xff; /* S=1 */
|
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
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
|
|
|
|
struct bgp_nlri *packet)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
|
|
|
uint8_t *lim;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct prefix p;
|
|
|
|
int psize = 0;
|
|
|
|
int prefixlen;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t type;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct rd_as rd_as;
|
|
|
|
struct rd_ip rd_ip;
|
|
|
|
struct prefix_rd prd;
|
2018-03-09 21:52:55 +01:00
|
|
|
mpls_label_t label = {0};
|
2017-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
|
|
|
int addpath_encoded;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t addpath_id;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* Make prefix_rd */
|
|
|
|
prd.family = AF_UNSPEC;
|
|
|
|
prd.prefixlen = 64;
|
|
|
|
|
|
|
|
pnt = packet->nlri;
|
|
|
|
lim = pnt + packet->length;
|
|
|
|
afi = packet->afi;
|
|
|
|
safi = packet->safi;
|
|
|
|
addpath_id = 0;
|
|
|
|
|
|
|
|
addpath_encoded =
|
|
|
|
(CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV)
|
|
|
|
&& CHECK_FLAG(peer->af_cap[afi][safi],
|
|
|
|
PEER_CAP_ADDPATH_AF_TX_RCV));
|
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 */
|
2017-07-17 14:03:14 +02:00
|
|
|
for (; pnt < lim; pnt += psize) {
|
|
|
|
/* Clear prefix structure. */
|
|
|
|
memset(&p, 0, sizeof(struct prefix));
|
|
|
|
|
|
|
|
if (addpath_encoded) {
|
|
|
|
|
|
|
|
/* When packet overflow occurs return immediately. */
|
|
|
|
if (pnt + BGP_ADDPATH_ID_LEN > lim)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
addpath_id = ntohl(*((uint32_t *)pnt));
|
|
|
|
pnt += BGP_ADDPATH_ID_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fetch prefix length. */
|
|
|
|
prefixlen = *pnt++;
|
|
|
|
p.family = afi2family(packet->afi);
|
|
|
|
psize = PSIZE(prefixlen);
|
|
|
|
|
|
|
|
if (prefixlen < VPN_PREFIXLEN_MIN_BYTES * 8) {
|
|
|
|
zlog_err(
|
|
|
|
"%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",
|
|
|
|
peer->host, prefixlen);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check against packet data */
|
|
|
|
if ((pnt + psize) > lim) {
|
|
|
|
zlog_err(
|
|
|
|
"%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)",
|
|
|
|
peer->host, prefixlen, (uint)(lim - pnt));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check against storage for the IP address portion */
|
|
|
|
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t)sizeof(p.u)) {
|
|
|
|
zlog_err(
|
|
|
|
"%s [Error] Update packet error / VPN (psize %d exceeds storage size %zu)",
|
|
|
|
peer->host,
|
|
|
|
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
|
|
|
|
sizeof(p.u));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity check against max bitlen of the address family */
|
|
|
|
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen(&p)) {
|
|
|
|
zlog_err(
|
|
|
|
"%s [Error] Update packet error / VPN (psize %d exceeds family (%u) max byte len %u)",
|
|
|
|
peer->host,
|
|
|
|
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
|
|
|
|
p.family, prefix_blen(&p));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy label to prefix. */
|
|
|
|
memcpy(&label, pnt, BGP_LABEL_BYTES);
|
|
|
|
bgp_set_valid_label(&label);
|
|
|
|
|
|
|
|
/* Copy routing distinguisher to rd. */
|
|
|
|
memcpy(&prd.val, pnt + BGP_LABEL_BYTES, 8);
|
|
|
|
|
|
|
|
/* Decode RD type. */
|
|
|
|
type = decode_rd_type(pnt + BGP_LABEL_BYTES);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RD_TYPE_AS:
|
|
|
|
decode_rd_as(pnt + 5, &rd_as);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RD_TYPE_AS4:
|
|
|
|
decode_rd_as4(pnt + 5, &rd_as);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RD_TYPE_IP:
|
|
|
|
decode_rd_ip(pnt + 5, &rd_ip);
|
|
|
|
break;
|
2016-01-12 19:41:54 +01:00
|
|
|
|
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 ENABLE_BGP_VNC
|
2017-07-17 14:03:14 +02:00
|
|
|
case RD_TYPE_VNC_ETH:
|
|
|
|
break;
|
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
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
default:
|
|
|
|
zlog_err("Unknown RD type %d", type);
|
|
|
|
break; /* just report */
|
|
|
|
}
|
|
|
|
|
|
|
|
p.prefixlen =
|
|
|
|
prefixlen
|
|
|
|
- VPN_PREFIXLEN_MIN_BYTES * 8; /* exclude label & RD */
|
|
|
|
memcpy(&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES,
|
|
|
|
psize - VPN_PREFIXLEN_MIN_BYTES);
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
bgp_update(peer, &p, addpath_id, attr, packet->afi,
|
|
|
|
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
2017-11-21 11:42:05 +01:00
|
|
|
BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
|
|
|
bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
|
|
|
|
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
2017-11-21 11:42:05 +01:00
|
|
|
BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Packet length consistency check. */
|
|
|
|
if (pnt != lim) {
|
|
|
|
zlog_err(
|
|
|
|
"%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
|
|
|
|
peer->host, lim - pnt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
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
|
|
|
|
* are set) and b) whether vpn-policy label is set.
|
|
|
|
*
|
|
|
|
* If any of these conditions do not hold, then we send MPLS_LABEL_NONE
|
|
|
|
* for this vrf, which zebra interprets to mean "delete this vrf-label
|
|
|
|
* association."
|
|
|
|
*/
|
|
|
|
void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
|
|
|
|
{
|
|
|
|
mpls_label_t label = MPLS_LABEL_NONE;
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
|
|
|
|
|
|
|
if (bgp->vrf_id == VRF_UNKNOWN) {
|
|
|
|
if (debug) {
|
|
|
|
zlog_debug(
|
|
|
|
"%s: vrf %s: afi %s: vrf_id not set, "
|
|
|
|
"can't set zebra vrf label",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp->name_pretty, afi2str(afi));
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vpn_leak_to_vpn_active(bgp, afi, NULL)) {
|
|
|
|
label = bgp->vpn_policy[afi].tovpn_label;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
zlog_err("%s: %s had label %u but got new assignment %u",
|
|
|
|
__func__, vp->bgp->name_pretty, vp->tovpn_label, label);
|
|
|
|
/* use new one */
|
|
|
|
}
|
|
|
|
|
|
|
|
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
|
|
|
|
vp->afi, bgp_get_default(), vp->bgp);
|
|
|
|
vp->tovpn_label = label;
|
|
|
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
|
|
|
|
vp->afi, bgp_get_default(), vp->bgp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
static int ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
if (!e1 || !e2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < e1->size; ++i) {
|
|
|
|
for (j = 0; j < e2->size; ++j) {
|
|
|
|
if (!memcmp(e1->val + (i * ECOMMUNITY_SIZE),
|
|
|
|
e2->val + (j * ECOMMUNITY_SIZE),
|
|
|
|
ECOMMUNITY_SIZE)) {
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-11 06:03:05 +02:00
|
|
|
static bool labels_same(struct bgp_info *bi, mpls_label_t *label, uint32_t n)
|
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
if (!bi->extra) {
|
|
|
|
if (!n)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n != bi->extra->num_labels)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
if (label[i] != bi->extra->label[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make encoded route labels match specified encoded label set
|
|
|
|
*/
|
|
|
|
static void setlabels(
|
|
|
|
struct bgp_info *bi,
|
|
|
|
mpls_label_t *label, /* array of labels */
|
|
|
|
uint32_t num_labels)
|
|
|
|
{
|
|
|
|
if (num_labels)
|
|
|
|
assert(label);
|
|
|
|
assert(num_labels <= BGP_MAX_LABELS);
|
|
|
|
|
|
|
|
if (!num_labels) {
|
|
|
|
if (bi->extra)
|
|
|
|
bi->extra->num_labels = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bgp_info_extra *extra = bgp_info_extra_get(bi);
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < num_labels; ++i) {
|
|
|
|
extra->label[i] = label[i];
|
|
|
|
if (!bgp_is_valid_label(&label[i])) {
|
|
|
|
bgp_set_valid_label(&extra->label[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
extra->num_labels = num_labels;
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/*
|
|
|
|
* returns pointer to new bgp_info upon success
|
|
|
|
*/
|
|
|
|
static struct bgp_info *
|
2018-03-24 00:57:03 +01:00
|
|
|
leak_update(
|
|
|
|
struct bgp *bgp, /* destination bgp instance */
|
|
|
|
struct bgp_node *bn,
|
|
|
|
struct attr *new_attr, /* already interned */
|
|
|
|
afi_t afi,
|
|
|
|
safi_t safi,
|
|
|
|
struct bgp_info *source_bi,
|
|
|
|
mpls_label_t *label,
|
2018-04-11 06:03:05 +02:00
|
|
|
uint32_t num_labels,
|
2018-03-24 00:57:03 +01:00
|
|
|
void *parent,
|
|
|
|
struct bgp *bgp_orig,
|
|
|
|
struct prefix *nexthop_orig,
|
|
|
|
int nexthop_self_flag,
|
|
|
|
int debug)
|
2018-03-09 21:52:55 +01:00
|
|
|
{
|
|
|
|
struct prefix *p = &bn->p;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
struct bgp_info *new;
|
|
|
|
char buf_prefix[PREFIX_STRLEN];
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
prefix2str(&bn->p, buf_prefix, sizeof(buf_prefix));
|
2018-03-24 00:57:03 +01:00
|
|
|
zlog_debug("%s: entry: leak-to=%s, p=%s, type=%d, sub_type=%d",
|
|
|
|
__func__, bgp->name_pretty, buf_prefix,
|
|
|
|
source_bi->type, source_bi->sub_type);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* match parent
|
|
|
|
*/
|
|
|
|
for (bi = bn->info; bi; bi = bi->next) {
|
|
|
|
if (bi->extra && bi->extra->parent == parent)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bi) {
|
2018-04-11 06:03:05 +02:00
|
|
|
bool labelssame = labels_same(bi, label, num_labels);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
if (attrhash_cmp(bi->attr, new_attr)
|
2018-04-11 06:03:05 +02:00
|
|
|
&& labelssame
|
2018-03-09 21:52:55 +01:00
|
|
|
&& !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) {
|
|
|
|
|
|
|
|
bgp_attr_unintern(&new_attr);
|
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: ->%s: %s: Found route, no change",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp->name_pretty,
|
2018-03-09 21:52:55 +01:00
|
|
|
buf_prefix);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attr is changed */
|
|
|
|
bgp_info_set_flag(bn, bi, BGP_INFO_ATTR_CHANGED);
|
|
|
|
|
|
|
|
/* Rewrite BGP route information. */
|
|
|
|
if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
|
|
|
|
bgp_info_restore(bn, bi);
|
|
|
|
else
|
|
|
|
bgp_aggregate_decrement(bgp, p, bi, afi, safi);
|
|
|
|
bgp_attr_unintern(&bi->attr);
|
|
|
|
bi->attr = new_attr;
|
|
|
|
bi->uptime = bgp_clock();
|
|
|
|
|
2018-04-11 06:03:05 +02:00
|
|
|
/*
|
|
|
|
* rewrite labels
|
|
|
|
*/
|
|
|
|
if (!labelssame)
|
|
|
|
setlabels(bi, label, num_labels);
|
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
if (nexthop_self_flag)
|
|
|
|
bgp_info_set_flag(bn, bi, BGP_INFO_ANNC_NH_SELF);
|
|
|
|
|
|
|
|
struct bgp *bgp_nexthop = bgp;
|
|
|
|
int nh_valid;
|
|
|
|
|
|
|
|
if (bi->extra && bi->extra->bgp_orig)
|
|
|
|
bgp_nexthop = bi->extra->bgp_orig;
|
|
|
|
|
|
|
|
/* No nexthop tracking for redistributed routes */
|
|
|
|
if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
|
|
|
|
nh_valid = 1;
|
|
|
|
else
|
|
|
|
/*
|
|
|
|
* TBD do we need to do anything about the
|
|
|
|
* 'connected' parameter?
|
|
|
|
*/
|
|
|
|
nh_valid = bgp_find_or_add_nexthop(
|
|
|
|
bgp, bgp_nexthop,
|
|
|
|
afi, bi, NULL, 0);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: nexthop is %svalid (in vrf %s)",
|
|
|
|
__func__, (nh_valid ? "" : "not "),
|
|
|
|
bgp_nexthop->name_pretty);
|
|
|
|
|
|
|
|
if (nh_valid)
|
|
|
|
bgp_info_set_flag(bn, bi, BGP_INFO_VALID);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
/* Process change. */
|
|
|
|
bgp_aggregate_increment(bgp, p, bi, afi, safi);
|
|
|
|
bgp_process(bgp, bn, afi, safi);
|
|
|
|
bgp_unlock_node(bn);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: ->%s: %s Found route, changed attr",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp->name_pretty, buf_prefix);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
|
|
|
|
bgp->peer_self, new_attr, bn);
|
|
|
|
|
|
|
|
if (nexthop_self_flag)
|
|
|
|
bgp_info_set_flag(bn, new, BGP_INFO_ANNC_NH_SELF);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-04-11 06:03:05 +02:00
|
|
|
if (num_labels)
|
|
|
|
setlabels(new, label, num_labels);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
bgp_info_extra_get(new);
|
|
|
|
new->extra->parent = parent;
|
|
|
|
|
|
|
|
if (bgp_orig)
|
|
|
|
new->extra->bgp_orig = bgp_orig;
|
|
|
|
if (nexthop_orig)
|
|
|
|
new->extra->nexthop_orig = *nexthop_orig;
|
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
/*
|
|
|
|
* nexthop tracking for unicast routes
|
|
|
|
*/
|
|
|
|
struct bgp *bgp_nexthop = bgp;
|
|
|
|
int nh_valid;
|
|
|
|
|
|
|
|
if (new->extra && new->extra->bgp_orig)
|
|
|
|
bgp_nexthop = new->extra->bgp_orig;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No nexthop tracking for redistributed routes because
|
|
|
|
* their originating protocols will do the tracking and
|
|
|
|
* withdraw those routes if the nexthops become unreachable
|
|
|
|
*/
|
|
|
|
if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
|
|
|
|
nh_valid = 1;
|
|
|
|
else
|
|
|
|
/*
|
|
|
|
* TBD do we need to do anything about the
|
|
|
|
* 'connected' parameter?
|
|
|
|
*/
|
|
|
|
nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop,
|
|
|
|
afi, new, NULL, 0);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: nexthop is %svalid (in vrf %s)",
|
|
|
|
__func__, (nh_valid ? "" : "not "),
|
|
|
|
bgp_nexthop->name_pretty);
|
|
|
|
if (nh_valid)
|
|
|
|
bgp_info_set_flag(bn, new, BGP_INFO_VALID);
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
bgp_aggregate_increment(bgp, p, new, afi, safi);
|
|
|
|
bgp_info_add(bn, new);
|
|
|
|
|
|
|
|
bgp_unlock_node(bn);
|
|
|
|
bgp_process(bgp, bn, afi, safi);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: ->%s: %s: Added new route", __func__,
|
2018-03-24 00:57:03 +01:00
|
|
|
bgp->name_pretty, buf_prefix);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */
|
|
|
|
void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
|
|
|
|
struct bgp *bgp_vrf, /* from */
|
|
|
|
struct bgp_info *info_vrf) /* route */
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
|
|
|
struct prefix *p = &info_vrf->net->p;
|
|
|
|
afi_t afi = family2afi(p->family);
|
|
|
|
struct attr static_attr = {0};
|
|
|
|
struct attr *new_attr = NULL;
|
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
|
|
|
mpls_label_t label_val;
|
|
|
|
mpls_label_t label;
|
|
|
|
struct bgp_node *bn;
|
|
|
|
const char *debugmsg;
|
2018-03-24 00:57:03 +01:00
|
|
|
int nexthop_self_flag = 0;
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: from vrf %s", __func__, bgp_vrf->name_pretty);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-03-20 23:57:08 +01:00
|
|
|
if (debug && info_vrf->attr->ecommunity) {
|
|
|
|
char *s = ecommunity_ecom2str(info_vrf->attr->ecommunity,
|
|
|
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
zlog_debug("%s: info_vrf->type=%d, EC{%s}", __func__,
|
|
|
|
info_vrf->type, s);
|
2018-03-20 23:57:08 +01:00
|
|
|
XFREE(MTYPE_ECOMMUNITY_STR, s);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bgp_vpn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!afi) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: can't get afi of prefix", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* loop check */
|
|
|
|
if (info_vrf->extra && info_vrf->extra->bgp_orig == bgp_vpn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bgp_attr_dup(&static_attr, info_vrf->attr); /* shallow copy */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* route map handling
|
|
|
|
*/
|
|
|
|
if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
|
|
|
|
struct bgp_info info;
|
|
|
|
route_map_result_t ret;
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
info.peer = bgp_vpn->peer_self;
|
|
|
|
info.attr = &static_attr;
|
|
|
|
ret = route_map_apply(
|
|
|
|
bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN],
|
|
|
|
p, RMAP_BGP, &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",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp_vrf->name_pretty,
|
2018-03-09 21:52:55 +01:00
|
|
|
bgp_vrf->vpn_policy[afi]
|
|
|
|
.rmap[BGP_VPN_POLICY_DIR_TOVPN]
|
|
|
|
->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-20 23:57:08 +01:00
|
|
|
if (debug && static_attr.ecommunity) {
|
|
|
|
char *s = ecommunity_ecom2str(static_attr.ecommunity,
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
struct ecommunity *old_ecom;
|
|
|
|
struct ecommunity *new_ecom;
|
|
|
|
|
|
|
|
old_ecom = static_attr.ecommunity;
|
|
|
|
if (old_ecom) {
|
|
|
|
new_ecom = ecommunity_merge(
|
|
|
|
ecommunity_dup(old_ecom),
|
|
|
|
bgp_vrf->vpn_policy[afi]
|
|
|
|
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
|
|
|
|
if (!old_ecom->refcnt)
|
|
|
|
ecommunity_free(&old_ecom);
|
|
|
|
} else {
|
|
|
|
new_ecom = ecommunity_dup(
|
|
|
|
bgp_vrf->vpn_policy[afi]
|
|
|
|
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
|
|
|
|
}
|
|
|
|
static_attr.ecommunity = new_ecom;
|
|
|
|
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES));
|
|
|
|
|
2018-03-20 23:57:08 +01:00
|
|
|
if (debug && static_attr.ecommunity) {
|
|
|
|
char *s = ecommunity_ecom2str(static_attr.ecommunity,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* Nexthop */
|
|
|
|
/* if policy nexthop not set, use 0 */
|
|
|
|
if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
|
|
|
|
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
|
|
|
|
|
|
|
|
struct prefix *nexthop =
|
|
|
|
&bgp_vrf->vpn_policy[afi].tovpn_nexthop;
|
|
|
|
switch (nexthop->family) {
|
|
|
|
case AF_INET:
|
|
|
|
/* prevent mp_nexthop_global_in <- self in bgp_route.c
|
|
|
|
*/
|
|
|
|
static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr;
|
|
|
|
|
|
|
|
static_attr.mp_nexthop_global_in = nexthop->u.prefix4;
|
|
|
|
static_attr.mp_nexthop_len = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
static_attr.mp_nexthop_global = nexthop->u.prefix6;
|
|
|
|
static_attr.mp_nexthop_len = 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
} else {
|
2018-03-24 00:57:03 +01:00
|
|
|
if (afi == AFI_IP) {
|
|
|
|
/* For ipv4, copy to multiprotocol nexthop field */
|
|
|
|
static_attr.mp_nexthop_global_in = static_attr.nexthop;
|
2018-03-09 21:52:55 +01:00
|
|
|
static_attr.mp_nexthop_len = 4;
|
2018-03-24 00:57:03 +01:00
|
|
|
/* XXX Leave static_attr.nexthop intact for NHT */
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
label_val = bgp_vrf->vpn_policy[afi].tovpn_label;
|
|
|
|
if (label_val == MPLS_LABEL_NONE) {
|
2018-04-11 04:03:01 +02:00
|
|
|
encode_label(MPLS_LABEL_IMPLICIT_NULL, &label);
|
2018-03-09 21:52:55 +01:00
|
|
|
} else {
|
|
|
|
encode_label(label_val, &label);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set originator ID to "me" */
|
|
|
|
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
|
|
|
|
static_attr.originator_id = bgp_vpn->router_id;
|
|
|
|
|
|
|
|
|
|
|
|
new_attr = bgp_attr_intern(
|
|
|
|
&static_attr); /* hashed refcounted everything */
|
|
|
|
bgp_attr_flush(&static_attr); /* free locally-allocated parts */
|
|
|
|
|
2018-03-19 03:12:45 +01:00
|
|
|
if (debug && new_attr->ecommunity) {
|
|
|
|
char *s = ecommunity_ecom2str(new_attr->ecommunity,
|
|
|
|
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 */
|
|
|
|
|
|
|
|
bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
|
|
|
|
&(bgp_vrf->vpn_policy[afi].tovpn_rd));
|
|
|
|
|
|
|
|
struct bgp_info *new_info;
|
|
|
|
|
|
|
|
new_info = leak_update(bgp_vpn, bn, new_attr, afi, safi, info_vrf,
|
2018-03-24 00:57:03 +01:00
|
|
|
&label, 1, info_vrf, bgp_vrf, 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)
|
|
|
|
vpn_leak_to_vrf_update(bgp_vrf, new_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
|
|
|
struct bgp *bgp_vrf, /* from */
|
|
|
|
struct bgp_info *info_vrf) /* route */
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
|
|
|
struct prefix *p = &info_vrf->net->p;
|
|
|
|
afi_t afi = family2afi(p->family);
|
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
struct bgp_node *bn;
|
|
|
|
const char *debugmsg;
|
2018-03-24 00:57:03 +01:00
|
|
|
char buf_prefix[PREFIX_STRLEN];
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
prefix2str(p, buf_prefix, sizeof(buf_prefix));
|
|
|
|
zlog_debug(
|
|
|
|
"%s: entry: leak-from=%s, p=%s, type=%d, sub_type=%d",
|
|
|
|
__func__, bgp_vrf->name_pretty, buf_prefix,
|
|
|
|
info_vrf->type, info_vrf->sub_type);
|
|
|
|
}
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
if (info_vrf->type != ZEBRA_ROUTE_BGP) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: wrong type %d", __func__,
|
|
|
|
info_vrf->type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (info_vrf->sub_type != BGP_ROUTE_NORMAL
|
|
|
|
&& info_vrf->sub_type != BGP_ROUTE_STATIC) {
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: wrong sub_type %d", __func__,
|
|
|
|
info_vrf->sub_type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!bgp_vpn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!afi) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: can't get afi of prefix", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: withdrawing (info_vrf=%p)", __func__, info_vrf);
|
|
|
|
|
|
|
|
bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
|
|
|
|
&(bgp_vrf->vpn_policy[afi].tovpn_rd));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vrf -> vpn
|
|
|
|
* match original bi imported from
|
|
|
|
*/
|
|
|
|
for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
|
|
|
|
if (bi->extra && bi->extra->parent == info_vrf) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bi) {
|
|
|
|
/* withdraw from looped vrfs as well */
|
|
|
|
vpn_leak_to_vrf_withdraw(bgp_vpn, bi);
|
|
|
|
|
|
|
|
bgp_aggregate_decrement(bgp_vpn, p, bi, afi, safi);
|
|
|
|
bgp_info_delete(bn, bi);
|
|
|
|
bgp_process(bgp_vpn, bn, afi, safi);
|
|
|
|
}
|
|
|
|
bgp_unlock_node(bn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
|
|
|
|
struct bgp *bgp_vrf, /* from */
|
|
|
|
afi_t afi)
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
|
|
|
struct bgp_node *prn;
|
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Walk vpn table, delete bi with bgp_orig == bgp_vrf
|
|
|
|
*/
|
|
|
|
for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn;
|
|
|
|
prn = bgp_route_next(prn)) {
|
|
|
|
|
|
|
|
struct bgp_table *table;
|
|
|
|
struct bgp_node *bn;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
|
|
|
|
/* This is the per-RD table of prefixes */
|
|
|
|
table = prn->info;
|
|
|
|
|
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
|
|
|
|
|
|
|
|
char buf[PREFIX2STR_BUFFER];
|
|
|
|
|
|
|
|
if (debug && bn->info) {
|
|
|
|
zlog_debug(
|
|
|
|
"%s: looking at prefix %s", __func__,
|
|
|
|
prefix2str(&bn->p, buf, sizeof(buf)));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (bi = bn->info; bi; bi = bi->next) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: type %d, sub_type %d",
|
|
|
|
__func__, bi->type,
|
|
|
|
bi->sub_type);
|
|
|
|
if (bi->sub_type != BGP_ROUTE_IMPORTED)
|
|
|
|
continue;
|
|
|
|
if (!bi->extra)
|
|
|
|
continue;
|
|
|
|
if ((struct bgp *)bi->extra->bgp_orig
|
|
|
|
== bgp_vrf) {
|
|
|
|
/* delete route */
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: deleting it\n",
|
|
|
|
__func__);
|
|
|
|
bgp_aggregate_decrement(bgp_vpn, &bn->p,
|
|
|
|
bi, afi, safi);
|
|
|
|
bgp_info_delete(bn, bi);
|
|
|
|
bgp_process(bgp_vpn, bn, afi, safi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */
|
|
|
|
struct bgp *bgp_vrf, /* from */
|
|
|
|
afi_t afi)
|
|
|
|
{
|
|
|
|
struct bgp_node *bn;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
|
2018-03-24 00:57:03 +01:00
|
|
|
bgp_vrf->name_pretty);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
for (bn = bgp_table_top(bgp_vrf->rib[afi][SAFI_UNICAST]); bn;
|
|
|
|
bn = bgp_route_next(bn)) {
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: node=%p", __func__, bn);
|
|
|
|
|
|
|
|
for (bi = bn->info; bi; bi = bi->next) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: calling vpn_leak_from_vrf_update",
|
|
|
|
__func__);
|
|
|
|
vpn_leak_from_vrf_update(bgp_vpn, bgp_vrf, bi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
|
|
|
|
struct bgp *bgp_vpn, /* from */
|
|
|
|
struct bgp_info *info_vpn) /* route */
|
|
|
|
{
|
|
|
|
struct prefix *p = &info_vpn->net->p;
|
|
|
|
afi_t afi = family2afi(p->family);
|
|
|
|
|
|
|
|
struct attr static_attr = {0};
|
|
|
|
struct attr *new_attr = NULL;
|
|
|
|
struct bgp_node *bn;
|
|
|
|
safi_t safi = SAFI_UNICAST;
|
|
|
|
const char *debugmsg;
|
|
|
|
struct prefix nexthop_orig;
|
|
|
|
mpls_label_t *pLabels = NULL;
|
2018-04-11 06:03:05 +02:00
|
|
|
uint32_t num_labels = 0;
|
2018-03-24 00:57:03 +01:00
|
|
|
int nexthop_self_flag = 1;
|
2018-04-11 19:58:03 +02:00
|
|
|
struct bgp_info *bi_ultimate = NULL;
|
|
|
|
int origin_local = 0;
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
2018-03-16 19:11:37 +01:00
|
|
|
if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for intersection of route targets */
|
|
|
|
if (!ecom_intersect(
|
|
|
|
bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
|
|
|
|
info_vpn->attr->ecommunity)) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug)
|
2018-03-24 00:57:03 +01:00
|
|
|
zlog_debug("%s: updating to vrf %s", __func__,
|
|
|
|
bgp_vrf->name_pretty);
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
bgp_attr_dup(&static_attr, info_vpn->attr); /* shallow copy */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Nexthop: stash and clear
|
|
|
|
*
|
|
|
|
* Nexthop is valid in context of VPN core, but not in destination vrf.
|
|
|
|
* Stash it for later label resolution by vrf ingress path and then
|
|
|
|
* overwrite with 0, i.e., "me", for the sake of vrf advertisement.
|
|
|
|
*/
|
|
|
|
uint8_t nhfamily = NEXTHOP_FAMILY(info_vpn->attr->mp_nexthop_len);
|
|
|
|
|
|
|
|
memset(&nexthop_orig, 0, sizeof(nexthop_orig));
|
|
|
|
nexthop_orig.family = nhfamily;
|
|
|
|
|
|
|
|
switch (nhfamily) {
|
|
|
|
|
|
|
|
case AF_INET:
|
|
|
|
/* save */
|
|
|
|
nexthop_orig.u.prefix4 = info_vpn->attr->mp_nexthop_global_in;
|
|
|
|
nexthop_orig.prefixlen = 32;
|
|
|
|
static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
/* save */
|
|
|
|
nexthop_orig.u.prefix6 = info_vpn->attr->mp_nexthop_global;
|
|
|
|
nexthop_orig.prefixlen = 128;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* route map handling
|
|
|
|
*/
|
|
|
|
if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
|
|
|
|
struct bgp_info info;
|
|
|
|
route_map_result_t ret;
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
info.peer = bgp_vrf->peer_self;
|
|
|
|
info.attr = &static_attr;
|
|
|
|
ret = route_map_apply(bgp_vrf->vpn_policy[afi]
|
|
|
|
.rmap[BGP_VPN_POLICY_DIR_FROMVPN],
|
|
|
|
p, RMAP_BGP, &info);
|
|
|
|
if (RMAP_DENYMATCH == ret) {
|
|
|
|
bgp_attr_flush(&static_attr); /* free any added parts */
|
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: vrf %s vpn-policy route map \"%s\" says DENY, returning",
|
2018-03-24 00:57:03 +01:00
|
|
|
__func__, bgp_vrf->name_pretty,
|
2018-03-09 21:52:55 +01:00
|
|
|
bgp_vrf->vpn_policy[afi]
|
|
|
|
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
|
|
|
|
->name);
|
|
|
|
return;
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
new_attr = bgp_attr_intern(&static_attr);
|
|
|
|
bgp_attr_flush(&static_attr);
|
|
|
|
|
|
|
|
bn = bgp_afi_node_get(bgp_vrf->rib[afi][safi], afi, safi, p, NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
*/
|
2018-04-11 19:58:03 +02:00
|
|
|
|
|
|
|
/* work back to original route */
|
|
|
|
for (bi_ultimate = info_vpn;
|
|
|
|
bi_ultimate->extra && bi_ultimate->extra->parent;
|
|
|
|
bi_ultimate = bi_ultimate->extra->parent)
|
|
|
|
;
|
|
|
|
|
|
|
|
/* if original route was unicast, then it did not arrive over vpn */
|
|
|
|
if (bi_ultimate->net) {
|
|
|
|
struct bgp_table *table;
|
|
|
|
|
|
|
|
table = bgp_node_table(bi_ultimate->net);
|
|
|
|
if (table && (table->safi == SAFI_UNICAST))
|
|
|
|
origin_local = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy labels */
|
|
|
|
if (!origin_local && info_vpn->extra && info_vpn->extra->num_labels) {
|
2018-03-09 21:52:55 +01:00
|
|
|
num_labels = info_vpn->extra->num_labels;
|
|
|
|
if (num_labels > BGP_MAX_LABELS)
|
|
|
|
num_labels = BGP_MAX_LABELS;
|
|
|
|
pLabels = info_vpn->extra->label;
|
|
|
|
}
|
2018-04-11 19:58:03 +02:00
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug) {
|
|
|
|
char buf_prefix[PREFIX_STRLEN];
|
|
|
|
prefix2str(p, buf_prefix, sizeof(buf_prefix));
|
|
|
|
zlog_debug("%s: pfx %s: num_labels %d", __func__, buf_prefix,
|
|
|
|
num_labels);
|
|
|
|
}
|
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
leak_update(bgp_vrf, bn, new_attr, afi, safi, info_vpn,
|
|
|
|
pLabels, num_labels,
|
|
|
|
info_vpn, /* parent */
|
|
|
|
bgp_vpn, &nexthop_orig, nexthop_self_flag, debug);
|
2018-03-09 21:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
|
|
|
|
struct bgp_info *info_vpn) /* route */
|
|
|
|
{
|
|
|
|
struct listnode *mnode, *mnnode;
|
|
|
|
struct bgp *bgp;
|
|
|
|
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: start (info_vpn=%p)", __func__, info_vpn);
|
|
|
|
|
|
|
|
/* Loop over VRFs */
|
|
|
|
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
|
|
|
|
|
|
|
|
if (!info_vpn->extra
|
|
|
|
|| info_vpn->extra->bgp_orig != bgp) { /* no loop */
|
|
|
|
vpn_leak_to_vrf_update_onevrf(bgp, bgp_vpn, info_vpn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
|
|
|
|
struct bgp_info *info_vpn) /* route */
|
|
|
|
{
|
2018-03-22 02:20:39 +01:00
|
|
|
struct prefix *p;
|
|
|
|
afi_t afi;
|
2018-03-09 21:52:55 +01:00
|
|
|
safi_t safi = SAFI_UNICAST;
|
|
|
|
struct bgp *bgp;
|
|
|
|
struct listnode *mnode, *mnnode;
|
|
|
|
struct bgp_node *bn;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
const char *debugmsg;
|
2018-03-24 00:57:03 +01:00
|
|
|
char buf_prefix[PREFIX_STRLEN];
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
|
2018-03-24 00:57:03 +01:00
|
|
|
if (debug) {
|
|
|
|
prefix2str(&info_vpn->net->p, buf_prefix, sizeof(buf_prefix));
|
|
|
|
zlog_debug("%s: entry: p=%s, type=%d, sub_type=%d",
|
|
|
|
__func__, buf_prefix,
|
|
|
|
info_vpn->type, info_vpn->sub_type);
|
|
|
|
}
|
|
|
|
|
2018-03-09 21:52:55 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: start (info_vpn=%p)", __func__, info_vpn);
|
|
|
|
|
2018-03-22 02:20:39 +01:00
|
|
|
if (!info_vpn->net) {
|
2018-03-22 05:18:25 +01:00
|
|
|
#if ENABLE_BGP_VNC
|
2018-03-22 02:20:39 +01:00
|
|
|
/* BGP_ROUTE_RFP routes do not have info_vpn->net set (yet) */
|
|
|
|
if (info_vpn->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
info_vpn->sub_type == BGP_ROUTE_RFP) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2018-03-22 05:18:25 +01:00
|
|
|
#endif
|
2018-03-22 02:20:39 +01:00
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: info_vpn->net unexpectedly NULL, no prefix, bailing",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = &info_vpn->net->p;
|
|
|
|
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)
|
|
|
|
zlog_debug("%s: skipping: %s", __func__,
|
|
|
|
debugmsg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for intersection of route targets */
|
|
|
|
if (!ecom_intersect(bgp->vpn_policy[afi]
|
|
|
|
.rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
|
|
|
|
info_vpn->attr->ecommunity)) {
|
|
|
|
|
|
|
|
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);
|
|
|
|
for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
|
|
|
|
if (bi->extra
|
|
|
|
&& (struct bgp_info *)bi->extra->parent
|
|
|
|
== info_vpn) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bi) {
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: deleting bi %p", __func__, bi);
|
|
|
|
bgp_aggregate_decrement(bgp, p, bi, afi, safi);
|
|
|
|
bgp_info_delete(bn, bi);
|
|
|
|
bgp_process(bgp, bn, afi, safi);
|
|
|
|
}
|
|
|
|
bgp_unlock_node(bn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
|
|
|
|
afi_t afi)
|
|
|
|
{
|
|
|
|
struct bgp_node *bn;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
safi_t safi = SAFI_UNICAST;
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
|
|
|
|
struct bgp *bgp_vpn = bgp_get_default();
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: entry", __func__);
|
|
|
|
/*
|
|
|
|
* Walk vrf table, delete bi with bgp_orig == bgp_vpn
|
|
|
|
*/
|
|
|
|
for (bn = bgp_table_top(bgp_vrf->rib[afi][safi]); bn;
|
|
|
|
bn = bgp_route_next(bn)) {
|
|
|
|
|
|
|
|
for (bi = bn->info; bi; bi = bi->next) {
|
|
|
|
if (bi->extra && bi->extra->bgp_orig == bgp_vpn) {
|
|
|
|
|
|
|
|
/* delete route */
|
|
|
|
bgp_aggregate_decrement(bgp_vrf, &bn->p, bi,
|
|
|
|
afi, safi);
|
|
|
|
bgp_info_delete(bn, bi);
|
|
|
|
bgp_process(bgp_vrf, bn, afi, safi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
|
|
|
|
struct bgp *bgp_vpn, /* from */
|
|
|
|
afi_t afi)
|
|
|
|
{
|
|
|
|
struct prefix_rd prd;
|
|
|
|
struct bgp_node *prn;
|
|
|
|
safi_t safi = SAFI_MPLS_VPN;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Walk vpn table
|
|
|
|
*/
|
|
|
|
for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn;
|
|
|
|
prn = bgp_route_next(prn)) {
|
|
|
|
|
|
|
|
struct bgp_table *table;
|
|
|
|
struct bgp_node *bn;
|
|
|
|
struct bgp_info *bi;
|
|
|
|
|
|
|
|
memset(&prd, 0, sizeof(prd));
|
|
|
|
prd.family = AF_UNSPEC;
|
|
|
|
prd.prefixlen = 64;
|
|
|
|
memcpy(prd.val, prn->p.u.val, 8);
|
|
|
|
|
|
|
|
/* This is the per-RD table of prefixes */
|
|
|
|
table = prn->info;
|
|
|
|
|
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
|
|
|
|
|
|
|
|
for (bi = bn->info; bi; bi = bi->next) {
|
|
|
|
|
|
|
|
if (bi->extra && bi->extra->bgp_orig == bgp_vrf)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vpn_leak_to_vrf_update_onevrf(bgp_vrf, bgp_vpn,
|
|
|
|
bi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name)
|
|
|
|
{
|
|
|
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
|
|
|
|
afi_t afi;
|
|
|
|
struct route_map *rmap;
|
|
|
|
|
|
|
|
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
|
|
|
|
&& bgp->inst_type != BGP_INSTANCE_TYPE_VRF) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rmap = route_map_lookup_by_name(rmap_name); /* NULL if deleted */
|
|
|
|
|
|
|
|
for (afi = 0; afi < AFI_MAX; ++afi) {
|
|
|
|
|
|
|
|
if (vpn_leak_to_vpn_active(bgp, afi, NULL)
|
|
|
|
&& bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]
|
|
|
|
&& !strcmp(rmap_name,
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.rmap_name[BGP_VPN_POLICY_DIR_TOVPN])) {
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: rmap \"%s\" matches vrf-policy tovpn for as %d afi %s",
|
|
|
|
__func__, rmap_name, bgp->as,
|
|
|
|
afi2str(afi));
|
|
|
|
|
|
|
|
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
|
|
|
|
bgp_get_default(), bgp);
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: after vpn_leak_prechange",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
if (!rmap)
|
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.rmap[BGP_VPN_POLICY_DIR_TOVPN] = NULL;
|
|
|
|
|
|
|
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
|
|
|
|
bgp_get_default(), bgp);
|
|
|
|
if (debug)
|
|
|
|
zlog_debug("%s: after vpn_leak_postchange",
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
|
2018-03-16 19:11:37 +01:00
|
|
|
char *mapname = bgp->vpn_policy[afi]
|
|
|
|
.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
|
2018-03-09 21:52:55 +01:00
|
|
|
|
2018-03-18 23:08:45 +01:00
|
|
|
if (vpn_leak_from_vpn_active(bgp, afi, NULL) &&
|
2018-03-16 19:11:37 +01:00
|
|
|
mapname &&
|
|
|
|
!strcmp(rmap_name, mapname)) {
|
|
|
|
|
|
|
|
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-03-16 19:11:37 +01:00
|
|
|
if (!rmap) {
|
2018-03-09 21:52:55 +01:00
|
|
|
bgp->vpn_policy[afi]
|
|
|
|
.rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
|
|
|
|
NULL;
|
2018-03-16 19:11:37 +01:00
|
|
|
}
|
2018-03-09 21:52:55 +01:00
|
|
|
|
|
|
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
|
|
|
|
bgp_get_default(), bgp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv4_prefixlen = 1;
|
|
|
|
int idx_ext_community = 3;
|
|
|
|
int idx_label = 5;
|
|
|
|
return bgp_static_set_safi(
|
|
|
|
AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg,
|
|
|
|
argv[idx_ext_community]->arg, argv[idx_label]->arg, NULL, 0,
|
|
|
|
NULL, NULL, NULL, NULL);
|
2016-01-12 19:41:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN (vpnv4_network_route_map,
|
|
|
|
vpnv4_network_route_map_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) route-map WORD",
|
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")
|
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv4_prefixlen = 1;
|
|
|
|
int idx_ext_community = 3;
|
|
|
|
int idx_label = 5;
|
|
|
|
int idx_word_2 = 7;
|
|
|
|
return bgp_static_set_safi(
|
|
|
|
AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg,
|
|
|
|
argv[idx_ext_community]->arg, argv[idx_label]->arg,
|
|
|
|
argv[idx_word_2]->arg, 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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv4_prefixlen = 2;
|
|
|
|
int idx_ext_community = 4;
|
|
|
|
int idx_label = 6;
|
|
|
|
return bgp_static_unset_safi(AFI_IP, SAFI_MPLS_VPN, vty,
|
|
|
|
argv[idx_ipv4_prefixlen]->arg,
|
|
|
|
argv[idx_ext_community]->arg,
|
|
|
|
argv[idx_label]->arg, 0, 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,
|
2017-09-14 20:07:30 +02:00
|
|
|
"network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) [route-map WORD]",
|
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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv6_prefix = 1;
|
|
|
|
int idx_ext_community = 3;
|
|
|
|
int idx_label = 5;
|
|
|
|
int idx_word_2 = 7;
|
|
|
|
if (argc == 8)
|
|
|
|
return bgp_static_set_safi(
|
|
|
|
AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg,
|
|
|
|
argv[idx_ext_community]->arg, argv[idx_label]->arg,
|
|
|
|
argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
|
|
|
|
else
|
|
|
|
return bgp_static_set_safi(
|
|
|
|
AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg,
|
|
|
|
argv[idx_ext_community]->arg, argv[idx_label]->arg,
|
|
|
|
NULL, 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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv6_prefix = 2;
|
|
|
|
int idx_ext_community = 4;
|
|
|
|
int idx_label = 6;
|
|
|
|
return bgp_static_unset_safi(AFI_IP6, SAFI_MPLS_VPN, vty,
|
|
|
|
argv[idx_ipv6_prefix]->arg,
|
|
|
|
argv[idx_ext_community]->arg,
|
|
|
|
argv[idx_label]->arg, 0, NULL, NULL, NULL);
|
2016-12-19 10:53:38 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +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-03-27 21:13:34 +02:00
|
|
|
uint8_t use_json)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct bgp *bgp;
|
|
|
|
struct bgp_table *table;
|
|
|
|
|
|
|
|
bgp = bgp_get_default();
|
|
|
|
if (bgp == NULL) {
|
|
|
|
if (!use_json)
|
|
|
|
vty_out(vty, "No BGP process is configured\n");
|
2017-07-26 17:27:37 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "{}\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
2017-09-29 00:51:31 +02:00
|
|
|
table = bgp->rib[afi][SAFI_MPLS_VPN];
|
2018-02-09 19:22:50 +01:00
|
|
|
return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type,
|
|
|
|
output_arg, use_json);
|
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,
|
2017-09-14 20:07:30 +02:00
|
|
|
"show bgp "BGP_AFI_CMD_STR" vpn all [rd ASN:NN_OR_IP-ADDRESS:NN] [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"
|
|
|
|
JSON_STR)
|
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int ret;
|
|
|
|
struct prefix_rd prd;
|
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
|
2017-09-29 17:32:10 +02:00
|
|
|
if (argv_find(argv, argc, "rd", &idx)) {
|
2018-02-09 19:22:50 +01:00
|
|
|
ret = str2prefix_rd(argv[idx + 1]->arg, &prd);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!ret) {
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Malformed Route Distinguisher\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, &prd,
|
|
|
|
bgp_show_type_normal, NULL, 0,
|
|
|
|
use_json(argc, argv));
|
|
|
|
} else {
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, NULL,
|
|
|
|
bgp_show_type_normal, NULL, 0,
|
|
|
|
use_json(argc, argv));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:54:31 +02:00
|
|
|
ALIAS(show_bgp_ip_vpn_all_rd,
|
|
|
|
show_bgp_ip_vpn_rd_cmd,
|
|
|
|
"show bgp "BGP_AFI_CMD_STR" vpn rd ASN:NN_OR_IP-ADDRESS:NN [json]",
|
|
|
|
SHOW_STR
|
|
|
|
BGP_STR
|
|
|
|
BGP_VPNVX_HELP_STR
|
|
|
|
"Display VPN NLRI specific information\n"
|
|
|
|
"Display information for a route distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n"
|
|
|
|
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,
|
2017-09-29 17:54:31 +02:00
|
|
|
"show ip bgp "BGP_AFI_CMD_STR" vpn rd ASN:NN_OR_IP-ADDRESS:NN",
|
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
|
2017-01-27 21:51:41 +01:00
|
|
|
"Address Family modifier\n"
|
2002-12-13 21:15:29 +01:00
|
|
|
"Display information for a route distinguisher\n"
|
|
|
|
"VPN Route Distinguisher\n")
|
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ext_community = argc - 1;
|
|
|
|
int ret;
|
|
|
|
struct prefix_rd prd;
|
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
|
|
|
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
|
|
|
if (!ret) {
|
|
|
|
vty_out(vty, "%% Malformed Route Distinguisher\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal,
|
|
|
|
NULL, 0, 0);
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-01-24 20:52:06 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
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-24 20:52:06 +01:00
|
|
|
}
|
|
|
|
|
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-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
2017-01-08 18:09:04 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
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,
|
2017-09-14 20:07:30 +02:00
|
|
|
"show [ip] bgp <vpnv4|vpnv6> rd ASN:NN_OR_IP-ADDRESS:NN 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"
|
|
|
|
"Display BGP tags for prefixes\n")
|
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ext_community = 5;
|
|
|
|
int ret;
|
|
|
|
struct prefix_rd prd;
|
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
|
|
|
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
|
|
|
if (!ret) {
|
|
|
|
vty_out(vty, "%% Malformed Route Distinguisher\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal,
|
|
|
|
NULL, 1, 0);
|
|
|
|
}
|
|
|
|
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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv4 = 6;
|
|
|
|
union sockunion su;
|
|
|
|
struct peer *peer;
|
|
|
|
int ret;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t uj = use_json(argc, argv);
|
2017-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
|
|
|
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(json_no, "warning",
|
|
|
|
"Malformed address");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
|
|
|
argv[idx_ipv4]->arg);
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
peer = peer_lookup(NULL, &su);
|
|
|
|
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(
|
|
|
|
json_no, "warning",
|
|
|
|
"No such neighbor or address family");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_neighbor,
|
|
|
|
&su, 0, uj);
|
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-01-08 18:09:04 +01:00
|
|
|
DEFUN (show_ip_bgp_vpn_rd_neighbor_routes,
|
|
|
|
show_ip_bgp_vpn_rd_neighbor_routes_cmd,
|
2017-09-14 20:07:30 +02:00
|
|
|
"show [ip] bgp <vpnv4|vpnv6> rd ASN:NN_OR_IP-ADDRESS:NN 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"
|
|
|
|
"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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ext_community = 5;
|
|
|
|
int idx_ipv4 = 7;
|
|
|
|
int ret;
|
|
|
|
union sockunion su;
|
|
|
|
struct peer *peer;
|
|
|
|
struct prefix_rd prd;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t uj = use_json(argc, argv);
|
2017-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
|
|
|
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
|
|
|
if (!ret) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(
|
|
|
|
json_no, "warning",
|
|
|
|
"Malformed Route Distinguisher");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Malformed Route Distinguisher\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(json_no, "warning",
|
|
|
|
"Malformed address");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
|
|
|
argv[idx_ext_community]->arg);
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
peer = peer_lookup(NULL, &su);
|
|
|
|
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(
|
|
|
|
json_no, "warning",
|
|
|
|
"No such neighbor or address family");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_neighbor,
|
|
|
|
&su, 0, uj);
|
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ipv4 = 6;
|
|
|
|
int ret;
|
|
|
|
struct peer *peer;
|
|
|
|
union sockunion su;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t uj = use_json(argc, argv);
|
2017-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
|
|
|
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(json_no, "warning",
|
|
|
|
"Malformed address");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
|
|
|
argv[idx_ipv4]->arg);
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
peer = peer_lookup(NULL, &su);
|
|
|
|
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(
|
|
|
|
json_no, "warning",
|
|
|
|
"No such neighbor or address family");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
return show_adj_route_vpn(vty, peer, NULL, AFI_IP,
|
|
|
|
SAFI_MPLS_VPN, uj);
|
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
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,
|
2017-09-14 20:07:30 +02:00
|
|
|
"show [ip] bgp <vpnv4|vpnv6> rd ASN:NN_OR_IP-ADDRESS:NN 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"
|
|
|
|
"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
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int idx_ext_community = 5;
|
|
|
|
int idx_ipv4 = 7;
|
|
|
|
int ret;
|
|
|
|
struct peer *peer;
|
|
|
|
struct prefix_rd prd;
|
|
|
|
union sockunion su;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t uj = use_json(argc, argv);
|
2017-07-17 14:03:14 +02:00
|
|
|
afi_t afi;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
|
|
|
|
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(json_no, "warning",
|
|
|
|
"Malformed address");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty, "Malformed address: %s\n",
|
|
|
|
argv[idx_ext_community]->arg);
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
peer = peer_lookup(NULL, &su);
|
|
|
|
if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(
|
|
|
|
json_no, "warning",
|
|
|
|
"No such neighbor or address family");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% No such neighbor or address family\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
|
|
|
if (!ret) {
|
|
|
|
if (uj) {
|
|
|
|
json_object *json_no = NULL;
|
|
|
|
json_no = json_object_new_object();
|
|
|
|
json_object_string_add(
|
|
|
|
json_no, "warning",
|
|
|
|
"Malformed Route Distinguisher");
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string(json_no));
|
|
|
|
json_object_free(json_no);
|
|
|
|
} else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Malformed Route Distinguisher\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
return show_adj_route_vpn(vty, peer, &prd, AFI_IP,
|
|
|
|
SAFI_MPLS_VPN, uj);
|
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-01-18 12:27:52 +01:00
|
|
|
#endif /* KEEP_OLD_VPN_COMMANDS */
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
void bgp_mplsvpn_init(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
install_element(BGP_VPNV4_NODE, &vpnv4_network_cmd);
|
|
|
|
install_element(BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd);
|
|
|
|
install_element(BGP_VPNV4_NODE, &no_vpnv4_network_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
install_element(BGP_VPNV6_NODE, &vpnv6_network_cmd);
|
|
|
|
install_element(BGP_VPNV6_NODE, &no_vpnv6_network_cmd);
|
2016-12-19 10:53:38 +01:00
|
|
|
|
2017-07-17 14:03:14 +02: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-07-17 14:03:14 +02: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;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
|
|
|
|
struct ecommunity *ec;
|
|
|
|
|
|
|
|
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ec = bgp->vpn_policy[AFI_IP].import_redirect_rtlist;
|
|
|
|
|
|
|
|
if (ecom_intersect(ec, eckey))
|
|
|
|
return bgp->vrf_id;
|
|
|
|
}
|
|
|
|
return VRF_UNKNOWN;
|
|
|
|
}
|