2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2016-09-05 11:07:25 +02:00
|
|
|
/* Ethernet-VPN Packet and vty Processing File
|
2017-05-13 10:25:29 +02:00
|
|
|
* Copyright (C) 2016 6WIND
|
2017-05-15 23:34:04 +02:00
|
|
|
* Copyright (C) 2017 Cumulus Networks, Inc.
|
2017-05-13 10:25:29 +02:00
|
|
|
*/
|
2016-09-05 11:07:25 +02:00
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "command.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "stream.h"
|
2017-05-15 23:27:51 +02:00
|
|
|
#include "hash.h"
|
|
|
|
#include "jhash.h"
|
2017-05-15 23:34:04 +02:00
|
|
|
#include "zclient.h"
|
2016-09-05 11:07:25 +02:00
|
|
|
|
2020-10-15 21:33:09 +02:00
|
|
|
#include "lib/printfrr.h"
|
|
|
|
|
2016-09-05 11:07:25 +02:00
|
|
|
#include "bgpd/bgp_attr_evpn.h"
|
|
|
|
#include "bgpd/bgpd.h"
|
|
|
|
#include "bgpd/bgp_table.h"
|
|
|
|
#include "bgpd/bgp_route.h"
|
|
|
|
#include "bgpd/bgp_attr.h"
|
|
|
|
#include "bgpd/bgp_mplsvpn.h"
|
2017-06-16 21:12:57 +02:00
|
|
|
#include "bgpd/bgp_label.h"
|
2016-09-05 11:07:25 +02:00
|
|
|
#include "bgpd/bgp_evpn.h"
|
2017-05-15 23:27:51 +02:00
|
|
|
#include "bgpd/bgp_evpn_private.h"
|
2020-03-27 14:39:51 +01:00
|
|
|
#include "bgpd/bgp_evpn_mh.h"
|
2017-05-15 23:27:51 +02:00
|
|
|
#include "bgpd/bgp_ecommunity.h"
|
2017-05-15 23:34:04 +02:00
|
|
|
#include "bgpd/bgp_encap_types.h"
|
|
|
|
#include "bgpd/bgp_debug.h"
|
2018-06-15 23:08:53 +02:00
|
|
|
#include "bgpd/bgp_errors.h"
|
2017-05-15 23:34:04 +02:00
|
|
|
#include "bgpd/bgp_aspath.h"
|
2017-07-28 02:11:48 +02:00
|
|
|
#include "bgpd/bgp_zebra.h"
|
2017-08-17 08:19:58 +02:00
|
|
|
#include "bgpd/bgp_nexthop.h"
|
bgpd: Re-use TX Addpath IDs where possible
The motivation for this patch is to address a concerning behavior of
tx-addpath-bestpath-per-AS. Prior to this patch, all paths' TX ID was
pre-determined as the path was received from a peer. However, this meant
that any time the path selected as best from an AS changed, bgpd had no
choice but to withdraw the previous best path, and advertise the new
best-path under a new TX ID. This could cause significant network
disruption, especially for the subset of prefixes coming from only one
AS that were also communicated over a bestpath-per-AS session.
The patch's general approach is best illustrated by
txaddpath_update_ids. After a bestpath run (required for best-per-AS to
know what will and will not be sent as addpaths) ID numbers will be
stripped from paths that no longer need to be sent, and held in a pool.
Then, paths that will be sent as addpaths and do not already have ID
numbers will allocate new ID numbers, pulling first from that pool.
Finally, anything left in the pool will be returned to the allocator.
In order for this to work, ID numbers had to be split by strategy. The
tx-addpath-All strategy would keep every ID number "in use" constantly,
preventing IDs from being transferred to different paths. Rather than
create two variables for ID, this patch create a more generic array that
will easily enable more addpath strategies to be implemented. The
previously described ID manipulations will happen per addpath strategy,
and will only be run for strategies that are enabled on at least one
peer.
Finally, the ID numbers are allocated from an allocator that tracks per
AFI/SAFI/Addpath Strategy which IDs are in use. Though it would be very
improbable, there was the possibility with the free-running counter
approach for rollover to cause two paths on the same prefix to get
assigned the same TX ID. As remote as the possibility is, we prefer to
not leave it to chance.
This ID re-use method is not perfect. In some cases you could still get
withdraw-then-add behaviors where not strictly necessary. In the case of
bestpath-per-AS this requires one AS to advertise a prefix for the first
time, then a second AS withdraws that prefix, all within the space of an
already pending MRAI timer. In those situations a withdraw-then-add is
more forgivable, and fixing it would probably require a much more
significant effort, as IDs would need to be moved to ADVs instead of
paths.
Signed-off-by Mitchell Skiba <mskiba@amazon.com>
2018-05-10 01:10:02 +02:00
|
|
|
#include "bgpd/bgp_addpath.h"
|
2019-03-13 02:41:01 +01:00
|
|
|
#include "bgpd/bgp_mac.h"
|
2019-08-01 18:50:56 +02:00
|
|
|
#include "bgpd/bgp_vty.h"
|
2021-01-11 07:32:41 +01:00
|
|
|
#include "bgpd/bgp_nht.h"
|
bgpd: initial batch of evpn lttng tracepoints
Low overhead bgp-evpn TPs have been added which push data out in a binary
format -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@switch:~# lttng list --userspace |grep "frr_bgp:evpn"
frr_bgp:evpn_mh_nh_rmac_zsend (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint)
frr_bgp:evpn_mh_nh_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mh_nhg_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mh_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_bum_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mac_ip_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
root@switch:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
In addition to the tracepoints a babeltrace python plugin for pretty
printing (binary data is converted into grepable strings). Sample usage -
frr_babeltrace.py trace_path
Sample tracepoint output -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1. frr_bgp: evpn_mac_ip_zsend
frr_bgp:evpn_mac_ip_zsend {'action': 'add', 'vni': 1007, 'mac': '00:02:00:00:00:04', 'ip': 'fe80::202:ff:fe00:4', 'vtep': '27.0.0.15', 'esi': '03:44:38:39:ff:ff:01:00:00:02'}
2. frr_bgp: evpn_mh_vtep_zsend
frr_bgp:evpn_mh_vtep_zsend {'action': 'add', 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vtep': '27.0.0.16'}
3. frr_bgp: evpn_mh_nhg_zsend
frr_bgp:evpn_mh_nhg_zsend {'action': 'add', 'type': 'v4', 'nhg': 74999998, 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vrf': 85}
4. frr_bgp: evpn_mh_nh_zsend
frr_bgp:evpn_mh_nh_zsend {'nhg': 74999998, 'vtep': '27.0.0.16', 'svi': 93}
5. frr_bgp: evpn_mh_nh_rmac_zsend
frr_bgp:evpn_mh_nh_rmac_zsend {'action': 'add', 'vrf': 85, 'nh': '::ffff:1b00:12', 'rmac': '00:02:00:00:00:50'}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
2021-09-28 20:18:43 +02:00
|
|
|
#include "bgpd/bgp_trace.h"
|
2021-04-09 01:20:53 +02:00
|
|
|
#include "bgpd/bgp_mpath.h"
|
2023-05-08 05:54:25 +02:00
|
|
|
#include "bgpd/bgp_packet.h"
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Definitions and external declarations.
|
|
|
|
*/
|
|
|
|
DEFINE_QOBJ_TYPE(bgpevpn);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
DEFINE_QOBJ_TYPE(bgp_evpn_es);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2023-05-08 04:28:21 +02:00
|
|
|
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
|
2021-02-17 22:11:49 +01:00
|
|
|
DEFINE_MTYPE_STATIC(BGPD, VRF_ROUTE_TARGET, "L3 Route Target");
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Static function declarations
|
|
|
|
*/
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn);
|
|
|
|
static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn);
|
|
|
|
static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
|
|
|
|
struct bgp_path_info *pi);
|
|
|
|
static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
|
|
|
|
struct bgp_path_info *pi);
|
2021-05-12 00:26:29 +02:00
|
|
|
static void bgp_evpn_remote_ip_hash_iterate(struct bgpevpn *vpn,
|
|
|
|
void (*func)(struct hash_bucket *,
|
|
|
|
void *),
|
|
|
|
void *arg);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
static void bgp_evpn_link_to_vni_svi_hash(struct bgp *bgp, struct bgpevpn *vpn);
|
|
|
|
static void bgp_evpn_unlink_from_vni_svi_hash(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn);
|
|
|
|
static unsigned int vni_svi_hash_key_make(const void *p);
|
|
|
|
static bool vni_svi_hash_cmp(const void *p1, const void *p2);
|
|
|
|
static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
|
|
|
|
struct ipaddr *addr,
|
|
|
|
bool resolve);
|
|
|
|
static void bgp_evpn_remote_ip_hash_link_nexthop(struct hash_bucket *bucket,
|
|
|
|
void *args);
|
|
|
|
static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,
|
|
|
|
void *args);
|
2020-03-28 18:12:04 +01:00
|
|
|
static struct in_addr zero_vtep_ip;
|
2017-05-15 23:27:51 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Private functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make vni hash key.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int vni_hash_key_make(const void *p)
|
2017-05-15 23:27:51 +02:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const struct bgpevpn *vpn = p;
|
2017-05-15 23:27:51 +02:00
|
|
|
return (jhash_1word(vpn->vni, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison function for vni hash
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool vni_hash_cmp(const void *p1, const void *p2)
|
2017-05-15 23:27:51 +02:00
|
|
|
{
|
|
|
|
const struct bgpevpn *vpn1 = p1;
|
|
|
|
const struct bgpevpn *vpn2 = p2;
|
|
|
|
|
2021-07-13 07:46:10 +02:00
|
|
|
return vpn1->vni == vpn2->vni;
|
2017-05-15 23:27:51 +02:00
|
|
|
}
|
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
int vni_list_cmp(void *p1, void *p2)
|
2018-10-15 17:41:39 +02:00
|
|
|
{
|
|
|
|
const struct bgpevpn *vpn1 = p1;
|
|
|
|
const struct bgpevpn *vpn2 = p2;
|
|
|
|
|
|
|
|
return vpn1->vni - vpn2->vni;
|
|
|
|
}
|
|
|
|
|
2017-10-10 03:12:05 +02:00
|
|
|
/*
|
|
|
|
* Make vrf import route target hash key.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int vrf_import_rt_hash_key_make(const void *p)
|
2017-10-10 03:12:05 +02:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const struct vrf_irt_node *irt = p;
|
|
|
|
const char *pnt = irt->rt.val;
|
2018-01-12 15:55:28 +01:00
|
|
|
|
|
|
|
return jhash(pnt, 8, 0x5abc1234);
|
2017-10-10 03:12:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison function for vrf import rt hash
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool vrf_import_rt_hash_cmp(const void *p1, const void *p2)
|
2017-10-10 03:12:05 +02:00
|
|
|
{
|
|
|
|
const struct vrf_irt_node *irt1 = p1;
|
|
|
|
const struct vrf_irt_node *irt2 = p2;
|
|
|
|
|
|
|
|
return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-03-06 19:35:03 +01:00
|
|
|
* Create a new vrf import_rt in evpn instance
|
2017-10-10 03:12:05 +02:00
|
|
|
*/
|
|
|
|
static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt)
|
|
|
|
{
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-10 03:12:05 +02:00
|
|
|
struct vrf_irt_node *irt;
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_NO_DFLT,
|
2019-03-06 19:35:03 +01:00
|
|
|
"vrf import rt new - evpn instance not created yet");
|
2017-10-10 03:12:05 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
irt = XCALLOC(MTYPE_BGP_EVPN_VRF_IMPORT_RT,
|
|
|
|
sizeof(struct vrf_irt_node));
|
|
|
|
|
|
|
|
irt->rt = *rt;
|
|
|
|
irt->vrfs = list_new();
|
|
|
|
|
|
|
|
/* Add to hash */
|
2022-04-20 12:57:53 +02:00
|
|
|
(void)hash_get(bgp_evpn->vrf_import_rt_hash, irt, hash_alloc_intern);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
|
|
|
return irt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the vrf import rt node
|
|
|
|
*/
|
|
|
|
static void vrf_import_rt_free(struct vrf_irt_node *irt)
|
|
|
|
{
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_NO_DFLT,
|
2019-03-06 19:35:03 +01:00
|
|
|
"vrf import rt free - evpn instance not created yet");
|
2017-10-10 03:12:05 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
hash_release(bgp_evpn->vrf_import_rt_hash, irt);
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&irt->vrfs);
|
2017-10-10 03:12:05 +02:00
|
|
|
XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
|
|
|
|
}
|
|
|
|
|
2022-08-30 12:46:26 +02:00
|
|
|
static void hash_vrf_import_rt_free(struct vrf_irt_node *irt)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
|
|
|
|
}
|
|
|
|
|
2017-10-10 03:12:05 +02:00
|
|
|
/*
|
|
|
|
* Function to lookup Import RT node - used to map a RT to set of
|
|
|
|
* VNIs importing routes with that RT.
|
|
|
|
*/
|
|
|
|
static struct vrf_irt_node *lookup_vrf_import_rt(struct ecommunity_val *rt)
|
|
|
|
{
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-10 03:12:05 +02:00
|
|
|
struct vrf_irt_node *irt;
|
|
|
|
struct vrf_irt_node tmp;
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn) {
|
2019-03-06 19:35:03 +01:00
|
|
|
flog_err(
|
|
|
|
EC_BGP_NO_DFLT,
|
|
|
|
"vrf import rt lookup - evpn instance not created yet");
|
2017-10-10 03:12:05 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
2017-10-10 03:12:05 +02:00
|
|
|
memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE);
|
2019-03-06 19:10:02 +01:00
|
|
|
irt = hash_lookup(bgp_evpn->vrf_import_rt_hash, &tmp);
|
2017-10-10 03:12:05 +02:00
|
|
|
return irt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Is specified VRF present on the RT's list of "importing" VRFs?
|
|
|
|
*/
|
|
|
|
static int is_vrf_present_in_irt_vrfs(struct list *vrfs, struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
struct bgp *tmp_bgp_vrf = NULL;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(vrfs, node, nnode, tmp_bgp_vrf)) {
|
|
|
|
if (tmp_bgp_vrf == bgp_vrf)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:27:51 +02:00
|
|
|
/*
|
|
|
|
* Make import route target hash key.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int import_rt_hash_key_make(const void *p)
|
2017-05-15 23:27:51 +02:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const struct irt_node *irt = p;
|
|
|
|
const char *pnt = irt->rt.val;
|
2018-01-12 15:55:28 +01:00
|
|
|
|
|
|
|
return jhash(pnt, 8, 0xdeadbeef);
|
2017-05-15 23:27:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison function for import rt hash
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool import_rt_hash_cmp(const void *p1, const void *p2)
|
2017-05-15 23:27:51 +02:00
|
|
|
{
|
|
|
|
const struct irt_node *irt1 = p1;
|
|
|
|
const struct irt_node *irt2 = p2;
|
|
|
|
|
|
|
|
return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:30:19 +02:00
|
|
|
/*
|
2017-05-15 23:34:04 +02:00
|
|
|
* Create a new import_rt
|
|
|
|
*/
|
|
|
|
static struct irt_node *import_rt_new(struct bgp *bgp,
|
|
|
|
struct ecommunity_val *rt)
|
|
|
|
{
|
|
|
|
struct irt_node *irt;
|
|
|
|
|
|
|
|
irt = XCALLOC(MTYPE_BGP_EVPN_IMPORT_RT, sizeof(struct irt_node));
|
|
|
|
|
|
|
|
irt->rt = *rt;
|
|
|
|
irt->vnis = list_new();
|
|
|
|
|
|
|
|
/* Add to hash */
|
2022-04-20 12:57:53 +02:00
|
|
|
(void)hash_get(bgp->import_rt_hash, irt, hash_alloc_intern);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
return irt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the import rt node
|
2017-05-15 23:30:19 +02:00
|
|
|
*/
|
2017-05-15 23:34:04 +02:00
|
|
|
static void import_rt_free(struct bgp *bgp, struct irt_node *irt)
|
2017-05-15 23:30:19 +02:00
|
|
|
{
|
2017-05-15 23:34:04 +02:00
|
|
|
hash_release(bgp->import_rt_hash, irt);
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&irt->vnis);
|
2017-05-15 23:34:04 +02:00
|
|
|
XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt);
|
2017-05-15 23:30:19 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 12:46:26 +02:00
|
|
|
static void hash_import_rt_free(struct irt_node *irt)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:27:51 +02:00
|
|
|
/*
|
2017-05-15 23:34:04 +02:00
|
|
|
* Function to lookup Import RT node - used to map a RT to set of
|
|
|
|
* VNIs importing routes with that RT.
|
|
|
|
*/
|
|
|
|
static struct irt_node *lookup_import_rt(struct bgp *bgp,
|
|
|
|
struct ecommunity_val *rt)
|
|
|
|
{
|
|
|
|
struct irt_node *irt;
|
|
|
|
struct irt_node tmp;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
2017-05-15 23:34:04 +02:00
|
|
|
memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE);
|
|
|
|
irt = hash_lookup(bgp->import_rt_hash, &tmp);
|
|
|
|
return irt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Is specified VNI present on the RT's list of "importing" VNIs?
|
|
|
|
*/
|
|
|
|
static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct bgpevpn *tmp_vpn;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(vnis, node, nnode, tmp_vpn)) {
|
|
|
|
if (tmp_vpn == vpn)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-09-23 02:19:09 +02:00
|
|
|
/* Flag if the route is injectable into EVPN.
|
|
|
|
* This would be following category:
|
|
|
|
* Non-imported route,
|
|
|
|
* Non-EVPN imported route,
|
|
|
|
*/
|
2024-01-24 06:52:34 +01:00
|
|
|
bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi)
|
2023-09-23 02:19:09 +02:00
|
|
|
{
|
|
|
|
struct bgp_path_info *parent_pi;
|
|
|
|
struct bgp_table *table;
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
|
|
|
|
if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra ||
|
|
|
|
!pi->extra->vrfleak || !pi->extra->vrfleak->parent)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent;
|
|
|
|
dest = parent_pi->net;
|
|
|
|
if (!dest)
|
|
|
|
return true;
|
|
|
|
table = bgp_dest_table(dest);
|
|
|
|
if (table &&
|
|
|
|
table->afi == AFI_L2VPN &&
|
|
|
|
table->safi == SAFI_EVPN)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-01-24 06:52:34 +01:00
|
|
|
/* Flag if the route is injectable into EVPN.
|
|
|
|
* This would be following category:
|
|
|
|
* Non-imported route,
|
|
|
|
* Non-EVPN imported route,
|
|
|
|
* Non Aggregate suppressed route.
|
|
|
|
*/
|
|
|
|
bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
|
|
|
|
{
|
|
|
|
/* do not import aggr suppressed routes */
|
|
|
|
if (bgp_path_suppressed(pi))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return is_route_injectable_into_evpn_non_supp(pi);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Compare Route Targets.
|
|
|
|
*/
|
2021-05-12 01:45:55 +02:00
|
|
|
int bgp_evpn_route_target_cmp(struct ecommunity *ecom1,
|
|
|
|
struct ecommunity *ecom2)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
if (ecom1 && !ecom2)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!ecom1 && ecom2)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!ecom1 && !ecom2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ecom1->str && !ecom2->str)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!ecom1->str && ecom2->str)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!ecom1->str && !ecom2->str)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return strcmp(ecom1->str, ecom2->str);
|
|
|
|
}
|
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
/*
|
|
|
|
* Compare L3 Route Targets.
|
|
|
|
*/
|
|
|
|
static int evpn_vrf_route_target_cmp(struct vrf_route_target *rt1,
|
|
|
|
struct vrf_route_target *rt2)
|
|
|
|
{
|
|
|
|
return bgp_evpn_route_target_cmp(rt1->ecom, rt2->ecom);
|
|
|
|
}
|
|
|
|
|
2021-05-12 01:45:55 +02:00
|
|
|
void bgp_evpn_xxport_delete_ecomm(void *val)
|
2018-05-18 00:54:25 +02:00
|
|
|
{
|
|
|
|
struct ecommunity *ecomm = val;
|
|
|
|
ecommunity_free(&ecomm);
|
|
|
|
}
|
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
/*
|
|
|
|
* Delete l3 Route Target.
|
|
|
|
*/
|
|
|
|
static void evpn_vrf_rt_del(void *val)
|
|
|
|
{
|
|
|
|
struct vrf_route_target *l3rt = val;
|
|
|
|
|
|
|
|
ecommunity_free(&l3rt->ecom);
|
|
|
|
|
|
|
|
XFREE(MTYPE_VRF_ROUTE_TARGET, l3rt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a new l3 Route Target.
|
|
|
|
*/
|
|
|
|
static struct vrf_route_target *evpn_vrf_rt_new(struct ecommunity *ecom)
|
|
|
|
{
|
|
|
|
struct vrf_route_target *l3rt;
|
|
|
|
|
|
|
|
l3rt = XCALLOC(MTYPE_VRF_ROUTE_TARGET, sizeof(struct vrf_route_target));
|
|
|
|
|
|
|
|
l3rt->ecom = ecom;
|
|
|
|
|
|
|
|
return l3rt;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Mask off global-admin field of specified extended community (RT),
|
|
|
|
* just retain the local-admin field.
|
|
|
|
*/
|
|
|
|
static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
|
2021-02-25 22:27:07 +01:00
|
|
|
const struct ecommunity_val *src)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t type;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
type = src->val[0];
|
|
|
|
dst->val[0] = 0;
|
|
|
|
if (type == ECOMMUNITY_ENCODE_AS) {
|
|
|
|
dst->val[2] = dst->val[3] = 0;
|
|
|
|
} else if (type == ECOMMUNITY_ENCODE_AS4
|
|
|
|
|| type == ECOMMUNITY_ENCODE_IP) {
|
|
|
|
dst->val[2] = dst->val[3] = 0;
|
|
|
|
dst->val[4] = dst->val[5] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-10 03:12:05 +02:00
|
|
|
/*
|
2021-02-25 22:27:07 +01:00
|
|
|
* Converts the RT to Ecommunity Value and adjusts masking based
|
|
|
|
* on flags set for RT.
|
2017-10-10 03:12:05 +02:00
|
|
|
*/
|
2021-02-25 22:27:07 +01:00
|
|
|
static void vrf_rt2ecom_val(struct ecommunity_val *to_eval,
|
|
|
|
const struct vrf_route_target *l3rt, int iter)
|
2017-10-10 03:12:05 +02:00
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
const struct ecommunity_val *eval;
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
eval = (const struct ecommunity_val *)(l3rt->ecom->val +
|
|
|
|
(iter * ECOMMUNITY_SIZE));
|
|
|
|
/* If using "automatic" or "wildcard *" RT,
|
2017-10-10 03:12:05 +02:00
|
|
|
* we only care about the local-admin sub-field.
|
|
|
|
* This is to facilitate using L3VNI(VRF-VNI)
|
2021-02-25 22:27:07 +01:00
|
|
|
* as the RT for EBGP peering too and simplify
|
|
|
|
* configurations by allowing any ASN via '*'.
|
2017-10-10 03:12:05 +02:00
|
|
|
*/
|
2021-02-25 22:27:07 +01:00
|
|
|
memcpy(to_eval, eval, ECOMMUNITY_SIZE);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO) ||
|
|
|
|
CHECK_FLAG(l3rt->flags, BGP_VRF_RT_WILD))
|
|
|
|
mask_ecom_global_admin(to_eval, eval);
|
|
|
|
}
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
/*
|
|
|
|
* Map one RT to specified VRF.
|
|
|
|
* bgp_vrf = BGP vrf instance
|
|
|
|
*/
|
|
|
|
static void map_vrf_to_rt(struct bgp *bgp_vrf, struct vrf_route_target *l3rt)
|
|
|
|
{
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < l3rt->ecom->size; i++) {
|
|
|
|
struct vrf_irt_node *irt = NULL;
|
|
|
|
struct ecommunity_val eval_tmp;
|
|
|
|
|
|
|
|
/* Adjust masking for value */
|
|
|
|
vrf_rt2ecom_val(&eval_tmp, l3rt, i);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
irt = lookup_vrf_import_rt(&eval_tmp);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
if (irt && is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
|
|
|
|
return; /* Already mapped. */
|
|
|
|
|
|
|
|
if (!irt)
|
|
|
|
irt = vrf_import_rt_new(&eval_tmp);
|
|
|
|
|
|
|
|
/* Add VRF to the list for this RT. */
|
|
|
|
listnode_add(irt->vrfs, bgp_vrf);
|
|
|
|
}
|
2017-10-10 03:12:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unmap specified VRF from specified RT. If there are no other
|
|
|
|
* VRFs for this RT, then the RT hash is deleted.
|
|
|
|
* bgp_vrf: BGP VRF specific instance
|
|
|
|
*/
|
2021-02-25 22:27:07 +01:00
|
|
|
static void unmap_vrf_from_rt(struct bgp *bgp_vrf,
|
|
|
|
struct vrf_route_target *l3rt)
|
2017-10-10 03:12:05 +02:00
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < l3rt->ecom->size; i++) {
|
|
|
|
struct vrf_irt_node *irt;
|
|
|
|
struct ecommunity_val eval_tmp;
|
|
|
|
|
|
|
|
/* Adjust masking for value */
|
|
|
|
vrf_rt2ecom_val(&eval_tmp, l3rt, i);
|
|
|
|
|
|
|
|
irt = lookup_vrf_import_rt(&eval_tmp);
|
|
|
|
|
|
|
|
if (!irt)
|
|
|
|
return; /* Not mapped */
|
|
|
|
|
|
|
|
/* Delete VRF from list for this RT. */
|
|
|
|
listnode_delete(irt->vrfs, bgp_vrf);
|
|
|
|
|
|
|
|
if (!listnode_head(irt->vrfs))
|
|
|
|
vrf_import_rt_free(irt);
|
2017-10-10 03:12:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Map one RT to specified VNI.
|
2017-05-15 23:27:51 +02:00
|
|
|
*/
|
2017-05-15 23:34:04 +02:00
|
|
|
static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct ecommunity_val *eval)
|
|
|
|
{
|
|
|
|
struct irt_node *irt;
|
|
|
|
struct ecommunity_val eval_tmp;
|
|
|
|
|
|
|
|
/* If using "automatic" RT, we only care about the local-admin
|
|
|
|
* sub-field.
|
|
|
|
* This is to facilitate using VNI as the RT for EBGP peering too.
|
|
|
|
*/
|
|
|
|
memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
|
|
|
|
if (!is_import_rt_configured(vpn))
|
|
|
|
mask_ecom_global_admin(&eval_tmp, eval);
|
|
|
|
|
|
|
|
irt = lookup_import_rt(bgp, &eval_tmp);
|
2018-05-22 16:50:53 +02:00
|
|
|
if (irt)
|
2017-05-15 23:34:04 +02:00
|
|
|
if (is_vni_present_in_irt_vnis(irt->vnis, vpn))
|
|
|
|
/* Already mapped. */
|
|
|
|
return;
|
|
|
|
|
2022-05-06 11:52:12 +02:00
|
|
|
if (!irt)
|
2017-05-15 23:34:04 +02:00
|
|
|
irt = import_rt_new(bgp, &eval_tmp);
|
|
|
|
|
|
|
|
/* Add VNI to the hash list for this RT. */
|
|
|
|
listnode_add(irt->vnis, vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unmap specified VNI from specified RT. If there are no other
|
|
|
|
* VNIs for this RT, then the RT hash is deleted.
|
|
|
|
*/
|
|
|
|
static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct irt_node *irt)
|
2017-05-15 23:27:51 +02:00
|
|
|
{
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Delete VNI from hash list for this RT. */
|
|
|
|
listnode_delete(irt->vnis, vpn);
|
|
|
|
if (!listnode_head(irt->vnis)) {
|
|
|
|
import_rt_free(bgp, irt);
|
|
|
|
}
|
2017-05-15 23:27:51 +02:00
|
|
|
}
|
|
|
|
|
2019-08-09 03:58:03 +02:00
|
|
|
static void bgp_evpn_get_rmac_nexthop(struct bgpevpn *vpn,
|
2020-03-22 19:50:46 +01:00
|
|
|
const struct prefix_evpn *p,
|
2019-08-09 03:58:03 +02:00
|
|
|
struct attr *attr, uint8_t flags)
|
|
|
|
{
|
|
|
|
struct bgp *bgp_vrf = vpn->bgp_vrf;
|
|
|
|
|
|
|
|
memset(&attr->rmac, 0, sizeof(struct ethaddr));
|
|
|
|
if (!bgp_vrf)
|
|
|
|
return;
|
|
|
|
|
2019-10-24 23:32:49 +02:00
|
|
|
if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Copy sys (pip) RMAC and PIP IP as nexthop
|
|
|
|
* in case of route is self MAC-IP,
|
|
|
|
* advertise-pip and advertise-svi-ip features
|
|
|
|
* are enabled.
|
|
|
|
* Otherwise, for all host MAC-IP route's
|
2019-10-26 00:27:47 +02:00
|
|
|
* copy anycast RMAC.
|
2019-10-24 23:32:49 +02:00
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(flags, BGP_EVPN_MACIP_TYPE_SVI_IP)
|
|
|
|
&& bgp_vrf->evpn_info->advertise_pip &&
|
|
|
|
bgp_vrf->evpn_info->is_anycast_mac) {
|
|
|
|
/* copy sys rmac */
|
|
|
|
memcpy(&attr->rmac, &bgp_vrf->evpn_info->pip_rmac,
|
|
|
|
ETH_ALEN);
|
|
|
|
attr->nexthop = bgp_vrf->evpn_info->pip_ip;
|
|
|
|
attr->mp_nexthop_global_in =
|
|
|
|
bgp_vrf->evpn_info->pip_ip;
|
|
|
|
} else
|
|
|
|
memcpy(&attr->rmac, &bgp_vrf->rmac, ETH_ALEN);
|
2019-08-09 03:58:03 +02:00
|
|
|
}
|
2019-10-24 23:32:49 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Create RT extended community automatically from passed information:
|
|
|
|
* of the form AS:VNI.
|
|
|
|
* NOTE: We use only the lower 16 bits of the AS. This is sufficient as
|
|
|
|
* the need is to get a RT value that will be unique across different
|
|
|
|
* VNIs but the same across routers (in the same AS) for a particular
|
|
|
|
* VNI.
|
|
|
|
*/
|
2021-02-25 22:27:07 +01:00
|
|
|
static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl,
|
|
|
|
bool is_l3)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct ecommunity_val eval;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct ecommunity *ecomadd;
|
2021-02-25 22:27:07 +01:00
|
|
|
struct ecommunity *ecom;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct vrf_route_target *l3rt;
|
|
|
|
struct vrf_route_target *newrt;
|
2019-08-10 01:12:55 +02:00
|
|
|
bool ecom_found = false;
|
|
|
|
struct listnode *node;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2017-04-12 11:24:07 +02:00
|
|
|
if (bgp->advertise_autort_rfc8365)
|
|
|
|
vni |= EVPN_AUTORT_VXLAN;
|
2023-04-10 21:40:30 +02:00
|
|
|
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
ecomadd = ecommunity_new();
|
2020-03-24 21:50:20 +01:00
|
|
|
ecommunity_add_val(ecomadd, &eval, false, false);
|
2019-08-10 01:12:55 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
if (is_l3) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(rtl, node, l3rt))
|
|
|
|
if (ecommunity_cmp(ecomadd, l3rt->ecom)) {
|
|
|
|
ecom_found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom))
|
|
|
|
if (ecommunity_cmp(ecomadd, ecom)) {
|
|
|
|
ecom_found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-08-10 01:12:55 +02:00
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
if (!ecom_found) {
|
2021-02-25 22:27:07 +01:00
|
|
|
if (is_l3) {
|
|
|
|
newrt = evpn_vrf_rt_new(ecomadd);
|
|
|
|
/* Label it as autoderived */
|
|
|
|
SET_FLAG(newrt->flags, BGP_VRF_RT_AUTO);
|
|
|
|
listnode_add_sort(rtl, newrt);
|
|
|
|
} else
|
|
|
|
listnode_add_sort(rtl, ecomadd);
|
2021-02-17 22:11:49 +01:00
|
|
|
} else
|
2020-05-15 00:33:10 +02:00
|
|
|
ecommunity_free(&ecomadd);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-05-15 23:27:51 +02:00
|
|
|
|
|
|
|
/*
|
2017-05-15 23:34:04 +02:00
|
|
|
* Derive RD and RT for a VNI automatically. Invoked at the time of
|
|
|
|
* creation of a VNI.
|
|
|
|
*/
|
|
|
|
static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
bgp_evpn_derive_auto_rd(bgp, vpn);
|
|
|
|
bgp_evpn_derive_auto_rt_import(bgp, vpn);
|
|
|
|
bgp_evpn_derive_auto_rt_export(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/*
|
|
|
|
* Convert nexthop (remote VTEP IP) into an IPv6 address.
|
|
|
|
*/
|
|
|
|
static void evpn_convert_nexthop_to_ipv6(struct attr *attr)
|
|
|
|
{
|
|
|
|
if (BGP_ATTR_NEXTHOP_AFI_IP6(attr))
|
|
|
|
return;
|
|
|
|
ipv4_to_ipv4_mapped_ipv6(&attr->mp_nexthop_global, attr->nexthop);
|
|
|
|
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
|
|
|
|
}
|
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
/*
|
|
|
|
* Wrapper for node get in global table.
|
|
|
|
*/
|
|
|
|
struct bgp_dest *bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi,
|
2020-10-14 17:19:45 +02:00
|
|
|
safi_t safi,
|
|
|
|
const struct prefix_evpn *evp,
|
2021-07-23 19:35:14 +02:00
|
|
|
struct prefix_rd *prd,
|
|
|
|
const struct bgp_path_info *local_pi)
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
{
|
|
|
|
struct prefix_evpn global_p;
|
|
|
|
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
|
|
|
|
/* prefix in the global table doesn't include the VTEP-IP so
|
|
|
|
* we need to create a different copy of the prefix
|
|
|
|
*/
|
|
|
|
evpn_type1_prefix_global_copy(&global_p, evp);
|
|
|
|
evp = &global_p;
|
2021-07-23 19:35:14 +02:00
|
|
|
} else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
|
|
|
|
local_pi) {
|
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* prefix in the global table needs MAC/IP, ensure they are
|
|
|
|
* present, using one's from local table's path_info.
|
2021-07-23 19:35:14 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_none(evp)) {
|
|
|
|
/* VNI MAC -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
|
|
|
&global_p, evp, NULL /* mac */,
|
|
|
|
evpn_type2_path_info_get_ip(local_pi));
|
|
|
|
} else {
|
|
|
|
/* VNI IP -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
|
|
|
&global_p, evp,
|
|
|
|
evpn_type2_path_info_get_mac(local_pi),
|
|
|
|
NULL /* ip */);
|
|
|
|
}
|
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
evp = &global_p;
|
|
|
|
}
|
|
|
|
return bgp_afi_node_get(table, afi, safi, (struct prefix *)evp, prd);
|
|
|
|
}
|
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
/*
|
|
|
|
* Wrapper for node lookup in global table.
|
|
|
|
*/
|
2023-03-14 11:05:58 +01:00
|
|
|
struct bgp_dest *bgp_evpn_global_node_lookup(
|
|
|
|
struct bgp_table *table, safi_t safi, const struct prefix_evpn *evp,
|
|
|
|
struct prefix_rd *prd, const struct bgp_path_info *local_pi)
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
{
|
|
|
|
struct prefix_evpn global_p;
|
|
|
|
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
|
|
|
|
/* prefix in the global table doesn't include the VTEP-IP so
|
|
|
|
* we need to create a different copy of the prefix
|
|
|
|
*/
|
|
|
|
evpn_type1_prefix_global_copy(&global_p, evp);
|
|
|
|
evp = &global_p;
|
2021-07-23 19:35:14 +02:00
|
|
|
} else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
|
|
|
|
local_pi) {
|
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* prefix in the global table needs MAC/IP, ensure they are
|
|
|
|
* present, using one's from local table's path_info.
|
2021-07-23 19:35:14 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_none(evp)) {
|
|
|
|
/* VNI MAC -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
|
|
|
&global_p, evp, NULL /* mac */,
|
|
|
|
evpn_type2_path_info_get_ip(local_pi));
|
|
|
|
} else {
|
|
|
|
/* VNI IP -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
|
|
|
&global_p, evp,
|
|
|
|
evpn_type2_path_info_get_mac(local_pi),
|
|
|
|
NULL /* ip */);
|
|
|
|
}
|
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
evp = &global_p;
|
|
|
|
}
|
2023-03-14 11:01:56 +01:00
|
|
|
return bgp_safi_node_lookup(table, safi, (struct prefix *)evp, prd);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
}
|
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* Wrapper for node get in VNI IP table.
|
2021-07-23 19:35:14 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
struct bgp_dest *bgp_evpn_vni_ip_node_get(struct bgp_table *const table,
|
|
|
|
const struct prefix_evpn *evp,
|
|
|
|
const struct bgp_path_info *parent_pi)
|
2021-07-23 19:35:14 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn vni_p;
|
|
|
|
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) {
|
|
|
|
/* prefix in the global table doesn't include the VTEP-IP so
|
|
|
|
* we need to create a different copy for the VNI
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
evpn_type1_prefix_vni_ip_copy(&vni_p, evp,
|
|
|
|
parent_pi->attr->nexthop);
|
2021-07-23 19:35:14 +02:00
|
|
|
evp = &vni_p;
|
2021-10-26 23:55:54 +02:00
|
|
|
} else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
/* Only MAC-IP should go into this table, not mac-only */
|
|
|
|
assert(is_evpn_prefix_ipaddr_none(evp) == false);
|
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* prefix in the vni IP table doesn't include MAC so
|
2021-07-23 19:35:14 +02:00
|
|
|
* we need to create a different copy of the prefix.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
evpn_type2_prefix_vni_ip_copy(&vni_p, evp);
|
2021-07-23 19:35:14 +02:00
|
|
|
evp = &vni_p;
|
|
|
|
}
|
|
|
|
return bgp_node_get(table, (struct prefix *)evp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* Wrapper for node lookup in VNI IP table.
|
2021-07-23 19:35:14 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
struct bgp_dest *
|
|
|
|
bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table,
|
|
|
|
const struct prefix_evpn *evp,
|
|
|
|
const struct bgp_path_info *parent_pi)
|
2021-07-23 19:35:14 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn vni_p;
|
|
|
|
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) {
|
|
|
|
/* prefix in the global table doesn't include the VTEP-IP so
|
|
|
|
* we need to create a different copy for the VNI
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
evpn_type1_prefix_vni_ip_copy(&vni_p, evp,
|
|
|
|
parent_pi->attr->nexthop);
|
2021-07-23 19:35:14 +02:00
|
|
|
evp = &vni_p;
|
2021-10-26 23:55:54 +02:00
|
|
|
} else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
/* Only MAC-IP should go into this table, not mac-only */
|
|
|
|
assert(is_evpn_prefix_ipaddr_none(evp) == false);
|
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* prefix in the vni IP table doesn't include MAC so
|
2021-07-23 19:35:14 +02:00
|
|
|
* we need to create a different copy of the prefix.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
evpn_type2_prefix_vni_ip_copy(&vni_p, evp);
|
2021-07-23 19:35:14 +02:00
|
|
|
evp = &vni_p;
|
|
|
|
}
|
|
|
|
return bgp_node_lookup(table, (struct prefix *)evp);
|
|
|
|
}
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/*
|
|
|
|
* Wrapper for node get in VNI MAC table.
|
|
|
|
*/
|
|
|
|
struct bgp_dest *
|
|
|
|
bgp_evpn_vni_mac_node_get(struct bgp_table *const table,
|
|
|
|
const struct prefix_evpn *evp,
|
|
|
|
const struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
struct prefix_evpn vni_p;
|
|
|
|
|
|
|
|
/* Only type-2 should ever go into this table */
|
|
|
|
assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prefix in the vni MAC table doesn't include IP so
|
|
|
|
* we need to create a different copy of the prefix.
|
|
|
|
*/
|
|
|
|
evpn_type2_prefix_vni_mac_copy(&vni_p, evp);
|
|
|
|
evp = &vni_p;
|
|
|
|
return bgp_node_get(table, (struct prefix *)evp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wrapper for node lookup in VNI MAC table.
|
|
|
|
*/
|
|
|
|
struct bgp_dest *
|
|
|
|
bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table,
|
|
|
|
const struct prefix_evpn *evp,
|
|
|
|
const struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
struct prefix_evpn vni_p;
|
|
|
|
|
|
|
|
/* Only type-2 should ever go into this table */
|
|
|
|
assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prefix in the vni MAC table doesn't include IP so
|
|
|
|
* we need to create a different copy of the prefix.
|
|
|
|
*/
|
|
|
|
evpn_type2_prefix_vni_mac_copy(&vni_p, evp);
|
|
|
|
evp = &vni_p;
|
|
|
|
return bgp_node_lookup(table, (struct prefix *)evp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wrapper for node get in both VNI tables.
|
|
|
|
*/
|
|
|
|
struct bgp_dest *bgp_evpn_vni_node_get(struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
const struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
|
|
|
|
(is_evpn_prefix_ipaddr_none(p) == true))
|
|
|
|
return bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi);
|
|
|
|
|
|
|
|
return bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wrapper for node lookup in both VNI tables.
|
|
|
|
*/
|
|
|
|
struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
const struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
|
|
|
|
(is_evpn_prefix_ipaddr_none(p) == true))
|
|
|
|
return bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p,
|
|
|
|
parent_pi);
|
|
|
|
|
|
|
|
return bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Add (update) or delete MACIP from zebra.
|
2017-05-15 23:27:51 +02:00
|
|
|
*/
|
2024-02-15 20:23:51 +01:00
|
|
|
static enum zclient_send_status bgp_zebra_send_remote_macip(
|
|
|
|
struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
|
|
|
|
const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add,
|
|
|
|
uint8_t flags, uint32_t seq, esi_t *esi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
2020-09-23 21:31:52 +02:00
|
|
|
uint16_t ipa_len;
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
static struct in_addr zero_remote_vtep_ip;
|
2021-08-17 20:27:35 +02:00
|
|
|
bool esi_valid;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Check socket. */
|
2024-02-15 20:23:51 +01:00
|
|
|
if (!zclient || zclient->sock < 0) {
|
|
|
|
if (BGP_DEBUG(zebra, ZEBRA))
|
|
|
|
zlog_debug("%s: No zclient or zclient->sock exists",
|
|
|
|
__func__);
|
|
|
|
return ZCLIENT_SEND_SUCCESS;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Don't try to register if Zebra doesn't know of this instance. */
|
2018-10-05 15:43:28 +02:00
|
|
|
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
|
|
|
|
if (BGP_DEBUG(zebra, ZEBRA))
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: No zebra instance to talk to, not installing remote macip",
|
|
|
|
__func__);
|
2024-02-15 20:23:51 +01:00
|
|
|
return ZCLIENT_SEND_SUCCESS;
|
2018-10-05 15:43:28 +02:00
|
|
|
}
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
|
|
|
|
if (!esi)
|
|
|
|
esi = zero_esi;
|
2017-05-15 23:34:04 +02:00
|
|
|
s = zclient->obuf;
|
|
|
|
stream_reset(s);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-21 21:55:29 +02:00
|
|
|
zclient_create_header(
|
|
|
|
s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL,
|
|
|
|
bgp->vrf_id);
|
2022-09-07 18:31:42 +02:00
|
|
|
stream_putl(s, vpn ? vpn->vni : 0);
|
2021-07-23 19:35:14 +02:00
|
|
|
|
|
|
|
if (mac) /* Mac Addr */
|
|
|
|
stream_put(s, &mac->octet, ETH_ALEN);
|
|
|
|
else
|
|
|
|
stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN);
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* IP address length and IP address, if any. */
|
2018-04-14 00:37:30 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_none(p))
|
2020-09-23 21:31:52 +02:00
|
|
|
stream_putw(s, 0);
|
2017-05-15 23:34:04 +02:00
|
|
|
else {
|
2018-04-14 00:37:30 +02:00
|
|
|
ipa_len = is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BYTELEN
|
2017-05-15 23:34:04 +02:00
|
|
|
: IPV6_MAX_BYTELEN;
|
2020-09-23 21:31:52 +02:00
|
|
|
stream_putw(s, ipa_len);
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_put(s, &p->prefix.macip_addr.ip.ip.addr, ipa_len);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2020-03-28 18:12:04 +01:00
|
|
|
/* If the ESI is valid that becomes the nexthop; tape out the
|
|
|
|
* VTEP-IP for that case
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
*/
|
2021-08-17 20:27:35 +02:00
|
|
|
if (bgp_evpn_is_esi_valid(esi)) {
|
|
|
|
esi_valid = true;
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
stream_put_in_addr(s, &zero_remote_vtep_ip);
|
2021-08-17 20:27:35 +02:00
|
|
|
} else {
|
|
|
|
esi_valid = false;
|
2020-03-28 18:12:04 +01:00
|
|
|
stream_put_in_addr(s, &remote_vtep_ip);
|
2021-08-17 20:27:35 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-13 12:19:52 +01:00
|
|
|
/* TX flags - MAC sticky status and/or gateway mac */
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Also TX the sequence number of the best route. */
|
|
|
|
if (add) {
|
2017-11-13 12:19:52 +01:00
|
|
|
stream_putc(s, flags);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
stream_putl(s, seq);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
stream_put(s, esi, sizeof(esi_t));
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-17 20:27:35 +02:00
|
|
|
if (bgp_debug_zebra(NULL)) {
|
|
|
|
char esi_buf[ESI_STR_LEN];
|
|
|
|
|
|
|
|
if (esi_valid)
|
|
|
|
esi_to_str(esi, esi_buf, sizeof(esi_buf));
|
|
|
|
else
|
|
|
|
snprintf(esi_buf, sizeof(esi_buf), "-");
|
2017-11-13 12:19:52 +01:00
|
|
|
zlog_debug(
|
2021-08-17 20:27:35 +02:00
|
|
|
"Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s",
|
2022-09-07 18:31:42 +02:00
|
|
|
add ? "ADD" : "DEL", (vpn ? vpn->vni : 0),
|
2021-10-26 23:55:54 +02:00
|
|
|
(mac ? mac : &p->prefix.macip_addr.mac),
|
|
|
|
&p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip,
|
|
|
|
esi_buf);
|
2021-08-17 20:27:35 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd: initial batch of evpn lttng tracepoints
Low overhead bgp-evpn TPs have been added which push data out in a binary
format -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@switch:~# lttng list --userspace |grep "frr_bgp:evpn"
frr_bgp:evpn_mh_nh_rmac_zsend (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint)
frr_bgp:evpn_mh_nh_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mh_nhg_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mh_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_bum_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mac_ip_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
root@switch:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
In addition to the tracepoints a babeltrace python plugin for pretty
printing (binary data is converted into grepable strings). Sample usage -
frr_babeltrace.py trace_path
Sample tracepoint output -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1. frr_bgp: evpn_mac_ip_zsend
frr_bgp:evpn_mac_ip_zsend {'action': 'add', 'vni': 1007, 'mac': '00:02:00:00:00:04', 'ip': 'fe80::202:ff:fe00:4', 'vtep': '27.0.0.15', 'esi': '03:44:38:39:ff:ff:01:00:00:02'}
2. frr_bgp: evpn_mh_vtep_zsend
frr_bgp:evpn_mh_vtep_zsend {'action': 'add', 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vtep': '27.0.0.16'}
3. frr_bgp: evpn_mh_nhg_zsend
frr_bgp:evpn_mh_nhg_zsend {'action': 'add', 'type': 'v4', 'nhg': 74999998, 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vrf': 85}
4. frr_bgp: evpn_mh_nh_zsend
frr_bgp:evpn_mh_nh_zsend {'nhg': 74999998, 'vtep': '27.0.0.16', 'svi': 93}
5. frr_bgp: evpn_mh_nh_rmac_zsend
frr_bgp:evpn_mh_nh_rmac_zsend {'action': 'add', 'vrf': 85, 'nh': '::ffff:1b00:12', 'rmac': '00:02:00:00:00:50'}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
2021-09-28 20:18:43 +02:00
|
|
|
frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip,
|
|
|
|
esi);
|
|
|
|
|
2024-02-15 20:23:51 +01:00
|
|
|
return zclient_send_message(zclient);
|
2016-09-05 11:07:25 +02:00
|
|
|
}
|
2016-09-05 14:19:40 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Add (update) or delete remote VTEP from zebra.
|
|
|
|
*/
|
2024-02-15 20:23:51 +01:00
|
|
|
static enum zclient_send_status
|
|
|
|
bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p, int flood_control,
|
|
|
|
int add)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
|
|
|
|
/* Check socket. */
|
2024-02-15 20:23:51 +01:00
|
|
|
if (!zclient || zclient->sock < 0) {
|
|
|
|
if (BGP_DEBUG(zebra, ZEBRA))
|
|
|
|
zlog_debug("%s: No zclient or zclient->sock exists",
|
|
|
|
__func__);
|
|
|
|
return ZCLIENT_SEND_SUCCESS;
|
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Don't try to register if Zebra doesn't know of this instance. */
|
2018-10-05 15:43:28 +02:00
|
|
|
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
|
|
|
|
if (BGP_DEBUG(zebra, ZEBRA))
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: No zebra instance to talk to, not installing remote vtep",
|
|
|
|
__func__);
|
2024-02-15 20:23:51 +01:00
|
|
|
return ZCLIENT_SEND_SUCCESS;
|
2018-10-05 15:43:28 +02:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
s = zclient->obuf;
|
|
|
|
stream_reset(s);
|
|
|
|
|
2017-06-21 21:55:29 +02:00
|
|
|
zclient_create_header(
|
|
|
|
s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL,
|
|
|
|
bgp->vrf_id);
|
2022-09-07 18:31:42 +02:00
|
|
|
stream_putl(s, vpn ? vpn->vni : 0);
|
2018-04-14 00:37:30 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_v4(p))
|
|
|
|
stream_put_in_addr(s, &p->prefix.imet_addr.ip.ipaddr_v4);
|
|
|
|
else if (is_evpn_prefix_ipaddr_v6(p)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_VTEP_INVALID,
|
2017-05-15 23:34:04 +02:00
|
|
|
"Bad remote IP when trying to %s remote VTEP for VNI %u",
|
2022-09-07 18:31:42 +02:00
|
|
|
add ? "ADD" : "DEL", (vpn ? vpn->vni : 0));
|
2024-02-15 20:23:51 +01:00
|
|
|
return ZCLIENT_SEND_FAILURE;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2019-03-19 19:29:04 +01:00
|
|
|
stream_putl(s, flood_control);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (bgp_debug_zebra(NULL))
|
2020-10-15 21:33:09 +02:00
|
|
|
zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %pI4",
|
2022-09-07 18:31:42 +02:00
|
|
|
add ? "ADD" : "DEL", (vpn ? vpn->vni : 0),
|
2020-10-15 21:33:09 +02:00
|
|
|
&p->prefix.imet_addr.ip.ipaddr_v4);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
bgpd: initial batch of evpn lttng tracepoints
Low overhead bgp-evpn TPs have been added which push data out in a binary
format -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@switch:~# lttng list --userspace |grep "frr_bgp:evpn"
frr_bgp:evpn_mh_nh_rmac_zsend (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint)
frr_bgp:evpn_mh_nh_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mh_nhg_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mh_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_bum_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
frr_bgp:evpn_mac_ip_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint)
root@switch:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
In addition to the tracepoints a babeltrace python plugin for pretty
printing (binary data is converted into grepable strings). Sample usage -
frr_babeltrace.py trace_path
Sample tracepoint output -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1. frr_bgp: evpn_mac_ip_zsend
frr_bgp:evpn_mac_ip_zsend {'action': 'add', 'vni': 1007, 'mac': '00:02:00:00:00:04', 'ip': 'fe80::202:ff:fe00:4', 'vtep': '27.0.0.15', 'esi': '03:44:38:39:ff:ff:01:00:00:02'}
2. frr_bgp: evpn_mh_vtep_zsend
frr_bgp:evpn_mh_vtep_zsend {'action': 'add', 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vtep': '27.0.0.16'}
3. frr_bgp: evpn_mh_nhg_zsend
frr_bgp:evpn_mh_nhg_zsend {'action': 'add', 'type': 'v4', 'nhg': 74999998, 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vrf': 85}
4. frr_bgp: evpn_mh_nh_zsend
frr_bgp:evpn_mh_nh_zsend {'nhg': 74999998, 'vtep': '27.0.0.16', 'svi': 93}
5. frr_bgp: evpn_mh_nh_rmac_zsend
frr_bgp:evpn_mh_nh_rmac_zsend {'action': 'add', 'vrf': 85, 'nh': '::ffff:1b00:12', 'rmac': '00:02:00:00:00:50'}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
2021-09-28 20:18:43 +02:00
|
|
|
frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p);
|
|
|
|
|
2024-02-15 20:23:51 +01:00
|
|
|
return zclient_send_message(zclient);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
/*
|
|
|
|
* Build extended communities for EVPN prefix route.
|
|
|
|
*/
|
|
|
|
static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
|
|
|
|
struct attr *attr)
|
|
|
|
{
|
|
|
|
struct ecommunity ecom_encap;
|
|
|
|
struct ecommunity_val eval;
|
|
|
|
struct ecommunity_val eval_rmac;
|
|
|
|
bgp_encap_types tnl_type;
|
|
|
|
struct listnode *node, *nnode;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct vrf_route_target *l3rt;
|
2020-03-24 22:58:42 +01:00
|
|
|
struct ecommunity *old_ecom;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct ecommunity *ecom;
|
2017-10-27 23:15:45 +02:00
|
|
|
struct list *vrf_export_rtl = NULL;
|
|
|
|
|
|
|
|
/* Encap */
|
|
|
|
tnl_type = BGP_ENCAP_TYPE_VXLAN;
|
|
|
|
memset(&ecom_encap, 0, sizeof(ecom_encap));
|
|
|
|
encode_encap_extcomm(tnl_type, &eval);
|
|
|
|
ecom_encap.size = 1;
|
2019-10-22 09:21:28 +02:00
|
|
|
ecom_encap.unit_size = ECOMMUNITY_SIZE;
|
2018-03-27 21:13:34 +02:00
|
|
|
ecom_encap.val = (uint8_t *)eval.val;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* Add Encap */
|
2022-02-04 14:56:20 +01:00
|
|
|
if (bgp_attr_get_ecommunity(attr)) {
|
|
|
|
old_ecom = bgp_attr_get_ecommunity(attr);
|
2020-03-24 22:58:42 +01:00
|
|
|
ecom = ecommunity_merge(ecommunity_dup(old_ecom), &ecom_encap);
|
|
|
|
if (!old_ecom->refcnt)
|
|
|
|
ecommunity_free(&old_ecom);
|
|
|
|
} else
|
|
|
|
ecom = ecommunity_dup(&ecom_encap);
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(attr, ecom);
|
2020-12-10 22:59:56 +01:00
|
|
|
attr->encap_tunneltype = tnl_type;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* Add the export RTs for L3VNI/VRF */
|
|
|
|
vrf_export_rtl = bgp_vrf->vrf_export_rtl;
|
2021-02-17 22:11:49 +01:00
|
|
|
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, l3rt))
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(
|
2021-02-17 22:11:49 +01:00
|
|
|
attr, ecommunity_merge(bgp_attr_get_ecommunity(attr),
|
|
|
|
l3rt->ecom));
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* add the router mac extended community */
|
|
|
|
if (!is_zero_mac(&attr->rmac)) {
|
|
|
|
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
|
2022-02-04 14:56:20 +01:00
|
|
|
ecommunity_add_val(bgp_attr_get_ecommunity(attr), &eval_rmac,
|
|
|
|
true, true);
|
2017-10-27 23:15:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
2018-02-28 03:07:23 +01:00
|
|
|
* Build extended communities for EVPN route.
|
|
|
|
* This function is applicable for type-2 and type-3 routes. The layer-2 RT
|
|
|
|
* and ENCAP extended communities are applicable for all routes.
|
|
|
|
* The default gateway extended community and MAC mobility (sticky) extended
|
|
|
|
* community are added as needed based on passed settings - only for type-2
|
|
|
|
* routes. Likewise, the layer-3 RT and Router MAC extended communities are
|
|
|
|
* added, if present, based on passed settings - only for non-link-local
|
|
|
|
* type-2 routes.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2017-11-10 23:29:39 +01:00
|
|
|
static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
2023-05-08 04:51:28 +02:00
|
|
|
int add_l3_ecomm,
|
|
|
|
struct ecommunity *macvrf_soo)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct ecommunity ecom_encap;
|
2017-05-15 23:42:57 +02:00
|
|
|
struct ecommunity ecom_sticky;
|
2017-11-13 12:19:52 +01:00
|
|
|
struct ecommunity ecom_default_gw;
|
2018-07-07 06:46:46 +02:00
|
|
|
struct ecommunity ecom_na;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity_val eval;
|
2017-05-15 23:42:57 +02:00
|
|
|
struct ecommunity_val eval_sticky;
|
2017-11-13 12:19:52 +01:00
|
|
|
struct ecommunity_val eval_default_gw;
|
2017-10-09 13:55:57 +02:00
|
|
|
struct ecommunity_val eval_rmac;
|
2018-07-07 06:46:46 +02:00
|
|
|
struct ecommunity_val eval_na;
|
2020-03-28 18:12:04 +01:00
|
|
|
bool proxy;
|
2018-07-07 06:46:46 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
bgp_encap_types tnl_type;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct ecommunity *ecom;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct vrf_route_target *l3rt;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t seqnum;
|
2017-10-09 10:36:32 +02:00
|
|
|
struct list *vrf_export_rtl = NULL;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Encap */
|
|
|
|
tnl_type = BGP_ENCAP_TYPE_VXLAN;
|
|
|
|
memset(&ecom_encap, 0, sizeof(ecom_encap));
|
|
|
|
encode_encap_extcomm(tnl_type, &eval);
|
|
|
|
ecom_encap.size = 1;
|
2019-10-22 09:21:28 +02:00
|
|
|
ecom_encap.unit_size = ECOMMUNITY_SIZE;
|
2018-03-27 21:13:34 +02:00
|
|
|
ecom_encap.val = (uint8_t *)eval.val;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Add Encap */
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap));
|
2020-12-10 22:59:56 +01:00
|
|
|
attr->encap_tunneltype = tnl_type;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2017-10-09 10:36:32 +02:00
|
|
|
/* Add the export RTs for L2VNI */
|
2017-05-15 23:34:04 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr,
|
|
|
|
ecommunity_merge(bgp_attr_get_ecommunity(attr), ecom));
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* Add the export RTs for L3VNI if told to - caller determines
|
|
|
|
* when this should be done.
|
2017-12-27 20:47:10 +01:00
|
|
|
*/
|
2018-02-28 03:07:23 +01:00
|
|
|
if (add_l3_ecomm) {
|
2017-11-10 23:29:39 +01:00
|
|
|
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
|
|
|
|
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
|
|
|
|
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
|
2021-02-17 22:11:49 +01:00
|
|
|
l3rt))
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr,
|
|
|
|
ecommunity_merge(
|
|
|
|
bgp_attr_get_ecommunity(attr),
|
2021-02-17 22:11:49 +01:00
|
|
|
l3rt->ecom));
|
2017-11-10 23:29:39 +01:00
|
|
|
}
|
2017-10-09 11:06:34 +02:00
|
|
|
}
|
2017-10-09 10:36:32 +02:00
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* Add MAC mobility (sticky) if needed. */
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) {
|
2017-05-15 23:42:57 +02:00
|
|
|
seqnum = 0;
|
|
|
|
encode_mac_mobility_extcomm(1, seqnum, &eval_sticky);
|
|
|
|
ecom_sticky.size = 1;
|
2019-10-22 09:21:28 +02:00
|
|
|
ecom_sticky.unit_size = ECOMMUNITY_SIZE;
|
2018-03-27 21:13:34 +02:00
|
|
|
ecom_sticky.val = (uint8_t *)eval_sticky.val;
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr, ecommunity_merge(bgp_attr_get_ecommunity(attr),
|
|
|
|
&ecom_sticky));
|
2017-05-15 23:42:57 +02:00
|
|
|
}
|
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* Add RMAC, if told to. */
|
|
|
|
if (add_l3_ecomm) {
|
2017-10-09 13:55:57 +02:00
|
|
|
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
|
2022-02-04 14:56:20 +01:00
|
|
|
ecommunity_add_val(bgp_attr_get_ecommunity(attr), &eval_rmac,
|
|
|
|
true, true);
|
2017-10-09 13:55:57 +02:00
|
|
|
}
|
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* Add default gateway, if needed. */
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
|
2017-11-13 12:19:52 +01:00
|
|
|
encode_default_gw_extcomm(&eval_default_gw);
|
|
|
|
ecom_default_gw.size = 1;
|
2019-10-22 09:21:28 +02:00
|
|
|
ecom_default_gw.unit_size = ECOMMUNITY_SIZE;
|
2017-11-13 12:19:52 +01:00
|
|
|
ecom_default_gw.val = (uint8_t *)eval_default_gw.val;
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr, ecommunity_merge(bgp_attr_get_ecommunity(attr),
|
|
|
|
&ecom_default_gw));
|
2017-11-13 12:19:52 +01:00
|
|
|
}
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT);
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) {
|
|
|
|
encode_na_flag_extcomm(&eval_na,
|
|
|
|
CHECK_FLAG(attr->evpn_flags,
|
|
|
|
ATTR_EVPN_FLAG_ROUTER),
|
|
|
|
proxy);
|
2018-07-07 06:46:46 +02:00
|
|
|
ecom_na.size = 1;
|
2019-10-22 09:21:28 +02:00
|
|
|
ecom_na.unit_size = ECOMMUNITY_SIZE;
|
2018-07-07 06:46:46 +02:00
|
|
|
ecom_na.val = (uint8_t *)eval_na.val;
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr, ecommunity_merge(bgp_attr_get_ecommunity(attr),
|
|
|
|
&ecom_na));
|
2018-07-07 06:46:46 +02:00
|
|
|
}
|
2023-05-08 04:51:28 +02:00
|
|
|
|
|
|
|
/* Add MAC-VRF SoO, if configured */
|
|
|
|
if (macvrf_soo)
|
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr, ecommunity_merge(attr->ecommunity, macvrf_soo));
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add MAC mobility extended community to attribute.
|
|
|
|
*/
|
2018-03-27 21:13:34 +02:00
|
|
|
static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct ecommunity ecom_tmp;
|
|
|
|
struct ecommunity_val eval;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *ecom_val_ptr;
|
2021-01-17 22:08:03 +01:00
|
|
|
uint32_t i;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
2017-05-15 23:34:04 +02:00
|
|
|
int type = 0;
|
|
|
|
int sub_type = 0;
|
2022-02-04 14:56:20 +01:00
|
|
|
struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Build MM */
|
|
|
|
encode_mac_mobility_extcomm(0, seq_num, &eval);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Find current MM ecommunity */
|
2017-06-21 21:55:29 +02:00
|
|
|
ecom_val_ptr = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
if (ecomm) {
|
|
|
|
for (i = 0; i < ecomm->size; i++) {
|
|
|
|
pnt = ecomm->val + (i * ecomm->unit_size);
|
2017-05-15 23:34:04 +02:00
|
|
|
type = *pnt++;
|
|
|
|
sub_type = *pnt++;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
if (type == ECOMMUNITY_ENCODE_EVPN
|
|
|
|
&& sub_type
|
|
|
|
== ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
|
2020-04-08 07:57:15 +02:00
|
|
|
ecom_val_ptr =
|
2022-02-04 14:56:20 +01:00
|
|
|
(ecomm->val + (i * ecomm->unit_size));
|
2017-05-15 23:34:04 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Update the existing MM ecommunity */
|
2017-06-21 21:55:29 +02:00
|
|
|
if (ecom_val_ptr) {
|
2022-02-04 14:56:20 +01:00
|
|
|
memcpy(ecom_val_ptr, eval.val, sizeof(char) * ecomm->unit_size);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
/* Add MM to existing */
|
|
|
|
else {
|
|
|
|
memset(&ecom_tmp, 0, sizeof(ecom_tmp));
|
|
|
|
ecom_tmp.size = 1;
|
2019-10-22 09:21:28 +02:00
|
|
|
ecom_tmp.unit_size = ECOMMUNITY_SIZE;
|
2018-03-27 21:13:34 +02:00
|
|
|
ecom_tmp.val = (uint8_t *)eval.val;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
if (ecomm)
|
|
|
|
bgp_attr_set_ecommunity(
|
|
|
|
attr, ecommunity_merge(ecomm, &ecom_tmp));
|
2018-05-22 16:44:32 +02:00
|
|
|
else
|
2022-02-04 14:56:20 +01:00
|
|
|
bgp_attr_set_ecommunity(attr,
|
|
|
|
ecommunity_dup(&ecom_tmp));
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Install EVPN route into zebra. */
|
2024-02-15 20:23:51 +01:00
|
|
|
enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2019-01-15 00:10:42 +01:00
|
|
|
uint8_t flags;
|
2023-01-30 16:05:41 +01:00
|
|
|
int flood_control = VXLAN_FLOOD_DISABLED;
|
2020-03-28 18:12:04 +01:00
|
|
|
uint32_t seq;
|
2024-02-15 20:23:51 +01:00
|
|
|
enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2019-01-15 00:10:42 +01:00
|
|
|
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
flags = 0;
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
if (pi->sub_type == BGP_ROUTE_IMPORTED) {
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(pi->attr->evpn_flags,
|
|
|
|
ATTR_EVPN_FLAG_STICKY))
|
2020-03-28 18:12:04 +01:00
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(pi->attr->evpn_flags,
|
|
|
|
ATTR_EVPN_FLAG_DEFAULT_GW))
|
2020-03-28 18:12:04 +01:00
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
|
|
|
if (is_evpn_prefix_ipaddr_v6(p) &&
|
2024-07-02 18:31:14 +02:00
|
|
|
CHECK_FLAG(pi->attr->evpn_flags,
|
|
|
|
ATTR_EVPN_FLAG_ROUTER))
|
2020-03-28 18:12:04 +01:00
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
|
|
|
|
|
|
|
|
seq = mac_mobility_seqnum(pi->attr);
|
|
|
|
/* if local ES notify zebra that this is a sync path */
|
|
|
|
if (bgp_evpn_attr_is_local_es(pi->attr)) {
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH);
|
|
|
|
if (bgp_evpn_attr_is_proxy(pi->attr))
|
|
|
|
SET_FLAG(flags,
|
|
|
|
ZEBRA_MACIP_TYPE_PROXY_ADVERT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!bgp_evpn_attr_is_sync(pi->attr))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* if a local path is being turned around and sent
|
|
|
|
* to zebra it is because it is a sync path on
|
|
|
|
* a local ES
|
|
|
|
*/
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH);
|
|
|
|
/* supply the highest peer seq number to zebra
|
|
|
|
* for MM seq syncing
|
|
|
|
*/
|
|
|
|
seq = bgp_evpn_attr_get_sync_seq(pi->attr);
|
|
|
|
/* if any of the paths from the peer have the ROUTER
|
|
|
|
* flag set install the local entry as a router entry
|
|
|
|
*/
|
|
|
|
if (is_evpn_prefix_ipaddr_v6(p) &&
|
|
|
|
(pi->attr->es_flags &
|
|
|
|
ATTR_ES_PEER_ROUTER))
|
|
|
|
SET_FLAG(flags,
|
|
|
|
ZEBRA_MACIP_TYPE_ROUTER_FLAG);
|
|
|
|
|
|
|
|
if (!(pi->attr->es_flags & ATTR_ES_PEER_ACTIVE))
|
|
|
|
SET_FLAG(flags,
|
|
|
|
ZEBRA_MACIP_TYPE_PROXY_ADVERT);
|
|
|
|
}
|
|
|
|
|
2019-01-15 00:10:42 +01:00
|
|
|
ret = bgp_zebra_send_remote_macip(
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp, vpn, p,
|
|
|
|
(is_evpn_prefix_ipaddr_none(p)
|
|
|
|
? NULL /* MAC update */
|
|
|
|
: evpn_type2_path_info_get_mac(
|
|
|
|
pi) /* MAC-IP update */),
|
2021-07-23 19:35:14 +02:00
|
|
|
pi->attr->nexthop, 1, flags, seq,
|
|
|
|
bgp_evpn_attr_get_esi(pi->attr));
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
} else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) {
|
|
|
|
ret = bgp_evpn_remote_es_evi_add(bgp, vpn, p);
|
2019-01-15 00:10:42 +01:00
|
|
|
} else {
|
2020-11-02 16:52:40 +01:00
|
|
|
switch (bgp_attr_get_pmsi_tnl_type(pi->attr)) {
|
2019-03-19 19:29:04 +01:00
|
|
|
case PMSI_TNLTYPE_INGR_REPL:
|
|
|
|
flood_control = VXLAN_FLOOD_HEAD_END_REPL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PMSI_TNLTYPE_PIM_SM:
|
|
|
|
flood_control = VXLAN_FLOOD_PIM_SM;
|
|
|
|
break;
|
|
|
|
|
2023-01-30 16:05:41 +01:00
|
|
|
case PMSI_TNLTYPE_NO_INFO:
|
|
|
|
case PMSI_TNLTYPE_RSVP_TE_P2MP:
|
|
|
|
case PMSI_TNLTYPE_MLDP_P2MP:
|
|
|
|
case PMSI_TNLTYPE_PIM_SSM:
|
|
|
|
case PMSI_TNLTYPE_PIM_BIDIR:
|
|
|
|
case PMSI_TNLTYPE_MLDP_MP2MP:
|
2019-03-19 19:29:04 +01:00
|
|
|
flood_control = VXLAN_FLOOD_DISABLED;
|
|
|
|
break;
|
|
|
|
}
|
2024-02-15 20:23:51 +01:00
|
|
|
|
2019-03-19 19:29:04 +01:00
|
|
|
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1);
|
2019-01-15 00:10:42 +01:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Uninstall EVPN route from zebra. */
|
2024-02-15 20:23:51 +01:00
|
|
|
enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *pi,
|
|
|
|
bool is_sync)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2024-02-15 20:23:51 +01:00
|
|
|
enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
|
2021-07-23 19:35:14 +02:00
|
|
|
ret = bgp_zebra_send_remote_macip(
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp, vpn, p,
|
|
|
|
(is_evpn_prefix_ipaddr_none(p)
|
|
|
|
? NULL /* MAC update */
|
|
|
|
: evpn_type2_path_info_get_mac(
|
|
|
|
pi) /* MAC-IP update */),
|
2021-07-23 19:35:14 +02:00
|
|
|
(is_sync ? zero_vtep_ip : pi->attr->nexthop), 0, 0, 0,
|
|
|
|
NULL);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
|
|
|
|
ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p);
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2019-03-19 19:29:04 +01:00
|
|
|
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p,
|
2024-02-15 20:23:51 +01:00
|
|
|
VXLAN_FLOOD_DISABLED, 0);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Due to MAC mobility, the prior "local" best route has been supplanted
|
|
|
|
* by a "remote" best route. The prior route has to be deleted and withdrawn
|
|
|
|
* from peers.
|
|
|
|
*/
|
|
|
|
static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest,
|
2020-03-28 18:12:04 +01:00
|
|
|
struct bgp_path_info *old_local,
|
|
|
|
struct bgp_path_info *new_select)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *global_dest;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
|
|
|
|
char esi_buf[ESI_STR_LEN];
|
|
|
|
char esi_buf2[ESI_STR_LEN];
|
2020-10-14 17:39:27 +02:00
|
|
|
struct prefix_evpn *evp =
|
|
|
|
(struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("local path deleted %pFX es %s; new-path-es %s", evp,
|
|
|
|
esi_to_str(&old_local->attr->esi, esi_buf,
|
|
|
|
sizeof(esi_buf)),
|
|
|
|
new_select ? esi_to_str(&new_select->attr->esi,
|
|
|
|
esi_buf2, sizeof(esi_buf2))
|
|
|
|
: "");
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Locate route node in the global EVPN routing table. Note that
|
|
|
|
* this table is a 2-level tree (RD-level + Prefix-level) similar to
|
|
|
|
* L3VPN routes.
|
|
|
|
*/
|
2021-07-23 19:35:14 +02:00
|
|
|
global_dest = bgp_evpn_global_node_lookup(
|
2023-03-14 11:05:58 +01:00
|
|
|
bgp->rib[afi][safi], safi,
|
2021-07-23 19:35:14 +02:00
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(dest),
|
|
|
|
&vpn->prd, old_local);
|
2020-03-27 00:11:58 +01:00
|
|
|
if (global_dest) {
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Delete route entry in the global EVPN table. */
|
2020-03-27 00:11:58 +01:00
|
|
|
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Schedule for processing - withdraws to peers happen from
|
|
|
|
* this table.
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (pi)
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, global_dest, pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(global_dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete route entry in the VNI route table, caller to remove. */
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_delete(dest, old_local);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the best path for an EVPN route. Install/update best path in zebra,
|
|
|
|
* if appropriate.
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
* Note: vpn is NULL for local EAD-ES routes.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
|
2024-03-11 19:05:59 +01:00
|
|
|
struct bgp_dest *dest, struct bgp_path_info *pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2024-03-19 17:26:14 +01:00
|
|
|
struct bgp_path_info *old_select, *new_select, *first;
|
2018-10-02 22:41:30 +02:00
|
|
|
struct bgp_path_info_pair old_and_new;
|
2017-05-15 23:34:04 +02:00
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
int ret = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2024-03-19 17:26:14 +01:00
|
|
|
first = bgp_dest_get_bgp_path_info(dest);
|
2024-03-11 19:05:59 +01:00
|
|
|
SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
|
2024-03-19 17:26:14 +01:00
|
|
|
if (pi != first) {
|
|
|
|
if (pi->next)
|
|
|
|
pi->next->prev = pi->prev;
|
|
|
|
if (pi->prev)
|
|
|
|
pi->prev->next = pi->next;
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
first->prev = pi;
|
|
|
|
pi->next = first;
|
|
|
|
pi->prev = NULL;
|
|
|
|
bgp_dest_set_bgp_path_info(dest, pi);
|
|
|
|
}
|
2024-03-11 19:05:59 +01:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Compute the best path. */
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new,
|
2017-05-15 23:34:04 +02:00
|
|
|
afi, safi);
|
|
|
|
old_select = old_and_new.old;
|
|
|
|
new_select = old_and_new.new;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* If the best path hasn't changed - see if there is still something to
|
2020-03-28 18:12:04 +01:00
|
|
|
* update to zebra RIB.
|
|
|
|
* Remote routes and SYNC route (i.e. local routes with
|
|
|
|
* SYNCED_FROM_PEER flag) need to updated to zebra on any attr
|
|
|
|
* change.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
|
|
|
if (old_select && old_select == new_select
|
|
|
|
&& old_select->type == ZEBRA_ROUTE_BGP
|
2020-03-28 18:12:04 +01:00
|
|
|
&& (old_select->sub_type == BGP_ROUTE_IMPORTED ||
|
|
|
|
bgp_evpn_attr_is_sync(old_select->attr))
|
2020-03-27 00:11:58 +01:00
|
|
|
&& !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR)
|
2018-09-14 02:34:42 +02:00
|
|
|
&& !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
|
bgpd: Re-use TX Addpath IDs where possible
The motivation for this patch is to address a concerning behavior of
tx-addpath-bestpath-per-AS. Prior to this patch, all paths' TX ID was
pre-determined as the path was received from a peer. However, this meant
that any time the path selected as best from an AS changed, bgpd had no
choice but to withdraw the previous best path, and advertise the new
best-path under a new TX ID. This could cause significant network
disruption, especially for the subset of prefixes coming from only one
AS that were also communicated over a bestpath-per-AS session.
The patch's general approach is best illustrated by
txaddpath_update_ids. After a bestpath run (required for best-per-AS to
know what will and will not be sent as addpaths) ID numbers will be
stripped from paths that no longer need to be sent, and held in a pool.
Then, paths that will be sent as addpaths and do not already have ID
numbers will allocate new ID numbers, pulling first from that pool.
Finally, anything left in the pool will be returned to the allocator.
In order for this to work, ID numbers had to be split by strategy. The
tx-addpath-All strategy would keep every ID number "in use" constantly,
preventing IDs from being transferred to different paths. Rather than
create two variables for ID, this patch create a more generic array that
will easily enable more addpath strategies to be implemented. The
previously described ID manipulations will happen per addpath strategy,
and will only be run for strategies that are enabled on at least one
peer.
Finally, the ID numbers are allocated from an allocator that tracks per
AFI/SAFI/Addpath Strategy which IDs are in use. Though it would be very
improbable, there was the possibility with the free-running counter
approach for rollover to cause two paths on the same prefix to get
assigned the same TX ID. As remote as the possibility is, we prefer to
not leave it to chance.
This ID re-use method is not perfect. In some cases you could still get
withdraw-then-add behaviors where not strictly necessary. In the case of
bestpath-per-AS this requires one AS to advertise a prefix for the first
time, then a second AS withdraws that prefix, all within the space of an
already pending MRAI timer. In those situations a withdraw-then-add is
more forgivable, and fixing it would probably require a much more
significant effort, as IDs would need to be moved to ADVs instead of
paths.
Signed-off-by Mitchell Skiba <mskiba@amazon.com>
2018-05-10 01:10:02 +02:00
|
|
|
&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
|
2024-02-15 20:23:51 +01:00
|
|
|
if (bgp_zebra_has_route_changed(old_select)) {
|
|
|
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
|
|
|
|
evpn_zebra_install(bgp, vpn,
|
|
|
|
(const struct prefix_evpn *)
|
|
|
|
bgp_dest_get_prefix(
|
|
|
|
dest),
|
|
|
|
old_select);
|
|
|
|
else
|
|
|
|
bgp_zebra_route_install(dest, old_select, bgp,
|
|
|
|
true, vpn, false);
|
|
|
|
}
|
|
|
|
|
2018-09-14 02:34:42 +02:00
|
|
|
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
|
2020-03-24 21:57:44 +01:00
|
|
|
UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_zebra_clear_route_change_flags(dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* If the user did a "clear" this flag will be set */
|
2020-03-27 00:11:58 +01:00
|
|
|
UNSET_FLAG(dest->flags, BGP_NODE_USER_CLEAR);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* bestpath has changed; update relevant fields and install or uninstall
|
|
|
|
* into the zebra RIB.
|
|
|
|
*/
|
|
|
|
if (old_select || new_select)
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_bump_version(dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
if (old_select)
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED);
|
2017-05-15 23:34:04 +02:00
|
|
|
if (new_select) {
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED);
|
|
|
|
bgp_path_info_unset_flag(dest, new_select,
|
|
|
|
BGP_PATH_ATTR_CHANGED);
|
2018-09-14 02:34:42 +02:00
|
|
|
UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG);
|
2020-03-24 21:57:44 +01:00
|
|
|
UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
/* a local entry with the SYNC flag also results in a MAC-IP update
|
|
|
|
* to zebra
|
|
|
|
*/
|
2017-05-15 23:34:04 +02:00
|
|
|
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
|
2020-03-28 18:12:04 +01:00
|
|
|
&& (new_select->sub_type == BGP_ROUTE_IMPORTED ||
|
|
|
|
bgp_evpn_attr_is_sync(new_select->attr))) {
|
2024-02-15 20:23:51 +01:00
|
|
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
|
|
|
|
evpn_zebra_install(bgp, vpn,
|
|
|
|
(const struct prefix_evpn *)
|
|
|
|
bgp_dest_get_prefix(dest),
|
|
|
|
new_select);
|
|
|
|
else
|
|
|
|
bgp_zebra_route_install(dest, new_select, bgp, true,
|
|
|
|
vpn, false);
|
2019-01-15 00:10:42 +01:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* If an old best existed and it was a "local" route, the only
|
|
|
|
* reason
|
|
|
|
* it would be supplanted is due to MAC mobility procedures. So,
|
|
|
|
* we
|
|
|
|
* need to do an implicit delete and withdraw that route from
|
|
|
|
* peers.
|
|
|
|
*/
|
2020-03-28 18:12:04 +01:00
|
|
|
if (new_select->sub_type == BGP_ROUTE_IMPORTED &&
|
|
|
|
old_select && old_select->peer == bgp->peer_self
|
|
|
|
&& old_select->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& old_select->sub_type == BGP_ROUTE_STATIC
|
|
|
|
&& vpn)
|
|
|
|
evpn_delete_old_local_route(bgp, vpn, dest,
|
|
|
|
old_select, new_select);
|
2017-05-15 23:34:04 +02:00
|
|
|
} else {
|
2024-02-15 20:23:51 +01:00
|
|
|
if (old_select && old_select->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
old_select->sub_type == BGP_ROUTE_IMPORTED) {
|
|
|
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) ||
|
|
|
|
CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN))
|
|
|
|
evpn_zebra_uninstall(bgp, vpn,
|
|
|
|
(const struct prefix_evpn *)
|
|
|
|
bgp_dest_get_prefix(
|
|
|
|
dest),
|
|
|
|
old_select, false);
|
|
|
|
else
|
|
|
|
bgp_zebra_route_install(dest, old_select, bgp,
|
|
|
|
false, vpn, false);
|
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Clear any route change flags. */
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_zebra_clear_route_change_flags(dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-03 00:15:34 +02:00
|
|
|
/* Reap old select bgp_path_info, if it has been removed */
|
2018-09-14 02:34:42 +02:00
|
|
|
if (old_select && CHECK_FLAG(old_select->flags, BGP_PATH_REMOVED))
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_reap(dest, old_select);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
static struct bgp_path_info *bgp_evpn_route_get_local_path(
|
|
|
|
struct bgp *bgp, struct bgp_dest *dest)
|
2017-05-15 23:42:57 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *tmp_pi;
|
2020-03-28 18:12:04 +01:00
|
|
|
struct bgp_path_info *local_pi = NULL;
|
2017-05-15 23:42:57 +02:00
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
|
2020-03-28 18:12:04 +01:00
|
|
|
tmp_pi = tmp_pi->next) {
|
|
|
|
if (bgp_evpn_is_path_local(bgp, tmp_pi)) {
|
2018-10-03 02:43:07 +02:00
|
|
|
local_pi = tmp_pi;
|
2020-03-28 18:12:04 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-05-15 23:42:57 +02:00
|
|
|
}
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
return local_pi;
|
2017-05-15 23:42:57 +02:00
|
|
|
}
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
|
2017-10-27 23:15:45 +02:00
|
|
|
struct bgp *bgp_vrf, afi_t afi,
|
2020-03-27 00:11:58 +01:00
|
|
|
safi_t safi, struct bgp_dest *dest,
|
2024-03-11 16:22:49 +01:00
|
|
|
struct attr *attr, int *route_changed,
|
|
|
|
struct bgp_path_info **entry)
|
2017-10-27 23:15:45 +02:00
|
|
|
{
|
|
|
|
struct attr *attr_new = NULL;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi = NULL;
|
2024-02-26 18:23:11 +01:00
|
|
|
struct bgp_labels bgp_labels = {};
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *local_pi = NULL;
|
|
|
|
struct bgp_path_info *tmp_pi = NULL;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2017-11-09 11:37:09 +01:00
|
|
|
*route_changed = 0;
|
2023-04-12 15:40:26 +02:00
|
|
|
|
|
|
|
/* See if this is an update of an existing route, or a new add. */
|
|
|
|
local_pi = bgp_evpn_route_get_local_path(bgp_evpn, dest);
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2018-05-16 14:17:53 +02:00
|
|
|
/*
|
2018-10-25 20:06:59 +02:00
|
|
|
* create a new route entry if one doesn't exist.
|
2018-05-16 14:17:53 +02:00
|
|
|
* Otherwise see if route attr has changed
|
2017-12-27 20:47:10 +01:00
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!local_pi) {
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2017-11-09 11:37:09 +01:00
|
|
|
/* route has changed as this is the first entry */
|
|
|
|
*route_changed = 1;
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
/* Add (or update) attribute to hash. */
|
|
|
|
attr_new = bgp_attr_intern(attr);
|
|
|
|
|
|
|
|
/* create the route info from attribute */
|
2018-10-03 02:43:07 +02:00
|
|
|
pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_evpn->peer_self, attr_new, dest);
|
2018-10-03 02:43:07 +02:00
|
|
|
SET_FLAG(pi->flags, BGP_PATH_VALID);
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2017-11-21 11:42:05 +01:00
|
|
|
/* Type-5 routes advertise the L3-VNI */
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_path_info_extra_get(pi);
|
2024-02-26 18:23:11 +01:00
|
|
|
vni2label(bgp_vrf->l3vni, &bgp_labels.label[0]);
|
|
|
|
bgp_labels.num_labels = 1;
|
|
|
|
if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0],
|
|
|
|
bgp_labels.num_labels)) {
|
|
|
|
bgp_labels_unintern(&pi->extra->labels);
|
|
|
|
pi->extra->labels = bgp_labels_intern(&bgp_labels);
|
|
|
|
}
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* add the route entry to route node*/
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_add(dest, pi);
|
2024-03-11 16:22:49 +01:00
|
|
|
*entry = pi;
|
2017-10-27 23:15:45 +02:00
|
|
|
} else {
|
2018-10-03 02:43:07 +02:00
|
|
|
tmp_pi = local_pi;
|
|
|
|
if (!attrhash_cmp(tmp_pi->attr, attr)) {
|
2017-11-09 11:37:09 +01:00
|
|
|
|
|
|
|
/* attribute changed */
|
|
|
|
*route_changed = 1;
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
/* The attribute has changed. */
|
|
|
|
/* Add (or update) attribute to hash. */
|
|
|
|
attr_new = bgp_attr_intern(attr);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_set_flag(dest, tmp_pi,
|
2018-10-03 00:15:34 +02:00
|
|
|
BGP_PATH_ATTR_CHANGED);
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* Restore route, if needed. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_restore(dest, tmp_pi);
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* Unintern existing, set to new. */
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_attr_unintern(&tmp_pi->attr);
|
|
|
|
tmp_pi->attr = attr_new;
|
2022-08-18 00:27:54 +02:00
|
|
|
tmp_pi->uptime = monotime(NULL);
|
2017-10-27 23:15:45 +02:00
|
|
|
}
|
2024-03-11 16:22:49 +01:00
|
|
|
*entry = local_pi;
|
2017-10-27 23:15:45 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update evpn type-5 route entry */
|
|
|
|
static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
|
2021-01-11 03:32:34 +01:00
|
|
|
struct attr *src_attr, afi_t src_afi,
|
|
|
|
safi_t src_safi)
|
2017-10-27 23:15:45 +02:00
|
|
|
{
|
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
struct attr attr;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest = NULL;
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-11-09 11:37:09 +01:00
|
|
|
int route_changed = 0;
|
2024-03-11 16:22:49 +01:00
|
|
|
struct bgp_path_info *pi = NULL;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
2018-01-05 21:41:25 +01:00
|
|
|
return 0;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2017-12-04 18:52:54 +01:00
|
|
|
/* Build path attribute for this route - use the source attr, if
|
|
|
|
* present, else treat as locally originated.
|
|
|
|
*/
|
|
|
|
if (src_attr)
|
2019-12-03 22:01:19 +01:00
|
|
|
attr = *src_attr;
|
2017-12-04 18:52:54 +01:00
|
|
|
else {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&attr, 0, sizeof(attr));
|
2022-06-06 08:49:37 +02:00
|
|
|
bgp_attr_default_set(&attr, bgp_vrf, BGP_ORIGIN_IGP);
|
2017-12-04 18:52:54 +01:00
|
|
|
}
|
2019-04-18 09:17:57 +02:00
|
|
|
|
|
|
|
/* Advertise Primary IP (PIP) is enabled, send individual
|
|
|
|
* IP (default instance router-id) as nexthop.
|
|
|
|
* PIP is disabled or vrr interface is not present
|
2019-10-26 00:27:47 +02:00
|
|
|
* use anycast-IP as nexthop and anycast RMAC.
|
2019-04-18 09:17:57 +02:00
|
|
|
*/
|
|
|
|
if (!bgp_vrf->evpn_info->advertise_pip ||
|
|
|
|
(!bgp_vrf->evpn_info->is_anycast_mac)) {
|
|
|
|
attr.nexthop = bgp_vrf->originator_ip;
|
|
|
|
attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
|
2019-10-26 00:27:47 +02:00
|
|
|
memcpy(&attr.rmac, &bgp_vrf->rmac, ETH_ALEN);
|
2019-04-18 09:17:57 +02:00
|
|
|
} else {
|
2019-10-26 00:27:47 +02:00
|
|
|
/* copy sys rmac */
|
|
|
|
memcpy(&attr.rmac, &bgp_vrf->evpn_info->pip_rmac, ETH_ALEN);
|
2019-04-18 09:17:57 +02:00
|
|
|
if (bgp_vrf->evpn_info->pip_ip.s_addr != INADDR_ANY) {
|
|
|
|
attr.nexthop = bgp_vrf->evpn_info->pip_ip;
|
|
|
|
attr.mp_nexthop_global_in = bgp_vrf->evpn_info->pip_ip;
|
|
|
|
} else if (bgp_vrf->evpn_info->pip_ip.s_addr == INADDR_ANY)
|
2020-10-18 13:33:54 +02:00
|
|
|
if (bgp_debug_zebra(NULL))
|
|
|
|
zlog_debug(
|
|
|
|
"VRF %s evp %pFX advertise-pip primary ip is not configured",
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id), evp);
|
2019-04-18 09:17:57 +02:00
|
|
|
}
|
|
|
|
|
2021-03-10 01:50:42 +01:00
|
|
|
if (bgp_debug_zebra(NULL))
|
|
|
|
zlog_debug(
|
|
|
|
"VRF %s type-5 route evp %pFX RMAC %pEA nexthop %pI4",
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id), evp, &attr.rmac,
|
|
|
|
&attr.nexthop);
|
2019-04-18 09:17:57 +02:00
|
|
|
|
bgpd: lttng tp add evpn route events
Ticket:#3597393
Testing Done:
2023-09-08T22:53:03.532 frr_bgp:evpn_withdraw_type5 {'vrf_id': 42, 'ip':
'53.1.1.0'}
2023-09-08T22:53:06.207 frr_bgp:evpn_advertise_type5 {'vrf_id': 42,
'ip': '53.1.1.0', 'rmac': '00:02:00:00:00:38', 'vtep': '27.0.0.15'}
2023-09-08T21:51:15.637 frr_bgp:evpn_mh_local_ead_es_evi_route_upd
{'esi': '03:44:38:39:ff:ff:01:00:00:03', 'vni': 1000, 'route_type': 1,
'vtep': '27.0.0.15'}
2023-09-08T20:45:17.059 frr_bgp:evpn_mh_local_ead_es_evi_route_del
{'esi': '03:44:38:39:ff:ff:01:00:00:01', 'vni': 0, 'route_type': 4,
'vtep': '27.0.0.15'}
2023-09-08T21:51:18.363 frr_bgp:evpn_mh_es_evi_vtep_add {'esi':
'03:44:38:39:ff:ff:01:00:00:02', 'vni': 1000, 'vtep': '27.0.0.16',
'ead_es': 1}
2023-09-08T20:43:50.206 frr_bgp:evpn_mh_es_evi_vtep_del {'esi':
'03:44:38:39:ff:ff:01:00:00:01', 'vni': 1002, 'vtep': '27.0.0.16',
'ead_es': 0}
Signed-off-by: Chirag Shah <chirag@nvidia.com>
2023-09-08 00:51:32 +02:00
|
|
|
frrtrace(4, frr_bgp, evpn_advertise_type5, bgp_vrf->vrf_id, evp,
|
|
|
|
&attr.rmac, attr.nexthop);
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
|
|
|
|
2021-01-11 03:32:34 +01:00
|
|
|
if (src_afi == AFI_IP6 &&
|
|
|
|
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
|
|
|
BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
|
|
|
|
if (src_attr &&
|
|
|
|
!IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) {
|
|
|
|
attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
|
2022-01-19 21:06:45 +01:00
|
|
|
SET_IPADDR_V6(&attr.evpn_overlay.gw_ip);
|
|
|
|
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6,
|
2021-01-11 03:32:34 +01:00
|
|
|
&src_attr->mp_nexthop_global,
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
}
|
|
|
|
} else if (src_afi == AFI_IP &&
|
|
|
|
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
|
|
|
BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
|
|
|
|
if (src_attr && src_attr->nexthop.s_addr != 0) {
|
|
|
|
attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
|
2022-01-19 21:06:45 +01:00
|
|
|
SET_IPADDR_V4(&attr.evpn_overlay.gw_ip);
|
|
|
|
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4,
|
2021-01-11 03:32:34 +01:00
|
|
|
&src_attr->nexthop, sizeof(struct in_addr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
/* Setup RT and encap extended community */
|
|
|
|
build_evpn_type5_route_extcomm(bgp_vrf, &attr);
|
|
|
|
|
|
|
|
/* get the route node in global table */
|
2021-07-23 19:35:14 +02:00
|
|
|
dest = bgp_evpn_global_node_get(bgp_evpn->rib[afi][safi], afi, safi,
|
|
|
|
evp, &bgp_vrf->vrf_prd, NULL);
|
2020-03-27 00:11:58 +01:00
|
|
|
assert(dest);
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* create or update the route entry within the route node */
|
2020-03-27 00:11:58 +01:00
|
|
|
update_evpn_type5_route_entry(bgp_evpn, bgp_vrf, afi, safi, dest, &attr,
|
2024-03-11 16:22:49 +01:00
|
|
|
&route_changed, &pi);
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* schedule for processing and unlock node */
|
2017-11-09 11:37:09 +01:00
|
|
|
if (route_changed) {
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp_evpn, dest, pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2017-11-09 11:37:09 +01:00
|
|
|
}
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* uninten temporary */
|
2017-12-09 01:36:27 +01:00
|
|
|
if (!src_attr)
|
|
|
|
aspath_unintern(&attr.aspath);
|
2017-10-27 23:15:45 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
|
2020-10-14 17:19:45 +02:00
|
|
|
struct bgp_dest *dest, uint32_t loc_seq,
|
|
|
|
uint32_t *max_sync_seq, bool *active_on_peer,
|
2021-08-23 19:11:05 +02:00
|
|
|
bool *peer_router, bool *proxy_from_peer,
|
|
|
|
const struct ethaddr *mac)
|
2020-03-28 18:12:04 +01:00
|
|
|
{
|
|
|
|
struct bgp_path_info *tmp_pi;
|
|
|
|
struct bgp_path_info *second_best_path = NULL;
|
|
|
|
uint32_t tmp_mm_seq = 0;
|
|
|
|
esi_t *tmp_esi;
|
|
|
|
int paths_eq;
|
2021-08-23 19:11:05 +02:00
|
|
|
struct ethaddr *tmp_mac;
|
|
|
|
bool mac_cmp = false;
|
2023-07-31 14:34:48 +02:00
|
|
|
struct prefix_evpn *evp = (struct prefix_evpn *)&dest->rn->p;
|
2021-08-23 19:11:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* mac comparison is not needed for MAC-only routes */
|
|
|
|
if (mac && !is_evpn_prefix_ipaddr_none(evp))
|
|
|
|
mac_cmp = true;
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
/* find the best non-local path. a local path can only be present
|
|
|
|
* as best path
|
|
|
|
*/
|
2020-10-14 17:19:45 +02:00
|
|
|
for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
|
|
|
|
tmp_pi = tmp_pi->next) {
|
2020-03-28 18:12:04 +01:00
|
|
|
if (tmp_pi->sub_type != BGP_ROUTE_IMPORTED ||
|
|
|
|
!CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID))
|
|
|
|
continue;
|
|
|
|
|
2021-08-23 19:11:05 +02:00
|
|
|
/* ignore paths that have a different mac */
|
|
|
|
if (mac_cmp) {
|
|
|
|
tmp_mac = evpn_type2_path_info_get_mac(tmp_pi);
|
|
|
|
if (memcmp(mac, tmp_mac, sizeof(*mac)))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-09-19 21:51:05 +02:00
|
|
|
if (bgp_evpn_path_info_cmp(bgp, tmp_pi, second_best_path,
|
|
|
|
&paths_eq, false))
|
2020-03-28 18:12:04 +01:00
|
|
|
second_best_path = tmp_pi;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!second_best_path)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tmp_esi = bgp_evpn_attr_get_esi(second_best_path->attr);
|
|
|
|
/* if this has the same ES desination as the local path
|
|
|
|
* it is a sync path
|
|
|
|
*/
|
|
|
|
if (!memcmp(esi, tmp_esi, sizeof(esi_t))) {
|
|
|
|
tmp_mm_seq = mac_mobility_seqnum(second_best_path->attr);
|
|
|
|
if (tmp_mm_seq < loc_seq)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* we have a non-proxy path from the ES peer. */
|
|
|
|
if (second_best_path->attr->es_flags &
|
|
|
|
ATTR_ES_PROXY_ADVERT) {
|
|
|
|
*proxy_from_peer = true;
|
|
|
|
} else {
|
|
|
|
*active_on_peer = true;
|
|
|
|
}
|
|
|
|
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(second_best_path->attr->evpn_flags,
|
|
|
|
ATTR_EVPN_FLAG_ROUTER))
|
2020-03-28 18:12:04 +01:00
|
|
|
*peer_router = true;
|
|
|
|
|
|
|
|
/* we use both proxy and non-proxy imports to
|
|
|
|
* determine the max sync sequence
|
|
|
|
*/
|
|
|
|
if (tmp_mm_seq > *max_sync_seq)
|
|
|
|
*max_sync_seq = tmp_mm_seq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bubble up sync-info from all paths (non-best) to the local-path.
|
|
|
|
* This is need for MM sequence number syncing and proxy advertisement.
|
|
|
|
* Note: The local path can only exist as a best path in the
|
|
|
|
* VPN route table. It will take precedence over all sync paths.
|
|
|
|
*/
|
|
|
|
static void update_evpn_route_entry_sync_info(struct bgp *bgp,
|
2020-10-14 17:19:45 +02:00
|
|
|
struct bgp_dest *dest,
|
|
|
|
struct attr *attr,
|
2021-08-23 19:11:05 +02:00
|
|
|
uint32_t loc_seq, bool setup_sync,
|
|
|
|
const struct ethaddr *mac)
|
2020-03-28 18:12:04 +01:00
|
|
|
{
|
|
|
|
esi_t *esi;
|
2020-10-14 17:39:27 +02:00
|
|
|
struct prefix_evpn *evp =
|
|
|
|
(struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
esi = bgp_evpn_attr_get_esi(attr);
|
|
|
|
if (bgp_evpn_is_esi_valid(esi)) {
|
|
|
|
if (setup_sync) {
|
|
|
|
uint32_t max_sync_seq = 0;
|
|
|
|
bool active_on_peer = false;
|
|
|
|
bool peer_router = false;
|
|
|
|
bool proxy_from_peer = false;
|
|
|
|
|
2020-10-14 17:19:45 +02:00
|
|
|
bgp_evpn_get_sync_info(bgp, esi, dest, loc_seq,
|
|
|
|
&max_sync_seq, &active_on_peer,
|
2021-08-23 19:11:05 +02:00
|
|
|
&peer_router, &proxy_from_peer,
|
|
|
|
mac);
|
2020-03-28 18:12:04 +01:00
|
|
|
attr->mm_sync_seqnum = max_sync_seq;
|
|
|
|
if (active_on_peer)
|
|
|
|
attr->es_flags |= ATTR_ES_PEER_ACTIVE;
|
|
|
|
else
|
|
|
|
attr->es_flags &= ~ATTR_ES_PEER_ACTIVE;
|
|
|
|
if (proxy_from_peer)
|
|
|
|
attr->es_flags |= ATTR_ES_PEER_PROXY;
|
|
|
|
else
|
|
|
|
attr->es_flags &= ~ATTR_ES_PEER_PROXY;
|
|
|
|
if (peer_router)
|
|
|
|
attr->es_flags |= ATTR_ES_PEER_ROUTER;
|
|
|
|
else
|
|
|
|
attr->es_flags &= ~ATTR_ES_PEER_ROUTER;
|
|
|
|
|
|
|
|
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
|
|
|
|
char esi_buf[ESI_STR_LEN];
|
|
|
|
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug(
|
|
|
|
"setup sync info for %pFX es %s max_seq %d %s%s%s",
|
|
|
|
evp,
|
2020-03-28 18:12:04 +01:00
|
|
|
esi_to_str(esi, esi_buf,
|
2020-10-18 13:33:54 +02:00
|
|
|
sizeof(esi_buf)),
|
2020-03-28 18:12:04 +01:00
|
|
|
max_sync_seq,
|
2020-10-18 13:33:54 +02:00
|
|
|
(attr->es_flags & ATTR_ES_PEER_ACTIVE)
|
|
|
|
? "peer-active "
|
|
|
|
: "",
|
|
|
|
(attr->es_flags & ATTR_ES_PEER_PROXY)
|
|
|
|
? "peer-proxy "
|
|
|
|
: "",
|
|
|
|
(attr->es_flags & ATTR_ES_PEER_ROUTER)
|
|
|
|
? "peer-router "
|
|
|
|
: "");
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
attr->mm_sync_seqnum = 0;
|
|
|
|
attr->es_flags &= ~ATTR_ES_PEER_ACTIVE;
|
|
|
|
attr->es_flags &= ~ATTR_ES_PEER_PROXY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* Create or update EVPN route entry. This could be in the VNI route tables
|
2017-05-15 23:34:04 +02:00
|
|
|
* or the global route table.
|
|
|
|
*/
|
|
|
|
static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
2020-05-09 04:36:47 +02:00
|
|
|
afi_t afi, safi_t safi,
|
|
|
|
struct bgp_dest *dest, struct attr *attr,
|
2021-10-26 23:55:54 +02:00
|
|
|
const struct ethaddr *mac,
|
|
|
|
const struct ipaddr *ip, int add,
|
2021-07-23 19:35:14 +02:00
|
|
|
struct bgp_path_info **pi, uint8_t flags,
|
|
|
|
uint32_t seq, bool vpn_rt, bool *old_is_sync)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *tmp_pi;
|
|
|
|
struct bgp_path_info *local_pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct attr *attr_new;
|
bgpd: attr evpn attributes should be modified before interning attr
As remind, the attr attribute is a structure that contains
the attributes for a given BGP update. In order to avoid too much
memory consumption, the attr structure is stored in a hash table.
As consequence, other BGP updates may reuse the same attr. The
storage in the hash table is done when calling bgp_attr_intern(),
and a key is calculated based on all the attributes values of the
structure.
In BGP EVPN, when modifying the attributes of the attr structure
after having interned it, this means that some BGP updates will
want to use the old reference, whereas a new attr value is used.
Because in BGP EVPN, the modifications are done on a per BGP update
basis, a new attr entry specific to that BGP update should be created.
This is why a local_attr structure is done, modified, then later
interned.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-01-31 09:27:01 +01:00
|
|
|
struct attr local_attr;
|
2024-02-26 18:23:11 +01:00
|
|
|
struct bgp_labels bgp_labels = {};
|
2017-05-15 23:34:04 +02:00
|
|
|
int route_change = 1;
|
2020-03-22 05:02:18 +01:00
|
|
|
const struct prefix_evpn *evp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
*pi = NULL;
|
2020-03-27 00:11:58 +01:00
|
|
|
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* See if this is an update of an existing route, or a new add. */
|
2020-03-28 18:12:04 +01:00
|
|
|
local_pi = bgp_evpn_route_get_local_path(bgp, dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* If route doesn't exist already, create a new one, if told to.
|
|
|
|
* Otherwise act based on whether the attributes of the route have
|
|
|
|
* changed or not.
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!local_pi && !add)
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
if (old_is_sync && local_pi)
|
|
|
|
*old_is_sync = bgp_evpn_attr_is_sync(local_pi->attr);
|
|
|
|
|
|
|
|
/* if a local path is being added with a non-zero esi look
|
|
|
|
* for SYNC paths from ES peers and bubble up the sync-info
|
|
|
|
*/
|
2021-08-23 19:11:05 +02:00
|
|
|
update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt, mac);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* For non-GW MACs, update MAC mobility seq number, if needed. */
|
|
|
|
if (seq && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
|
|
|
|
add_mac_mobility_to_attr(seq, attr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!local_pi) {
|
bgpd: attr evpn attributes should be modified before interning attr
As remind, the attr attribute is a structure that contains
the attributes for a given BGP update. In order to avoid too much
memory consumption, the attr structure is stored in a hash table.
As consequence, other BGP updates may reuse the same attr. The
storage in the hash table is done when calling bgp_attr_intern(),
and a key is calculated based on all the attributes values of the
structure.
In BGP EVPN, when modifying the attributes of the attr structure
after having interned it, this means that some BGP updates will
want to use the old reference, whereas a new attr value is used.
Because in BGP EVPN, the modifications are done on a per BGP update
basis, a new attr entry specific to that BGP update should be created.
This is why a local_attr structure is done, modified, then later
interned.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-01-31 09:27:01 +01:00
|
|
|
local_attr = *attr;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Extract MAC mobility sequence number, if any. */
|
2024-07-02 18:31:14 +02:00
|
|
|
local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr);
|
bgpd: attr evpn attributes should be modified before interning attr
As remind, the attr attribute is a structure that contains
the attributes for a given BGP update. In order to avoid too much
memory consumption, the attr structure is stored in a hash table.
As consequence, other BGP updates may reuse the same attr. The
storage in the hash table is done when calling bgp_attr_intern(),
and a key is calculated based on all the attributes values of the
structure.
In BGP EVPN, when modifying the attributes of the attr structure
after having interned it, this means that some BGP updates will
want to use the old reference, whereas a new attr value is used.
Because in BGP EVPN, the modifications are done on a per BGP update
basis, a new attr entry specific to that BGP update should be created.
This is why a local_attr structure is done, modified, then later
interned.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-01-31 09:27:01 +01:00
|
|
|
|
|
|
|
/* Add (or update) attribute to hash. */
|
|
|
|
attr_new = bgp_attr_intern(&local_attr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Create new route with its attribute. */
|
2018-10-03 02:43:07 +02:00
|
|
|
tmp_pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp->peer_self, attr_new, dest);
|
2018-10-03 02:43:07 +02:00
|
|
|
SET_FLAG(tmp_pi->flags, BGP_PATH_VALID);
|
|
|
|
bgp_path_info_extra_get(tmp_pi);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* The VNI goes into the 'label' field of the route */
|
2024-02-26 18:23:11 +01:00
|
|
|
vni2label(vpn->vni, &bgp_labels.label[0]);
|
|
|
|
bgp_labels.num_labels = 1;
|
2018-02-06 23:28:22 +01:00
|
|
|
|
|
|
|
/* Type-2 routes may carry a second VNI - the L3-VNI.
|
|
|
|
* Only attach second label if we are advertising two labels for
|
|
|
|
* type-2 routes.
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
&& CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
|
2017-11-21 11:42:05 +01:00
|
|
|
vni_t l3vni;
|
|
|
|
|
|
|
|
l3vni = bgpevpn_get_l3vni(vpn);
|
|
|
|
if (l3vni) {
|
2024-02-26 18:23:11 +01:00
|
|
|
vni2label(l3vni, &bgp_labels.label[1]);
|
|
|
|
bgp_labels.num_labels++;
|
2017-11-21 11:42:05 +01:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2024-02-26 18:23:11 +01:00
|
|
|
if (!bgp_path_info_labels_same(tmp_pi, &bgp_labels.label[0],
|
|
|
|
bgp_labels.num_labels)) {
|
|
|
|
bgp_labels_unintern(&tmp_pi->extra->labels);
|
|
|
|
tmp_pi->extra->labels = bgp_labels_intern(&bgp_labels);
|
|
|
|
}
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
if (mac)
|
|
|
|
evpn_type2_path_info_set_mac(tmp_pi, *mac);
|
|
|
|
else if (ip)
|
|
|
|
evpn_type2_path_info_set_ip(tmp_pi, *ip);
|
|
|
|
}
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2019-08-09 03:58:03 +02:00
|
|
|
/* Mark route as self type-2 route */
|
|
|
|
if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
|
2023-08-08 12:47:29 +02:00
|
|
|
tmp_pi->extra->evpn->af_flags =
|
|
|
|
BGP_EVPN_MACIP_TYPE_SVI_IP;
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_add(dest, tmp_pi);
|
2017-05-15 23:34:04 +02:00
|
|
|
} else {
|
2018-10-03 02:43:07 +02:00
|
|
|
tmp_pi = local_pi;
|
|
|
|
if (attrhash_cmp(tmp_pi->attr, attr)
|
|
|
|
&& !CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
|
2017-05-15 23:34:04 +02:00
|
|
|
route_change = 0;
|
|
|
|
else {
|
2018-02-06 23:28:22 +01:00
|
|
|
/*
|
|
|
|
* The attributes have changed, type-2 routes needs to
|
|
|
|
* be advertised with right labels.
|
|
|
|
*/
|
2024-02-26 18:23:11 +01:00
|
|
|
vni2label(vpn->vni, &bgp_labels.label[0]);
|
|
|
|
bgp_labels.num_labels = 1;
|
2018-02-06 23:28:22 +01:00
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
&& CHECK_FLAG(vpn->flags,
|
|
|
|
VNI_FLAG_USE_TWO_LABELS)) {
|
|
|
|
vni_t l3vni;
|
|
|
|
|
|
|
|
l3vni = bgpevpn_get_l3vni(vpn);
|
|
|
|
if (l3vni) {
|
2024-02-26 18:23:11 +01:00
|
|
|
vni2label(l3vni, &bgp_labels.label[1]);
|
|
|
|
bgp_labels.num_labels++;
|
2018-02-06 23:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
2024-02-26 18:23:11 +01:00
|
|
|
if (!bgp_path_info_labels_same(tmp_pi,
|
|
|
|
&bgp_labels.label[0],
|
|
|
|
bgp_labels.num_labels)) {
|
|
|
|
bgp_labels_unintern(&tmp_pi->extra->labels);
|
|
|
|
tmp_pi->extra->labels =
|
|
|
|
bgp_labels_intern(&bgp_labels);
|
|
|
|
}
|
2018-02-06 23:28:22 +01:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
if (mac)
|
|
|
|
evpn_type2_path_info_set_mac(tmp_pi,
|
|
|
|
*mac);
|
|
|
|
else if (ip)
|
|
|
|
evpn_type2_path_info_set_ip(tmp_pi,
|
|
|
|
*ip);
|
|
|
|
}
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* The attribute has changed. */
|
|
|
|
/* Add (or update) attribute to hash. */
|
bgpd: attr evpn attributes should be modified before interning attr
As remind, the attr attribute is a structure that contains
the attributes for a given BGP update. In order to avoid too much
memory consumption, the attr structure is stored in a hash table.
As consequence, other BGP updates may reuse the same attr. The
storage in the hash table is done when calling bgp_attr_intern(),
and a key is calculated based on all the attributes values of the
structure.
In BGP EVPN, when modifying the attributes of the attr structure
after having interned it, this means that some BGP updates will
want to use the old reference, whereas a new attr value is used.
Because in BGP EVPN, the modifications are done on a per BGP update
basis, a new attr entry specific to that BGP update should be created.
This is why a local_attr structure is done, modified, then later
interned.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-01-31 09:27:01 +01:00
|
|
|
local_attr = *attr;
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_set_flag(dest, tmp_pi,
|
2018-10-03 00:15:34 +02:00
|
|
|
BGP_PATH_ATTR_CHANGED);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Extract MAC mobility sequence number, if any. */
|
2024-07-02 18:31:14 +02:00
|
|
|
local_attr.mm_seqnum =
|
|
|
|
bgp_attr_mac_mobility_seqnum(&local_attr);
|
bgpd: attr evpn attributes should be modified before interning attr
As remind, the attr attribute is a structure that contains
the attributes for a given BGP update. In order to avoid too much
memory consumption, the attr structure is stored in a hash table.
As consequence, other BGP updates may reuse the same attr. The
storage in the hash table is done when calling bgp_attr_intern(),
and a key is calculated based on all the attributes values of the
structure.
In BGP EVPN, when modifying the attributes of the attr structure
after having interned it, this means that some BGP updates will
want to use the old reference, whereas a new attr value is used.
Because in BGP EVPN, the modifications are done on a per BGP update
basis, a new attr entry specific to that BGP update should be created.
This is why a local_attr structure is done, modified, then later
interned.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-01-31 09:27:01 +01:00
|
|
|
|
|
|
|
attr_new = bgp_attr_intern(&local_attr);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Restore route, if needed. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_restore(dest, tmp_pi);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Unintern existing, set to new. */
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_attr_unintern(&tmp_pi->attr);
|
|
|
|
tmp_pi->attr = attr_new;
|
2022-08-18 00:27:54 +02:00
|
|
|
tmp_pi->uptime = monotime(NULL);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-18 01:24:50 +02:00
|
|
|
/* local MAC-IP routes in the VNI table are linked to
|
|
|
|
* the destination ES
|
2020-05-09 04:36:47 +02:00
|
|
|
*/
|
|
|
|
if (route_change && vpn_rt
|
|
|
|
&& (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
|
|
|
|
bgp_evpn_path_es_link(tmp_pi, vpn->vni,
|
|
|
|
bgp_evpn_attr_get_esi(tmp_pi->attr));
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Return back the route entry. */
|
2018-10-03 02:43:07 +02:00
|
|
|
*pi = tmp_pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
return route_change;
|
|
|
|
}
|
|
|
|
|
2019-01-15 00:24:43 +01:00
|
|
|
static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgpevpn *vpn,
|
|
|
|
struct bgp_dest *dest)
|
2019-01-15 00:24:43 +01:00
|
|
|
{
|
|
|
|
struct bgp_path_info *tmp_ri;
|
|
|
|
struct bgp_path_info *curr_select = NULL;
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (tmp_ri = bgp_dest_get_bgp_path_info(dest); tmp_ri;
|
|
|
|
tmp_ri = tmp_ri->next) {
|
2019-01-15 00:24:43 +01:00
|
|
|
if (CHECK_FLAG(tmp_ri->flags, BGP_PATH_SELECTED)) {
|
|
|
|
curr_select = tmp_ri;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
|
2020-03-28 18:12:04 +01:00
|
|
|
&& (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
|
|
|
|
bgp_evpn_attr_is_sync(curr_select->attr)))
|
2024-02-15 20:23:51 +01:00
|
|
|
if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
(curr_select->sub_type == BGP_ROUTE_IMPORTED ||
|
|
|
|
bgp_evpn_attr_is_sync(curr_select->attr))) {
|
|
|
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
|
|
|
|
evpn_zebra_install(bgp, vpn,
|
|
|
|
(const struct prefix_evpn *)
|
|
|
|
bgp_dest_get_prefix(
|
|
|
|
dest),
|
|
|
|
curr_select);
|
|
|
|
else
|
|
|
|
bgp_zebra_route_install(dest, curr_select, bgp,
|
|
|
|
true, vpn, false);
|
|
|
|
}
|
2019-01-15 00:24:43 +01:00
|
|
|
}
|
|
|
|
|
2018-10-15 17:16:51 +02:00
|
|
|
/*
|
|
|
|
* If the local route was not selected evict it and tell zebra to re-add
|
|
|
|
* the best remote dest.
|
|
|
|
*
|
|
|
|
* Typically a local path added by zebra is expected to be selected as
|
|
|
|
* best. In which case when a remote path wins as best (later)
|
|
|
|
* evpn_route_select_install itself evicts the older-local-best path.
|
|
|
|
*
|
|
|
|
* However if bgp's add and zebra's add cross paths (race condition) it
|
|
|
|
* is possible that the local path is no longer the "older" best path.
|
|
|
|
* It is a path that was never designated as best and hence requires
|
|
|
|
* additional handling to prevent bgp from injecting and holding on to a
|
|
|
|
* non-best local path.
|
|
|
|
*/
|
2023-09-10 15:09:08 +02:00
|
|
|
static struct bgp_dest *
|
|
|
|
evpn_cleanup_local_non_best_route(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct bgp_dest *dest,
|
|
|
|
struct bgp_path_info *local_pi)
|
2018-10-15 17:16:51 +02:00
|
|
|
{
|
|
|
|
/* local path was not picked as the winner; kick it out */
|
2020-03-22 05:02:18 +01:00
|
|
|
if (bgp_debug_zebra(NULL))
|
2020-06-23 16:00:41 +02:00
|
|
|
zlog_debug("evicting local evpn prefix %pBD as remote won",
|
2020-03-27 00:11:58 +01:00
|
|
|
dest);
|
2020-03-22 05:02:18 +01:00
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
evpn_delete_old_local_route(bgp, vpn, dest, local_pi, NULL);
|
2018-10-15 17:16:51 +02:00
|
|
|
|
|
|
|
/* tell zebra to re-add the best remote path */
|
2020-03-27 00:11:58 +01:00
|
|
|
evpn_zebra_reinstall_best_route(bgp, vpn, dest);
|
2023-09-10 15:09:08 +02:00
|
|
|
|
|
|
|
return bgp_path_info_reap(dest, local_pi);
|
2018-10-15 17:16:51 +02:00
|
|
|
}
|
|
|
|
|
2020-08-15 00:48:34 +02:00
|
|
|
static inline bool bgp_evpn_route_add_l3_ecomm_ok(struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
esi_t *esi)
|
|
|
|
{
|
|
|
|
return p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
&& (is_evpn_prefix_ipaddr_v4(p)
|
2021-04-13 05:42:11 +02:00
|
|
|
|| (is_evpn_prefix_ipaddr_v6(p)
|
|
|
|
&& !IN6_IS_ADDR_LINKLOCAL(
|
|
|
|
&p->prefix.macip_addr.ip.ipaddr_v6)))
|
2020-08-15 00:48:34 +02:00
|
|
|
&& CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)
|
|
|
|
&& bgpevpn_get_l3vni(vpn) && bgp_evpn_es_add_l3_ecomm_ok(esi);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Create or update EVPN route (of type based on prefix) for specified VNI
|
|
|
|
* and schedule for processing.
|
|
|
|
*/
|
|
|
|
static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
struct prefix_evpn *p, uint8_t flags,
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
uint32_t seq, esi_t *esi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct attr attr;
|
|
|
|
struct attr *attr_new;
|
2018-02-28 03:07:23 +01:00
|
|
|
int add_l3_ecomm = 0;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
int route_change;
|
2020-03-28 18:12:04 +01:00
|
|
|
bool old_is_sync = false;
|
2021-10-26 23:55:54 +02:00
|
|
|
bool mac_only = false;
|
2023-05-08 04:51:28 +02:00
|
|
|
struct ecommunity *macvrf_soo = NULL;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&attr, 0, sizeof(attr));
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Build path-attribute for this route. */
|
2022-06-06 08:49:37 +02:00
|
|
|
bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_IGP);
|
2017-05-15 23:34:04 +02:00
|
|
|
attr.nexthop = vpn->originator_ip;
|
2017-06-06 19:20:38 +02:00
|
|
|
attr.mp_nexthop_global_in = vpn->originator_ip;
|
|
|
|
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY))
|
|
|
|
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY);
|
|
|
|
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
|
|
|
|
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
|
|
|
|
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
|
|
|
|
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
|
2020-03-28 18:12:04 +01:00
|
|
|
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
|
|
|
|
attr.es_flags |= ATTR_ES_PROXY_ADVERT;
|
|
|
|
|
|
|
|
if (esi && bgp_evpn_is_esi_valid(esi)) {
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
memcpy(&attr.esi, esi, sizeof(esi_t));
|
2020-03-28 18:12:04 +01:00
|
|
|
attr.es_flags |= ATTR_ES_IS_LOCAL;
|
|
|
|
}
|
|
|
|
|
2018-02-23 11:16:47 +01:00
|
|
|
/* PMSI is only needed for type-3 routes */
|
2019-02-12 21:51:49 +01:00
|
|
|
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
|
2018-02-23 11:16:47 +01:00
|
|
|
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
2020-11-02 16:52:40 +01:00
|
|
|
bgp_attr_set_pmsi_tnl_type(&attr, PMSI_TNLTYPE_INGR_REPL);
|
2019-02-12 21:51:49 +01:00
|
|
|
}
|
2018-02-23 11:16:47 +01:00
|
|
|
|
2022-07-08 06:09:56 +02:00
|
|
|
/* router mac is only needed for type-2 routes here. */
|
|
|
|
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
uint8_t af_flags = 0;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
|
|
|
|
SET_FLAG(af_flags, BGP_EVPN_MACIP_TYPE_SVI_IP);
|
|
|
|
|
|
|
|
bgp_evpn_get_rmac_nexthop(vpn, p, &attr, af_flags);
|
|
|
|
}
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
if (bgp_debug_zebra(NULL)) {
|
|
|
|
char buf3[ESI_STR_LEN];
|
|
|
|
|
2020-10-15 21:33:09 +02:00
|
|
|
zlog_debug(
|
2023-01-16 08:35:27 +01:00
|
|
|
"VRF %s vni %u type-%u route evp %pFX RMAC %pEA nexthop %pI4 esi %s",
|
2020-10-15 21:33:09 +02:00
|
|
|
vpn->bgp_vrf ? vrf_id_to_name(vpn->bgp_vrf->vrf_id)
|
2023-01-16 08:35:27 +01:00
|
|
|
: "None",
|
|
|
|
vpn->vni, p->prefix.route_type, p, &attr.rmac,
|
|
|
|
&attr.mp_nexthop_global_in,
|
2020-10-15 21:33:09 +02:00
|
|
|
esi_to_str(esi, buf3, sizeof(buf3)));
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
2019-08-09 03:58:03 +02:00
|
|
|
|
2018-01-04 12:34:24 +01:00
|
|
|
vni2label(vpn->vni, &(attr.label));
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* Include L3 VNI related RTs and RMAC for type-2 routes, if they're
|
|
|
|
* IPv4 or IPv6 global addresses and we're advertising L3VNI with
|
|
|
|
* these routes.
|
|
|
|
*/
|
2020-08-15 00:48:34 +02:00
|
|
|
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
|
|
|
|
vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
|
2018-02-28 03:07:23 +01:00
|
|
|
|
2023-05-08 04:51:28 +02:00
|
|
|
if (bgp->evpn_info)
|
|
|
|
macvrf_soo = bgp->evpn_info->soo;
|
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* Set up extended community. */
|
2023-05-08 04:51:28 +02:00
|
|
|
build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm, macvrf_soo);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/* First, create (or fetch) route node within the VNI.
|
|
|
|
* NOTE: There is no RD here.
|
|
|
|
*/
|
|
|
|
dest = bgp_evpn_vni_node_get(vpn, p, NULL);
|
|
|
|
|
|
|
|
if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
|
|
|
|
(is_evpn_prefix_ipaddr_none(p) == true))
|
|
|
|
mac_only = true;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Create or update route entry. */
|
2021-07-23 19:35:14 +02:00
|
|
|
route_change = update_evpn_route_entry(
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp, vpn, afi, safi, dest, &attr,
|
|
|
|
(mac_only ? NULL : &p->prefix.macip_addr.mac), NULL /* ip */, 1,
|
2021-07-23 19:35:14 +02:00
|
|
|
&pi, flags, seq, true /* setup_sync */, &old_is_sync);
|
2018-10-03 02:43:07 +02:00
|
|
|
assert(pi);
|
|
|
|
attr_new = pi->attr;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2018-10-15 17:16:51 +02:00
|
|
|
/* lock ri to prevent freeing in evpn_route_select_install */
|
|
|
|
bgp_path_info_lock(pi);
|
2019-11-25 23:34:29 +01:00
|
|
|
|
|
|
|
/* Perform route selection. Normally, the local route in the
|
|
|
|
* VNI is expected to win and be the best route. However, if
|
|
|
|
* there is a race condition where a host moved from local to
|
|
|
|
* remote and the remote route was received in BGP just prior
|
|
|
|
* to the local MACIP notification from zebra, the remote
|
|
|
|
* route would win, and we should evict the defunct local route
|
|
|
|
* and (re)install the remote route into zebra.
|
|
|
|
*/
|
2024-03-11 19:05:59 +01:00
|
|
|
evpn_route_select_install(bgp, vpn, dest, pi);
|
2018-10-15 17:16:51 +02:00
|
|
|
/*
|
2018-10-19 17:46:46 +02:00
|
|
|
* If the new local route was not selected evict it and tell zebra
|
|
|
|
* to re-add the best remote dest. BGP doesn't retain non-best local
|
|
|
|
* routes.
|
2018-10-15 17:16:51 +02:00
|
|
|
*/
|
2020-03-28 18:12:04 +01:00
|
|
|
if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
|
2018-10-19 17:46:46 +02:00
|
|
|
route_change = 0;
|
2020-03-28 18:12:04 +01:00
|
|
|
} else {
|
|
|
|
if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
|
|
|
|
route_change = 0;
|
2023-09-10 15:09:08 +02:00
|
|
|
dest = evpn_cleanup_local_non_best_route(bgp, vpn, dest,
|
|
|
|
pi);
|
2020-03-28 18:12:04 +01:00
|
|
|
} else {
|
|
|
|
bool new_is_sync;
|
|
|
|
|
|
|
|
/* If the local path already existed and is still the
|
|
|
|
* best path we need to also check if it transitioned
|
|
|
|
* from being a sync path to a non-sync path. If it
|
|
|
|
* it did we need to notify zebra that the sync-path
|
|
|
|
* has been removed.
|
|
|
|
*/
|
|
|
|
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
|
2024-02-15 20:23:51 +01:00
|
|
|
if (!new_is_sync && old_is_sync) {
|
|
|
|
if (CHECK_FLAG(bgp->flags,
|
|
|
|
BGP_FLAG_DELETE_IN_PROGRESS))
|
|
|
|
evpn_zebra_uninstall(bgp, vpn, p, pi,
|
|
|
|
true);
|
|
|
|
else
|
|
|
|
bgp_zebra_route_install(dest, pi, bgp,
|
|
|
|
false, vpn,
|
|
|
|
true);
|
|
|
|
}
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
2018-10-19 17:46:46 +02:00
|
|
|
}
|
2018-10-15 17:16:51 +02:00
|
|
|
bgp_path_info_unlock(pi);
|
|
|
|
|
2023-09-10 15:09:08 +02:00
|
|
|
if (dest)
|
|
|
|
bgp_dest_unlock_node(dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* If this is a new route or some attribute has changed, export the
|
|
|
|
* route to the global table. The route will be advertised to peers
|
|
|
|
* from there. Note that this table is a 2-level tree (RD-level +
|
|
|
|
* Prefix-level) similar to L3VPN routes.
|
|
|
|
*/
|
|
|
|
if (route_change) {
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *global_pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
|
|
|
|
p, &vpn->prd, NULL);
|
2021-10-26 23:55:54 +02:00
|
|
|
update_evpn_route_entry(
|
|
|
|
bgp, vpn, afi, safi, dest, attr_new, NULL /* mac */,
|
|
|
|
NULL /* ip */, 1, &global_pi, flags, seq,
|
|
|
|
false /* setup_sync */, NULL /* old_is_sync */);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Schedule for processing and unlock node. */
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, dest, global_pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Unintern temporary. */
|
|
|
|
aspath_unintern(&attr.aspath);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/*
|
|
|
|
* Delete EVPN route entry.
|
|
|
|
* The entry can be in ESI/VNI table or the global table.
|
|
|
|
*/
|
2020-03-27 14:39:51 +01:00
|
|
|
void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi,
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info **pi)
|
2017-10-27 23:15:45 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *tmp_pi;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
*pi = NULL;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/* Now, find matching route. */
|
2020-03-27 00:11:58 +01:00
|
|
|
for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
|
2018-07-30 17:40:02 +02:00
|
|
|
tmp_pi = tmp_pi->next)
|
2018-10-03 02:43:07 +02:00
|
|
|
if (tmp_pi->peer == bgp->peer_self
|
|
|
|
&& tmp_pi->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& tmp_pi->sub_type == BGP_ROUTE_STATIC)
|
2017-10-27 23:15:45 +02:00
|
|
|
break;
|
|
|
|
|
2018-10-03 02:43:07 +02:00
|
|
|
*pi = tmp_pi;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* Mark route for delete. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (tmp_pi)
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_delete(dest, tmp_pi);
|
2017-10-27 23:15:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete EVPN type5 route */
|
|
|
|
static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp)
|
|
|
|
{
|
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest = NULL;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi = NULL;
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL; /* evpn bgp instance */
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
2018-01-05 21:41:25 +01:00
|
|
|
return 0;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
|
|
|
/* locate the global route entry for this type-5 prefix */
|
2023-03-14 11:05:58 +01:00
|
|
|
dest = bgp_evpn_global_node_lookup(bgp_evpn->rib[afi][safi], safi, evp,
|
|
|
|
&bgp_vrf->vrf_prd, NULL);
|
2020-03-27 00:11:58 +01:00
|
|
|
if (!dest)
|
2017-10-27 23:15:45 +02:00
|
|
|
return 0;
|
|
|
|
|
bgpd: lttng tp add evpn route events
Ticket:#3597393
Testing Done:
2023-09-08T22:53:03.532 frr_bgp:evpn_withdraw_type5 {'vrf_id': 42, 'ip':
'53.1.1.0'}
2023-09-08T22:53:06.207 frr_bgp:evpn_advertise_type5 {'vrf_id': 42,
'ip': '53.1.1.0', 'rmac': '00:02:00:00:00:38', 'vtep': '27.0.0.15'}
2023-09-08T21:51:15.637 frr_bgp:evpn_mh_local_ead_es_evi_route_upd
{'esi': '03:44:38:39:ff:ff:01:00:00:03', 'vni': 1000, 'route_type': 1,
'vtep': '27.0.0.15'}
2023-09-08T20:45:17.059 frr_bgp:evpn_mh_local_ead_es_evi_route_del
{'esi': '03:44:38:39:ff:ff:01:00:00:01', 'vni': 0, 'route_type': 4,
'vtep': '27.0.0.15'}
2023-09-08T21:51:18.363 frr_bgp:evpn_mh_es_evi_vtep_add {'esi':
'03:44:38:39:ff:ff:01:00:00:02', 'vni': 1000, 'vtep': '27.0.0.16',
'ead_es': 1}
2023-09-08T20:43:50.206 frr_bgp:evpn_mh_es_evi_vtep_del {'esi':
'03:44:38:39:ff:ff:01:00:00:01', 'vni': 1002, 'vtep': '27.0.0.16',
'ead_es': 0}
Signed-off-by: Chirag Shah <chirag@nvidia.com>
2023-09-08 00:51:32 +02:00
|
|
|
frrtrace(2, frr_bgp, evpn_withdraw_type5, bgp_vrf->vrf_id, evp);
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
delete_evpn_route_entry(bgp_evpn, afi, safi, dest, &pi);
|
2018-10-03 02:43:07 +02:00
|
|
|
if (pi)
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp_evpn, dest, pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2017-10-27 23:15:45 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Delete EVPN route (of type based on prefix) for specified VNI and
|
|
|
|
* schedule for processing.
|
|
|
|
*/
|
|
|
|
static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct prefix_evpn *p)
|
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest, *global_dest;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* First, locate the route node within the VNI. If it doesn't exist,
|
|
|
|
* there
|
|
|
|
* is nothing further to do.
|
2021-10-26 23:55:54 +02:00
|
|
|
* NOTE: There is no RD here.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
dest = bgp_evpn_vni_node_lookup(vpn, p, NULL);
|
2020-03-27 00:11:58 +01:00
|
|
|
if (!dest)
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Next, locate route node in the global EVPN routing table. Note that
|
|
|
|
* this table is a 2-level tree (RD-level + Prefix-level) similar to
|
|
|
|
* L3VPN routes.
|
|
|
|
*/
|
2023-03-14 11:05:58 +01:00
|
|
|
global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], safi, p,
|
|
|
|
&vpn->prd, NULL);
|
2020-03-27 00:11:58 +01:00
|
|
|
if (global_dest) {
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Delete route entry in the global EVPN table. */
|
2020-03-27 00:11:58 +01:00
|
|
|
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Schedule for processing - withdraws to peers happen from
|
|
|
|
* this table.
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (pi)
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, global_dest, pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(global_dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Delete route entry in the VNI route table. This can just be removed.
|
|
|
|
*/
|
2020-03-27 00:11:58 +01:00
|
|
|
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
|
2018-10-12 17:43:19 +02:00
|
|
|
if (pi) {
|
2024-03-20 15:13:00 +01:00
|
|
|
bgp_path_info_delete(dest, pi);
|
2024-03-11 19:05:59 +01:00
|
|
|
evpn_route_select_install(bgp, vpn, dest, pi);
|
2018-10-12 17:43:19 +02:00
|
|
|
}
|
2023-09-10 15:12:26 +02:00
|
|
|
|
|
|
|
/* dest should still exist due to locking make coverity happy */
|
|
|
|
assert(dest);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:48:34 +02:00
|
|
|
void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct bgp_dest *dest,
|
|
|
|
struct bgp_path_info *local_pi,
|
|
|
|
const char *caller)
|
2020-03-28 18:12:04 +01:00
|
|
|
{
|
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
struct bgp_path_info *pi;
|
|
|
|
struct attr attr;
|
|
|
|
struct attr *attr_new;
|
|
|
|
uint32_t seq;
|
|
|
|
int add_l3_ecomm = 0;
|
2020-10-14 17:19:45 +02:00
|
|
|
struct bgp_dest *global_dest;
|
2020-03-28 18:12:04 +01:00
|
|
|
struct bgp_path_info *global_pi;
|
2021-07-23 19:35:14 +02:00
|
|
|
struct prefix_evpn evp;
|
2020-03-28 18:12:04 +01:00
|
|
|
int route_change;
|
|
|
|
bool old_is_sync = false;
|
2023-05-08 04:51:28 +02:00
|
|
|
struct ecommunity *macvrf_soo = NULL;
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
if (CHECK_FLAG(local_pi->flags, BGP_PATH_REMOVED))
|
|
|
|
return;
|
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
/*
|
|
|
|
* VNI table MAC-IP prefixes don't have MAC so make sure it's set from
|
|
|
|
* path info here.
|
|
|
|
*/
|
2023-07-31 14:34:48 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->rn->p)) {
|
2021-10-26 23:55:54 +02:00
|
|
|
/* VNI MAC -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
2023-07-31 14:34:48 +02:00
|
|
|
&evp, (struct prefix_evpn *)&dest->rn->p, NULL /* mac */,
|
2021-10-26 23:55:54 +02:00
|
|
|
evpn_type2_path_info_get_ip(local_pi));
|
|
|
|
} else {
|
|
|
|
/* VNI IP -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
2023-07-31 14:34:48 +02:00
|
|
|
&evp, (struct prefix_evpn *)&dest->rn->p,
|
2021-10-26 23:55:54 +02:00
|
|
|
evpn_type2_path_info_get_mac(local_pi), NULL /* ip */);
|
|
|
|
}
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
/*
|
|
|
|
* Build attribute per local route as the MAC mobility and
|
|
|
|
* some other values could differ for different routes. The
|
|
|
|
* attributes will be shared in the hash table.
|
|
|
|
*/
|
2022-06-06 08:49:37 +02:00
|
|
|
bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_IGP);
|
2020-03-28 18:12:04 +01:00
|
|
|
attr.nexthop = vpn->originator_ip;
|
|
|
|
attr.mp_nexthop_global_in = vpn->originator_ip;
|
|
|
|
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
2024-07-02 18:31:14 +02:00
|
|
|
attr.evpn_flags = local_pi->attr->evpn_flags;
|
2020-03-28 18:12:04 +01:00
|
|
|
attr.es_flags = local_pi->attr->es_flags;
|
2024-07-02 18:31:14 +02:00
|
|
|
if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
|
|
|
|
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
|
2021-07-23 19:35:14 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_v6(&evp))
|
2024-07-02 18:31:14 +02:00
|
|
|
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
|
|
|
memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t));
|
2023-08-08 12:47:29 +02:00
|
|
|
bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr,
|
|
|
|
local_pi->extra->evpn->af_flags);
|
2020-03-28 18:12:04 +01:00
|
|
|
vni2label(vpn->vni, &(attr.label));
|
|
|
|
/* Add L3 VNI RTs and RMAC for non IPv6 link-local if
|
|
|
|
* using L3 VNI for type-2 routes also.
|
|
|
|
*/
|
2020-08-15 00:48:34 +02:00
|
|
|
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
|
2021-07-23 19:35:14 +02:00
|
|
|
vpn, &evp,
|
2020-08-15 00:48:34 +02:00
|
|
|
(attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
2023-05-08 04:51:28 +02:00
|
|
|
if (bgp->evpn_info)
|
|
|
|
macvrf_soo = bgp->evpn_info->soo;
|
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
/* Set up extended community. */
|
2023-05-08 04:51:28 +02:00
|
|
|
build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm, macvrf_soo);
|
2020-03-28 18:12:04 +01:00
|
|
|
seq = mac_mobility_seqnum(local_pi->attr);
|
|
|
|
|
|
|
|
if (bgp_debug_zebra(NULL)) {
|
|
|
|
char buf3[ESI_STR_LEN];
|
|
|
|
|
2020-10-15 21:33:09 +02:00
|
|
|
zlog_debug(
|
2021-03-10 01:50:42 +01:00
|
|
|
"VRF %s vni %u evp %pFX RMAC %pEA nexthop %pI4 esi %s esf 0x%x from %s",
|
2020-10-15 21:33:09 +02:00
|
|
|
vpn->bgp_vrf ? vrf_id_to_name(vpn->bgp_vrf->vrf_id)
|
|
|
|
: " ",
|
2021-07-23 19:35:14 +02:00
|
|
|
vpn->vni, &evp, &attr.rmac, &attr.mp_nexthop_global_in,
|
2020-10-15 21:33:09 +02:00
|
|
|
esi_to_str(&attr.esi, buf3, sizeof(buf3)),
|
|
|
|
attr.es_flags, caller);
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the route entry. */
|
2020-10-14 17:19:45 +02:00
|
|
|
route_change = update_evpn_route_entry(
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, NULL /* ip */,
|
|
|
|
0, &pi, 0, seq, true /* setup_sync */, &old_is_sync);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
assert(pi);
|
|
|
|
attr_new = pi->attr;
|
|
|
|
/* lock ri to prevent freeing in evpn_route_select_install */
|
|
|
|
bgp_path_info_lock(pi);
|
|
|
|
|
|
|
|
/* Perform route selection. Normally, the local route in the
|
|
|
|
* VNI is expected to win and be the best route. However,
|
|
|
|
* under peculiar situations (e.g., tunnel (next hop) IP change
|
|
|
|
* that causes best selection to be based on next hop), a
|
|
|
|
* remote route could win. If the local route is the best,
|
|
|
|
* ensure it is updated in the global EVPN route table and
|
|
|
|
* advertised to peers; otherwise, ensure it is evicted and
|
|
|
|
* (re)install the remote route into zebra.
|
|
|
|
*/
|
2024-03-11 19:05:59 +01:00
|
|
|
evpn_route_select_install(bgp, vpn, dest, pi);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
|
|
|
|
route_change = 0;
|
|
|
|
} else {
|
|
|
|
if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
|
|
|
|
route_change = 0;
|
2020-10-14 17:19:45 +02:00
|
|
|
evpn_cleanup_local_non_best_route(bgp, vpn, dest, pi);
|
2020-03-28 18:12:04 +01:00
|
|
|
} else {
|
|
|
|
bool new_is_sync;
|
|
|
|
|
|
|
|
/* If the local path already existed and is still the
|
|
|
|
* best path we need to also check if it transitioned
|
|
|
|
* from being a sync path to a non-sync path. If it
|
|
|
|
* it did we need to notify zebra that the sync-path
|
|
|
|
* has been removed.
|
|
|
|
*/
|
|
|
|
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
|
2024-02-15 20:23:51 +01:00
|
|
|
if (!new_is_sync && old_is_sync) {
|
|
|
|
if (CHECK_FLAG(bgp->flags,
|
|
|
|
BGP_FLAG_DELETE_IN_PROGRESS))
|
|
|
|
(void)evpn_zebra_uninstall(bgp, vpn,
|
|
|
|
&evp, pi,
|
|
|
|
true);
|
|
|
|
else
|
|
|
|
bgp_zebra_route_install(dest, pi, bgp,
|
|
|
|
false, vpn,
|
|
|
|
true);
|
|
|
|
}
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* unlock pi */
|
|
|
|
bgp_path_info_unlock(pi);
|
|
|
|
|
|
|
|
if (route_change) {
|
|
|
|
/* Update route in global routing table. */
|
2021-07-23 19:35:14 +02:00
|
|
|
global_dest = bgp_evpn_global_node_get(
|
|
|
|
bgp->rib[afi][safi], afi, safi, &evp, &vpn->prd, NULL);
|
2020-10-14 17:19:45 +02:00
|
|
|
assert(global_dest);
|
|
|
|
update_evpn_route_entry(
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp, vpn, afi, safi, global_dest, attr_new,
|
|
|
|
NULL /* mac */, NULL /* ip */, 0, &global_pi, 0,
|
|
|
|
mac_mobility_seqnum(attr_new), false /* setup_sync */,
|
|
|
|
NULL /* old_is_sync */);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
|
|
|
/* Schedule for processing and unlock node. */
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, global_dest, global_pi, afi, safi);
|
2020-10-14 17:19:45 +02:00
|
|
|
bgp_dest_unlock_node(global_dest);
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Unintern temporary. */
|
|
|
|
aspath_unintern(&attr.aspath);
|
|
|
|
}
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
static void update_type2_route(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct bgp_dest *dest)
|
|
|
|
{
|
|
|
|
struct bgp_path_info *tmp_pi;
|
|
|
|
|
|
|
|
const struct prefix_evpn *evp =
|
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
|
|
|
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Identify local route. */
|
|
|
|
for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
|
|
|
|
tmp_pi = tmp_pi->next) {
|
|
|
|
if (tmp_pi->peer == bgp->peer_self &&
|
|
|
|
tmp_pi->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
tmp_pi->sub_type == BGP_ROUTE_STATIC)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tmp_pi)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi, __func__);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Update all type-2 (MACIP) local routes for this VNI - these should also
|
|
|
|
* be scheduled for advertise to peers.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
static void update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/* Walk this VNI's route MAC & IP table and update local type-2
|
|
|
|
* routes. For any routes updated, update corresponding entry in the
|
|
|
|
* global table too.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
for (dest = bgp_table_top(vpn->mac_table); dest;
|
|
|
|
dest = bgp_route_next(dest))
|
|
|
|
update_type2_route(bgp, vpn, dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
for (dest = bgp_table_top(vpn->ip_table); dest;
|
|
|
|
dest = bgp_route_next(dest))
|
|
|
|
update_type2_route(bgp, vpn, dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all type-2 (MACIP) local routes for this VNI - only from the
|
|
|
|
* global routing table. These are also scheduled for withdraw from peers.
|
|
|
|
*/
|
2022-04-26 06:14:34 +02:00
|
|
|
static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *rddest, *dest;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct bgp_table *table;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
afi = AFI_L2VPN;
|
|
|
|
safi = SAFI_EVPN;
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
rddest = bgp_node_lookup(bgp->rib[afi][safi],
|
|
|
|
(struct prefix *)&vpn->prd);
|
2022-04-26 06:14:34 +02:00
|
|
|
if (rddest) {
|
2020-03-27 00:11:58 +01:00
|
|
|
table = bgp_dest_get_bgp_table_info(rddest);
|
|
|
|
for (dest = bgp_table_top(table); dest;
|
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
const struct prefix_evpn *evp =
|
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(
|
|
|
|
dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
continue;
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
|
2018-10-03 02:43:07 +02:00
|
|
|
if (pi)
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, dest, pi, afi, safi);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2022-04-26 06:14:34 +02:00
|
|
|
/* Unlock RD node. */
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(rddest);
|
2022-04-26 06:14:34 +02:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2023-09-10 15:15:41 +02:00
|
|
|
static struct bgp_dest *delete_vni_type2_route(struct bgp *bgp,
|
|
|
|
struct bgp_dest *dest)
|
2021-10-26 23:55:54 +02:00
|
|
|
{
|
|
|
|
struct bgp_path_info *pi;
|
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
|
|
|
|
const struct prefix_evpn *evp =
|
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
|
|
|
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
2023-09-10 15:15:41 +02:00
|
|
|
return dest;
|
2021-10-26 23:55:54 +02:00
|
|
|
|
|
|
|
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
|
|
|
|
|
|
|
|
/* Route entry in local table gets deleted immediately. */
|
|
|
|
if (pi)
|
2023-09-10 15:15:41 +02:00
|
|
|
dest = bgp_path_info_reap(dest, pi);
|
|
|
|
|
|
|
|
return dest;
|
2021-10-26 23:55:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
|
|
|
|
/* Next, walk this VNI's MAC & IP route table and delete local type-2
|
|
|
|
* routes.
|
|
|
|
*/
|
|
|
|
for (dest = bgp_table_top(vpn->mac_table); dest;
|
2023-09-10 15:15:41 +02:00
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
dest = delete_vni_type2_route(bgp, dest);
|
|
|
|
assert(dest);
|
|
|
|
}
|
2021-10-26 23:55:54 +02:00
|
|
|
|
|
|
|
for (dest = bgp_table_top(vpn->ip_table); dest;
|
2023-09-10 15:15:41 +02:00
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
dest = delete_vni_type2_route(bgp, dest);
|
|
|
|
assert(dest);
|
|
|
|
}
|
2021-10-26 23:55:54 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Delete all type-2 (MACIP) local routes for this VNI - from the global
|
|
|
|
* table as well as the per-VNI route table.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
static void delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
/* First, walk the global route table for this VNI's type-2 local
|
|
|
|
* routes.
|
|
|
|
* EVPN routes are a 2-level table, first get the RD table.
|
|
|
|
*/
|
|
|
|
delete_global_type2_routes(bgp, vpn);
|
2021-10-26 23:55:54 +02:00
|
|
|
delete_vni_type2_routes(bgp, vpn);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all routes in the per-VNI route table.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi, *nextpi;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/* Walk this VNI's MAC & IP route table and delete all routes. */
|
|
|
|
for (dest = bgp_table_top(vpn->mac_table); dest;
|
2020-03-27 00:11:58 +01:00
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest);
|
2018-07-30 17:40:02 +02:00
|
|
|
(pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
bgp_evpn_remote_ip_hash_del(vpn, pi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_delete(dest, pi);
|
2023-09-10 15:32:29 +02:00
|
|
|
dest = bgp_path_info_reap(dest, pi);
|
|
|
|
|
|
|
|
assert(dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
for (dest = bgp_table_top(vpn->ip_table); dest;
|
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest);
|
|
|
|
(pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
|
|
|
|
bgp_path_info_delete(dest, pi);
|
2023-09-10 15:32:29 +02:00
|
|
|
dest = bgp_path_info_reap(dest, pi);
|
|
|
|
|
|
|
|
assert(dest);
|
2021-10-26 23:55:54 +02:00
|
|
|
}
|
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2019-03-26 21:26:33 +01:00
|
|
|
/* BUM traffic flood mode per-l2-vni */
|
|
|
|
static int bgp_evpn_vni_flood_mode_get(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
/* if flooding has been globally disabled per-vni mode is
|
|
|
|
* not relevant
|
|
|
|
*/
|
|
|
|
if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_DISABLED)
|
|
|
|
return VXLAN_FLOOD_DISABLED;
|
|
|
|
|
|
|
|
/* if mcast group ip has been specified we use a PIM-SM MDT */
|
|
|
|
if (vpn->mcast_grp.s_addr != INADDR_ANY)
|
|
|
|
return VXLAN_FLOOD_PIM_SM;
|
|
|
|
|
|
|
|
/* default is ingress replication */
|
|
|
|
return VXLAN_FLOOD_HEAD_END_REPL;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Update (and advertise) local routes for a VNI. Invoked upon the VNI
|
|
|
|
* export RT getting modified or change to tunnel IP. Note that these
|
|
|
|
* situations need the route in the per-VNI table as well as the global
|
|
|
|
* table to be updated (as attributes change).
|
|
|
|
*/
|
2019-08-09 03:58:03 +02:00
|
|
|
int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct prefix_evpn p;
|
|
|
|
|
2021-03-19 02:34:45 +01:00
|
|
|
update_type1_routes_for_evi(bgp, vpn);
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Update and advertise the type-3 route (only one) followed by the
|
|
|
|
* locally learnt type-2 routes (MACIP) - for this VNI.
|
2018-10-05 01:20:12 +02:00
|
|
|
*
|
|
|
|
* RT-3 only if doing head-end replication
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2019-03-26 21:26:33 +01:00
|
|
|
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
|
|
|
|
== VXLAN_FLOOD_HEAD_END_REPL) {
|
2018-10-05 01:20:12 +02:00
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
ret = update_evpn_route(bgp, vpn, &p, 0, 0, NULL);
|
2018-10-05 01:20:12 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
update_all_type2_routes(bgp, vpn);
|
|
|
|
return 0;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* Update Type-2/3 Routes for L2VNI.
|
|
|
|
* Called by hash_iterate()
|
|
|
|
*/
|
|
|
|
static void update_routes_for_vni_hash(struct hash_bucket *bucket,
|
|
|
|
struct bgp *bgp)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
|
|
|
|
if (!bucket)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vpn = (struct bgpevpn *)bucket->data;
|
|
|
|
update_routes_for_vni(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Delete (and withdraw) local routes for specified VNI from the global
|
|
|
|
* table and per-VNI table. After this, remove all other routes from
|
|
|
|
* the per-VNI table. Invoked upon the VNI being deleted or EVPN
|
|
|
|
* (advertise-all-vni) being disabled.
|
|
|
|
*/
|
|
|
|
static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct prefix_evpn p;
|
|
|
|
|
|
|
|
/* Delete and withdraw locally learnt type-2 routes (MACIP)
|
|
|
|
* followed by type-3 routes (only one) - for this VNI.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
delete_all_type2_routes(bgp, vpn);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
2024-02-15 20:23:51 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* To handle the following scenario:
|
|
|
|
* - Say, the new zebra announce fifo list has few vni Evpn prefixes yet
|
|
|
|
* to be sent to zebra.
|
|
|
|
* - At this point if we have triggers like "no advertise-all-vni" or
|
|
|
|
* "networking restart", where a vni is going down.
|
|
|
|
*
|
|
|
|
* Perform the below
|
|
|
|
* 1) send withdraw routes to zebra immediately in case it is installed.
|
|
|
|
* 2) before we blow up the vni table, we need to walk the list and
|
|
|
|
* pop all the dest whose za_vpn points to this vni.
|
|
|
|
*/
|
|
|
|
SET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN);
|
2017-05-15 23:34:04 +02:00
|
|
|
ret = delete_evpn_route(bgp, vpn, &p);
|
2024-02-15 20:23:51 +01:00
|
|
|
UNSET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN);
|
2017-05-15 23:34:04 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Delete all routes from the per-VNI table. */
|
2021-10-26 23:55:54 +02:00
|
|
|
delete_all_vni_routes(bgp, vpn);
|
|
|
|
return 0;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2019-03-19 19:08:24 +01:00
|
|
|
/*
|
|
|
|
* There is a flood mcast IP address change. Update the mcast-grp and
|
|
|
|
* remove the type-3 route if any. A new type-3 route will be generated
|
|
|
|
* post tunnel_ip update if the new flood mode is head-end-replication.
|
|
|
|
*/
|
|
|
|
static int bgp_evpn_mcast_grp_change(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct in_addr mcast_grp)
|
|
|
|
{
|
|
|
|
struct prefix_evpn p;
|
|
|
|
|
|
|
|
vpn->mcast_grp = mcast_grp;
|
|
|
|
|
|
|
|
if (is_vni_live(vpn)) {
|
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
|
|
|
delete_evpn_route(bgp, vpn, &p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
2023-05-08 05:26:25 +02:00
|
|
|
* If there is a tunnel endpoint IP address (VTEP-IP) change for this VNI.
|
|
|
|
- Deletes tip_hash entry for old VTEP-IP
|
|
|
|
- Adds tip_hash entry/refcount for new VTEP-IP
|
|
|
|
- Deletes prior type-3 route for L2VNI (if needed)
|
|
|
|
- Updates originator_ip
|
2018-01-25 07:41:44 +01:00
|
|
|
* Note: Route re-advertisement happens elsewhere after other processing
|
|
|
|
* other changes.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2023-05-08 05:26:25 +02:00
|
|
|
static void handle_tunnel_ip_change(struct bgp *bgp_vrf, struct bgp *bgp_evpn,
|
|
|
|
struct bgpevpn *vpn,
|
2023-01-25 19:25:20 +01:00
|
|
|
struct in_addr originator_ip)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn p;
|
2023-05-08 05:26:25 +02:00
|
|
|
struct in_addr old_vtep_ip;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2023-05-08 05:26:25 +02:00
|
|
|
if (bgp_vrf) /* L3VNI */
|
|
|
|
old_vtep_ip = bgp_vrf->originator_ip;
|
|
|
|
else /* L2VNI */
|
|
|
|
old_vtep_ip = vpn->originator_ip;
|
|
|
|
|
|
|
|
/* TIP didn't change, nothing to do */
|
|
|
|
if (IPV4_ADDR_SAME(&old_vtep_ip, &originator_ip))
|
2023-01-25 19:25:20 +01:00
|
|
|
return;
|
|
|
|
|
2023-05-08 05:26:25 +02:00
|
|
|
/* If L2VNI is not live, we only need to update the originator_ip.
|
|
|
|
* L3VNIs are updated immediately, so we can't bail out early.
|
|
|
|
*/
|
|
|
|
if (!bgp_vrf && !is_vni_live(vpn)) {
|
2017-07-07 01:33:50 +02:00
|
|
|
vpn->originator_ip = originator_ip;
|
2023-01-25 19:25:20 +01:00
|
|
|
return;
|
2017-07-07 01:33:50 +02:00
|
|
|
}
|
|
|
|
|
2017-08-17 08:19:58 +02:00
|
|
|
/* Update the tunnel-ip hash */
|
2023-05-08 05:26:25 +02:00
|
|
|
bgp_tip_del(bgp_evpn, &old_vtep_ip);
|
|
|
|
if (bgp_tip_add(bgp_evpn, &originator_ip))
|
2023-01-25 19:07:43 +01:00
|
|
|
/* The originator_ip was not already present in the
|
|
|
|
* bgp martian next-hop table as a tunnel-ip, so we
|
|
|
|
* need to go back and filter routes matching the new
|
|
|
|
* martian next-hop.
|
|
|
|
*/
|
2023-03-27 21:49:41 +02:00
|
|
|
bgp_filter_evpn_routes_upon_martian_change(bgp_evpn,
|
|
|
|
BGP_MARTIAN_TUN_IP);
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2023-05-08 05:26:25 +02:00
|
|
|
if (!bgp_vrf) {
|
|
|
|
/* Need to withdraw type-3 route as the originator IP is part
|
|
|
|
* of the key.
|
|
|
|
*/
|
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
|
|
|
delete_evpn_route(bgp_evpn, vpn, &p);
|
|
|
|
|
|
|
|
vpn->originator_ip = originator_ip;
|
|
|
|
} else
|
|
|
|
bgp_vrf->originator_ip = originator_ip;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2023-01-25 19:25:20 +01:00
|
|
|
return;
|
2020-03-27 14:39:51 +01:00
|
|
|
}
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-03-27 14:39:51 +01:00
|
|
|
static struct bgp_path_info *
|
|
|
|
bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
|
|
|
|
struct bgp_dest *dest, struct attr *attr)
|
|
|
|
{
|
|
|
|
struct attr *attr_new;
|
|
|
|
struct bgp_path_info *pi;
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-03-27 14:39:51 +01:00
|
|
|
/* Add (or update) attribute to hash. */
|
|
|
|
attr_new = bgp_attr_intern(attr);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-03-27 14:39:51 +01:00
|
|
|
/* Create new route with its attribute. */
|
|
|
|
pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0, parent_pi->peer,
|
|
|
|
attr_new, dest);
|
|
|
|
SET_FLAG(pi->flags, BGP_PATH_VALID);
|
|
|
|
bgp_path_info_extra_get(pi);
|
2023-08-08 12:47:29 +02:00
|
|
|
if (!pi->extra->vrfleak)
|
|
|
|
pi->extra->vrfleak =
|
|
|
|
XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK,
|
|
|
|
sizeof(struct bgp_path_info_extra_vrfleak));
|
|
|
|
pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi);
|
2020-03-27 14:39:51 +01:00
|
|
|
bgp_dest_lock_node((struct bgp_dest *)parent_pi->net);
|
2024-02-26 18:23:11 +01:00
|
|
|
if (parent_pi->extra)
|
bgpd: imported evpn rt5 routes copy igpmetric
when doing BGP over an IGP platform, the expectation is that
the path calculation for a given prefix takes into account the
igpmetric given by IGP.
This is true with prefixes obtained in a given BGP instance where
peering occurs. For instance, ipv4 unicast entries or l2vpn evpn
entries work this way. The igpmetric is obtained through nexthop
tracking, like below:
south-vm# show bgp nexthop
Current BGP nexthop cache:
1.1.1.1 valid [IGP metric 10], #paths 1, peer 1.1.1.1
2.2.2.2 valid [IGP metric 20], #paths 1, peer 2.2.2.2
The igp metric is taken into account when doing best path
selection, and only the entry with lowest igp wins.
[..]
*>i[5]:[0]:[32]:[5.5.5.5]
1.1.1.1 0 100 0 ?
RT:65400:268435556 ET:8 Rmac:2e:22:6c:67:bb:73
* i 2.2.2.2 0 100 0 ?
RT:65400:268435556 ET:8 Rmac:f2:d3:68:4e:f4:ed
however, for imported EVPN RT5 entries, the igpmetric was not
copied from the parent path info. Fix it. In this way, the
imported route entries use the igpmetric of the parent pi.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2021-08-17 16:43:37 +02:00
|
|
|
pi->extra->igpmetric = parent_pi->extra->igpmetric;
|
2024-02-26 18:23:11 +01:00
|
|
|
|
|
|
|
if (bgp_path_info_num_labels(parent_pi))
|
|
|
|
pi->extra->labels = bgp_labels_intern(parent_pi->extra->labels);
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2020-03-27 14:39:51 +01:00
|
|
|
bgp_path_info_add(dest, pi);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-03-27 14:39:51 +01:00
|
|
|
return pi;
|
2018-04-14 00:01:12 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/*
|
|
|
|
* Install route entry into the VRF routing table and invoke route selection.
|
|
|
|
*/
|
|
|
|
static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
2020-03-22 19:50:46 +01:00
|
|
|
const struct prefix_evpn *evp,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *parent_pi)
|
2017-10-11 10:32:54 +02:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2018-02-28 03:07:23 +01:00
|
|
|
struct attr attr;
|
2017-10-11 10:32:54 +02:00
|
|
|
struct attr *attr_new;
|
2017-11-13 19:57:52 +01:00
|
|
|
int ret = 0;
|
2017-10-11 10:32:54 +02:00
|
|
|
struct prefix p;
|
|
|
|
struct prefix *pp = &p;
|
|
|
|
afi_t afi = 0;
|
|
|
|
safi_t safi = 0;
|
2020-05-25 23:06:10 +02:00
|
|
|
bool new_pi = false;
|
2020-08-18 01:24:50 +02:00
|
|
|
bool use_l3nhg = false;
|
|
|
|
bool is_l3nhg_active = false;
|
2021-01-11 07:32:41 +01:00
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
memset(pp, 0, sizeof(struct prefix));
|
2018-04-14 00:37:30 +02:00
|
|
|
ip_prefix_from_evpn_prefix(evp, pp);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2020-10-18 13:33:54 +02:00
|
|
|
if (bgp_debug_zebra(NULL))
|
2017-10-14 11:56:37 +02:00
|
|
|
zlog_debug(
|
2020-10-18 13:33:54 +02:00
|
|
|
"vrf %s: import evpn prefix %pFX parent %p flags 0x%x",
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi,
|
|
|
|
parent_pi->flags);
|
2017-10-14 11:56:37 +02:00
|
|
|
|
2024-05-22 10:41:52 +02:00
|
|
|
if (bgp_vrf->vrf_id == VRF_UNKNOWN)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Create (or fetch) route within the VRF. */
|
|
|
|
/* NOTE: There is no RD here. */
|
2018-04-14 00:37:30 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_v4(evp)) {
|
2017-10-11 10:32:54 +02:00
|
|
|
afi = AFI_IP;
|
|
|
|
safi = SAFI_UNICAST;
|
2020-03-27 00:11:58 +01:00
|
|
|
dest = bgp_node_get(bgp_vrf->rib[afi][safi], pp);
|
2018-04-14 00:37:30 +02:00
|
|
|
} else if (is_evpn_prefix_ipaddr_v6(evp)) {
|
2017-10-11 10:32:54 +02:00
|
|
|
afi = AFI_IP6;
|
|
|
|
safi = SAFI_UNICAST;
|
2020-03-27 00:11:58 +01:00
|
|
|
dest = bgp_node_get(bgp_vrf->rib[afi][safi], pp);
|
2017-10-11 10:32:54 +02:00
|
|
|
} else
|
|
|
|
return 0;
|
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
/* EVPN routes currently only support a IPv4 next hop which corresponds
|
|
|
|
* to the remote VTEP. When importing into a VRF, if it is IPv6 host
|
2018-05-07 21:04:26 +02:00
|
|
|
* or prefix route, we have to convert the next hop to an IPv4-mapped
|
|
|
|
* address for the rest of the code to flow through. In the case of IPv4,
|
|
|
|
* make sure to set the flag for next hop attribute.
|
2018-02-28 03:07:23 +01:00
|
|
|
*/
|
2019-12-03 22:01:19 +01:00
|
|
|
attr = *parent_pi->attr;
|
2021-01-11 07:32:41 +01:00
|
|
|
if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) {
|
|
|
|
if (afi == AFI_IP6)
|
|
|
|
evpn_convert_nexthop_to_ipv6(&attr);
|
2022-07-27 00:04:14 +02:00
|
|
|
else {
|
|
|
|
attr.nexthop = attr.mp_nexthop_global_in;
|
2021-01-11 07:32:41 +01:00
|
|
|
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
2022-07-27 00:04:14 +02:00
|
|
|
}
|
2021-01-11 07:32:41 +01:00
|
|
|
} else {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If gateway IP overlay index is specified in the NLRI of
|
|
|
|
* EVPN RT-5, this gateway IP should be used as the nexthop
|
|
|
|
* for the prefix in the VRF
|
|
|
|
*/
|
|
|
|
if (bgp_debug_zebra(NULL)) {
|
|
|
|
zlog_debug(
|
|
|
|
"Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
|
|
|
|
inet_ntop(pp->family, &attr.evpn_overlay.gw_ip,
|
|
|
|
buf1, sizeof(buf1)), pp,
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (afi == AFI_IP6) {
|
|
|
|
memcpy(&attr.mp_nexthop_global,
|
2022-01-19 21:06:45 +01:00
|
|
|
&attr.evpn_overlay.gw_ip.ipaddr_v6,
|
2021-01-11 07:32:41 +01:00
|
|
|
sizeof(struct in6_addr));
|
|
|
|
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
|
|
|
|
} else {
|
2022-01-19 21:06:45 +01:00
|
|
|
attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4;
|
2021-01-11 07:32:41 +01:00
|
|
|
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
|
|
|
}
|
|
|
|
}
|
2018-02-28 03:07:23 +01:00
|
|
|
|
2020-08-18 01:24:50 +02:00
|
|
|
bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
|
|
|
|
&is_l3nhg_active, NULL);
|
|
|
|
if (use_l3nhg)
|
|
|
|
attr.es_flags |= ATTR_ES_L3_NHG_USE;
|
|
|
|
if (is_l3nhg_active)
|
|
|
|
attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE;
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Check if route entry is already present. */
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
2023-08-08 12:47:29 +02:00
|
|
|
if (pi->extra && pi->extra->vrfleak &&
|
|
|
|
(struct bgp_path_info *)pi->extra->vrfleak->parent ==
|
|
|
|
parent_pi)
|
2017-10-11 10:32:54 +02:00
|
|
|
break;
|
|
|
|
|
2020-05-25 23:06:10 +02:00
|
|
|
if (!pi) {
|
2020-03-27 00:11:58 +01:00
|
|
|
pi = bgp_create_evpn_bgp_path_info(parent_pi, dest, &attr);
|
2020-05-25 23:06:10 +02:00
|
|
|
new_pi = true;
|
|
|
|
} else {
|
2018-10-03 02:43:07 +02:00
|
|
|
if (attrhash_cmp(pi->attr, &attr)
|
|
|
|
&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2017-10-11 10:32:54 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* The attribute has changed. */
|
|
|
|
/* Add (or update) attribute to hash. */
|
2018-02-28 03:07:23 +01:00
|
|
|
attr_new = bgp_attr_intern(&attr);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
/* Restore route, if needed. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_restore(dest, pi);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
/* Mark if nexthop has changed. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if ((afi == AFI_IP
|
|
|
|
&& !IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop))
|
|
|
|
|| (afi == AFI_IP6
|
|
|
|
&& !IPV6_ADDR_SAME(&pi->attr->mp_nexthop_global,
|
|
|
|
&attr_new->mp_nexthop_global)))
|
|
|
|
SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Unintern existing, set to new. */
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_attr_unintern(&pi->attr);
|
|
|
|
pi->attr = attr_new;
|
2022-08-18 00:27:54 +02:00
|
|
|
pi->uptime = monotime(NULL);
|
2017-10-11 10:32:54 +02:00
|
|
|
}
|
2021-01-11 07:32:41 +01:00
|
|
|
|
|
|
|
/* Gateway IP nexthop should be resolved */
|
|
|
|
if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
|
|
|
|
if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi,
|
2021-06-30 10:52:29 +02:00
|
|
|
NULL, 0, NULL))
|
2021-01-11 07:32:41 +01:00
|
|
|
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
|
|
|
|
else {
|
|
|
|
if (BGP_DEBUG(nht, NHT)) {
|
|
|
|
inet_ntop(pp->family,
|
|
|
|
&attr.evpn_overlay.gw_ip,
|
|
|
|
buf1, sizeof(buf1));
|
|
|
|
zlog_debug("%s: gateway IP NH unresolved",
|
|
|
|
buf1);
|
|
|
|
}
|
|
|
|
bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* as it is an importation, change nexthop */
|
|
|
|
bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
|
|
|
|
}
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2020-09-12 19:36:01 +02:00
|
|
|
/* Link path to evpn nexthop */
|
|
|
|
bgp_evpn_path_nh_add(bgp_vrf, pi);
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_aggregate_increment(bgp_vrf, bgp_dest_get_prefix(dest), pi, afi,
|
2020-03-22 05:02:18 +01:00
|
|
|
safi);
|
2018-09-27 18:51:59 +02:00
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Perform route selection and update zebra, if required. */
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp_vrf, dest, pi, afi, safi);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2019-02-28 09:19:21 +01:00
|
|
|
/* Process for route leaking. */
|
|
|
|
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
|
|
|
|
|
2023-12-27 02:36:49 +01:00
|
|
|
if (bgp_debug_zebra(NULL)) {
|
|
|
|
struct ipaddr nhip = {};
|
|
|
|
|
|
|
|
if (pi->net->rn->p.family == AF_INET6) {
|
|
|
|
SET_IPADDR_V6(&nhip);
|
|
|
|
IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global);
|
|
|
|
} else {
|
|
|
|
SET_IPADDR_V4(&nhip);
|
|
|
|
IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop);
|
|
|
|
}
|
|
|
|
zlog_debug("... %s pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA",
|
|
|
|
new_pi ? "new" : "update",
|
|
|
|
bgp_vrf->name_pretty, dest,
|
2020-10-14 18:44:23 +02:00
|
|
|
bgp_dest_get_lock_count(dest), pi, pi->lock,
|
2023-12-27 02:36:49 +01:00
|
|
|
pi->flags, &nhip);
|
|
|
|
}
|
2020-05-25 23:06:10 +02:00
|
|
|
|
2023-09-10 15:46:25 +02:00
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* Common handling for vni route tables install/selection.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
static int install_evpn_route_entry_in_vni_common(
|
|
|
|
struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
|
|
|
|
struct bgp_dest *dest, struct bgp_path_info *parent_pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2020-03-28 18:12:04 +01:00
|
|
|
struct bgp_path_info *local_pi;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct attr *attr_new;
|
|
|
|
int ret;
|
2020-08-30 23:05:33 +02:00
|
|
|
bool old_local_es = false;
|
|
|
|
bool new_local_es;
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Check if route entry is already present. */
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
2023-08-08 12:47:29 +02:00
|
|
|
if (pi->extra && pi->extra->vrfleak &&
|
|
|
|
(struct bgp_path_info *)pi->extra->vrfleak->parent ==
|
|
|
|
parent_pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-10-23 17:56:35 +02:00
|
|
|
if (!pi) {
|
|
|
|
/* Create an info */
|
2020-05-09 04:36:47 +02:00
|
|
|
pi = bgp_create_evpn_bgp_path_info(parent_pi, dest,
|
2020-02-06 22:47:43 +01:00
|
|
|
parent_pi->attr);
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
if (is_evpn_type2_dest_ipaddr_none(dest))
|
|
|
|
evpn_type2_path_info_set_ip(
|
|
|
|
pi, p->prefix.macip_addr.ip);
|
|
|
|
else
|
|
|
|
evpn_type2_path_info_set_mac(
|
|
|
|
pi, p->prefix.macip_addr.mac);
|
|
|
|
}
|
2021-07-23 19:35:14 +02:00
|
|
|
|
2020-08-30 23:05:33 +02:00
|
|
|
new_local_es = bgp_evpn_attr_is_local_es(pi->attr);
|
2019-10-23 17:56:35 +02:00
|
|
|
} else {
|
2022-07-12 00:17:39 +02:00
|
|
|
/* Return early if attributes haven't changed
|
|
|
|
* and dest isn't flagged for removal.
|
|
|
|
* dest will be unlocked by either
|
|
|
|
* install_evpn_route_entry_in_vni_mac() or
|
|
|
|
* install_evpn_route_entry_in_vni_ip()
|
|
|
|
*/
|
|
|
|
if (attrhash_cmp(pi->attr, parent_pi->attr) &&
|
|
|
|
!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
|
|
|
/* The attribute has changed. */
|
|
|
|
/* Add (or update) attribute to hash. */
|
2018-10-03 02:43:07 +02:00
|
|
|
attr_new = bgp_attr_intern(parent_pi->attr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/* Restore route, if needed. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_restore(dest, pi);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
|
|
|
/* Mark if nexthop has changed. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop))
|
|
|
|
SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-08-30 23:05:33 +02:00
|
|
|
old_local_es = bgp_evpn_attr_is_local_es(pi->attr);
|
|
|
|
new_local_es = bgp_evpn_attr_is_local_es(attr_new);
|
|
|
|
/* If ESI is different or if its type has changed we
|
|
|
|
* need to reinstall the path in zebra
|
|
|
|
*/
|
|
|
|
if ((old_local_es != new_local_es)
|
|
|
|
|| memcmp(&pi->attr->esi, &attr_new->esi,
|
|
|
|
sizeof(attr_new->esi))) {
|
|
|
|
|
|
|
|
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
|
|
|
|
zlog_debug("VNI %d path %pFX chg to %s es",
|
2023-07-31 14:34:48 +02:00
|
|
|
vpn->vni, &pi->net->rn->p,
|
2020-08-30 23:05:33 +02:00
|
|
|
new_local_es ? "local"
|
|
|
|
: "non-local");
|
|
|
|
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
|
|
|
|
}
|
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/* Unintern existing, set to new. */
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp_attr_unintern(&pi->attr);
|
|
|
|
pi->attr = attr_new;
|
2022-08-18 00:27:54 +02:00
|
|
|
pi->uptime = monotime(NULL);
|
2018-04-14 00:01:12 +02:00
|
|
|
}
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
/* Add this route to remote IP hashtable */
|
|
|
|
bgp_evpn_remote_ip_hash_add(vpn, pi);
|
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/* Perform route selection and update zebra, if required. */
|
2024-03-11 19:05:59 +01:00
|
|
|
ret = evpn_route_select_install(bgp, vpn, dest, pi);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-03-28 18:12:04 +01:00
|
|
|
/* if the best path is a local path with a non-zero ES
|
|
|
|
* sync info against the local path may need to be updated
|
|
|
|
* when a remote path is added/updated (including changes
|
|
|
|
* from sync-path to remote-path)
|
|
|
|
*/
|
|
|
|
local_pi = bgp_evpn_route_get_local_path(bgp, dest);
|
2020-08-30 23:05:33 +02:00
|
|
|
if (local_pi && (old_local_es || new_local_es))
|
2020-03-28 18:12:04 +01:00
|
|
|
bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
|
2020-08-30 23:05:33 +02:00
|
|
|
__func__);
|
2021-10-26 23:55:54 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common handling for vni route tables uninstall/selection.
|
|
|
|
*/
|
|
|
|
static int uninstall_evpn_route_entry_in_vni_common(
|
|
|
|
struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
|
|
|
|
struct bgp_dest *dest, struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
struct bgp_path_info *pi;
|
|
|
|
struct bgp_path_info *local_pi;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Find matching route entry. */
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
2023-08-08 12:47:29 +02:00
|
|
|
if (pi->extra && pi->extra->vrfleak &&
|
|
|
|
(struct bgp_path_info *)pi->extra->vrfleak->parent ==
|
|
|
|
parent_pi)
|
2021-10-26 23:55:54 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (!pi)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_hash_del(vpn, pi);
|
|
|
|
|
|
|
|
/* Mark entry for deletion */
|
|
|
|
bgp_path_info_delete(dest, pi);
|
|
|
|
|
|
|
|
/* Perform route selection and update zebra, if required. */
|
2024-03-11 19:05:59 +01:00
|
|
|
ret = evpn_route_select_install(bgp, vpn, dest, pi);
|
2021-10-26 23:55:54 +02:00
|
|
|
|
|
|
|
/* if the best path is a local path with a non-zero ES
|
|
|
|
* sync info against the local path may need to be updated
|
|
|
|
* when a remote path is deleted
|
|
|
|
*/
|
|
|
|
local_pi = bgp_evpn_route_get_local_path(bgp, dest);
|
|
|
|
if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr))
|
|
|
|
bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install route entry into VNI IP table and invoke route selection.
|
|
|
|
*/
|
|
|
|
static int install_evpn_route_entry_in_vni_ip(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
|
|
|
|
/* Ignore MAC Only Type-2 */
|
|
|
|
if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
|
|
|
|
(is_evpn_prefix_ipaddr_none(p) == true))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Create (or fetch) route within the VNI IP table. */
|
|
|
|
dest = bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi);
|
|
|
|
|
|
|
|
ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
|
|
|
|
parent_pi);
|
|
|
|
|
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install route entry into VNI MAC table and invoke route selection.
|
|
|
|
*/
|
|
|
|
static int install_evpn_route_entry_in_vni_mac(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
|
|
|
|
/* Only type-2 routes go into this table */
|
|
|
|
if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Create (or fetch) route within the VNI MAC table. */
|
|
|
|
dest = bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi);
|
|
|
|
|
|
|
|
ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
|
|
|
|
parent_pi);
|
|
|
|
|
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall route entry from VNI IP table and invoke route selection.
|
|
|
|
*/
|
|
|
|
static int uninstall_evpn_route_entry_in_vni_ip(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
|
|
|
|
/* Ignore MAC Only Type-2 */
|
|
|
|
if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
|
|
|
|
(is_evpn_prefix_ipaddr_none(p) == true))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Locate route within the VNI IP table. */
|
|
|
|
dest = bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi);
|
|
|
|
if (!dest)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
|
|
|
|
parent_pi);
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2019-11-06 03:30:56 +01:00
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/*
|
|
|
|
* Uninstall route entry from VNI IP table and invoke route selection.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
uninstall_evpn_route_entry_in_vni_mac(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
|
|
|
|
/* Only type-2 routes go into this table */
|
|
|
|
if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Locate route within the VNI MAC table. */
|
|
|
|
dest = bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p, parent_pi);
|
|
|
|
if (!dest)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
|
|
|
|
parent_pi);
|
|
|
|
|
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2017-10-11 10:32:54 +02:00
|
|
|
/*
|
|
|
|
* Uninstall route entry from the VRF routing table and send message
|
|
|
|
* to zebra, if appropriate.
|
|
|
|
*/
|
|
|
|
static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
2020-03-22 19:50:46 +01:00
|
|
|
const struct prefix_evpn *evp,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *parent_pi)
|
2017-10-11 10:32:54 +02:00
|
|
|
{
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-11-13 19:57:52 +01:00
|
|
|
int ret = 0;
|
2017-10-11 10:32:54 +02:00
|
|
|
struct prefix p;
|
|
|
|
struct prefix *pp = &p;
|
|
|
|
afi_t afi = 0;
|
|
|
|
safi_t safi = 0;
|
|
|
|
|
|
|
|
memset(pp, 0, sizeof(struct prefix));
|
2018-04-14 00:37:30 +02:00
|
|
|
ip_prefix_from_evpn_prefix(evp, pp);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2020-10-18 13:33:54 +02:00
|
|
|
if (bgp_debug_zebra(NULL))
|
2017-10-15 06:12:06 +02:00
|
|
|
zlog_debug(
|
2020-10-18 13:33:54 +02:00
|
|
|
"vrf %s: unimport evpn prefix %pFX parent %p flags 0x%x",
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi,
|
|
|
|
parent_pi->flags);
|
2017-10-14 11:56:37 +02:00
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Locate route within the VRF. */
|
|
|
|
/* NOTE: There is no RD here. */
|
2018-04-14 00:37:30 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_v4(evp)) {
|
2017-10-11 10:32:54 +02:00
|
|
|
afi = AFI_IP;
|
|
|
|
safi = SAFI_UNICAST;
|
2020-03-27 00:11:58 +01:00
|
|
|
dest = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp);
|
2017-10-11 10:32:54 +02:00
|
|
|
} else {
|
|
|
|
afi = AFI_IP6;
|
|
|
|
safi = SAFI_UNICAST;
|
2020-03-27 00:11:58 +01:00
|
|
|
dest = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp);
|
2017-10-11 10:32:54 +02:00
|
|
|
}
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
if (!dest)
|
2017-10-11 10:32:54 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Find matching route entry. */
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
2023-08-08 12:47:29 +02:00
|
|
|
if (pi->extra && pi->extra->vrfleak &&
|
|
|
|
(struct bgp_path_info *)pi->extra->vrfleak->parent ==
|
|
|
|
parent_pi)
|
2017-10-11 10:32:54 +02:00
|
|
|
break;
|
|
|
|
|
2021-06-22 22:14:47 +02:00
|
|
|
if (!pi) {
|
|
|
|
bgp_dest_unlock_node(dest);
|
2017-10-11 10:32:54 +02:00
|
|
|
return 0;
|
2021-06-22 22:14:47 +02:00
|
|
|
}
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2023-12-27 02:36:49 +01:00
|
|
|
if (bgp_debug_zebra(NULL)) {
|
|
|
|
struct ipaddr nhip = {};
|
|
|
|
|
|
|
|
if (pi->net->rn->p.family == AF_INET6) {
|
|
|
|
SET_IPADDR_V6(&nhip);
|
|
|
|
IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global);
|
|
|
|
} else {
|
|
|
|
SET_IPADDR_V4(&nhip);
|
|
|
|
IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop);
|
|
|
|
}
|
|
|
|
|
|
|
|
zlog_debug("... delete pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA",
|
|
|
|
bgp_vrf->name_pretty, dest,
|
|
|
|
bgp_dest_get_lock_count(dest), pi, pi->lock,
|
|
|
|
pi->flags, &nhip);
|
|
|
|
}
|
2020-05-25 23:06:10 +02:00
|
|
|
|
2019-02-28 09:19:21 +01:00
|
|
|
/* Process for route leaking. */
|
|
|
|
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_aggregate_decrement(bgp_vrf, bgp_dest_get_prefix(dest), pi, afi,
|
2020-03-22 05:02:18 +01:00
|
|
|
safi);
|
2018-09-28 19:29:18 +02:00
|
|
|
|
2023-05-18 14:49:16 +02:00
|
|
|
/* Force deletion */
|
|
|
|
SET_FLAG(dest->flags, BGP_NODE_PROCESS_CLEAR);
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Mark entry for deletion */
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_path_info_delete(dest, pi);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
2020-09-12 19:36:01 +02:00
|
|
|
/* Unlink path to evpn nexthop */
|
|
|
|
bgp_evpn_path_nh_del(bgp_vrf, pi);
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/* Perform route selection and update zebra, if required. */
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp_vrf, dest, pi, afi, safi);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
/* Unlock route node. */
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(dest);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
2021-10-26 23:55:54 +02:00
|
|
|
* Install route entry into the VNI routing tables.
|
|
|
|
*/
|
|
|
|
static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
const struct prefix_evpn *p,
|
|
|
|
struct bgp_path_info *parent_pi)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1))
|
|
|
|
zlog_debug(
|
|
|
|
"%s (%u): Installing EVPN %pFX route in VNI %u IP/MAC table",
|
|
|
|
vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
|
|
|
|
|
|
|
|
ret = install_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
flog_err(
|
|
|
|
EC_BGP_EVPN_FAIL,
|
|
|
|
"%s (%u): Failed to install EVPN %pFX route in VNI %u MAC table",
|
|
|
|
vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = install_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
flog_err(
|
|
|
|
EC_BGP_EVPN_FAIL,
|
|
|
|
"%s (%u): Failed to install EVPN %pFX route in VNI %u IP table",
|
|
|
|
vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall route entry from the VNI routing tables.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
|
|
|
static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
2020-03-22 19:50:46 +01:00
|
|
|
const struct prefix_evpn *p,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *parent_pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2021-10-26 23:55:54 +02:00
|
|
|
int ret = 0;
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1))
|
|
|
|
zlog_debug(
|
|
|
|
"%s (%u): Uninstalling EVPN %pFX route from VNI %u IP/MAC table",
|
|
|
|
vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
ret = uninstall_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
if (ret) {
|
|
|
|
flog_err(
|
|
|
|
EC_BGP_EVPN_FAIL,
|
|
|
|
"%s (%u): Failed to uninstall EVPN %pFX route from VNI %u IP table",
|
|
|
|
vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
return ret;
|
2021-06-22 22:14:47 +02:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
ret = uninstall_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
if (ret) {
|
|
|
|
flog_err(
|
|
|
|
EC_BGP_EVPN_FAIL,
|
|
|
|
"%s (%u): Failed to uninstall EVPN %pFX route from VNI %u MAC table",
|
|
|
|
vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
|
2020-03-28 18:12:04 +01:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-13 13:10:03 +02:00
|
|
|
/*
|
|
|
|
* Given a route entry and a VRF, see if this route entry should be
|
2023-05-08 04:51:28 +02:00
|
|
|
* imported into the VRF i.e., RTs match + Site-of-Origin check passes.
|
2017-10-13 13:10:03 +02:00
|
|
|
*/
|
2018-10-02 22:41:30 +02:00
|
|
|
static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi)
|
2017-10-13 13:10:03 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
struct attr *attr = pi->attr;
|
2017-10-13 13:10:03 +02:00
|
|
|
struct ecommunity *ecom;
|
2021-01-17 22:08:03 +01:00
|
|
|
uint32_t i;
|
2017-10-13 13:10:03 +02:00
|
|
|
|
|
|
|
assert(attr);
|
|
|
|
/* Route should have valid RT to be even considered. */
|
|
|
|
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
|
|
|
|
return 0;
|
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
ecom = bgp_attr_get_ecommunity(attr);
|
2017-10-13 13:10:03 +02:00
|
|
|
if (!ecom || !ecom->size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* For each extended community RT, see if it matches this VNI. If any RT
|
|
|
|
* matches, we're done.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < ecom->size; i++) {
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
|
|
|
uint8_t type, sub_type;
|
2017-10-13 13:10:03 +02:00
|
|
|
struct ecommunity_val *eval;
|
|
|
|
struct ecommunity_val eval_tmp;
|
|
|
|
struct vrf_irt_node *irt;
|
|
|
|
|
|
|
|
/* Only deal with RTs */
|
2019-10-22 09:21:28 +02:00
|
|
|
pnt = (ecom->val + (i * ecom->unit_size));
|
2017-10-13 13:10:03 +02:00
|
|
|
eval = (struct ecommunity_val *)(ecom->val
|
2019-10-22 09:21:28 +02:00
|
|
|
+ (i * ecom->unit_size));
|
2017-10-13 13:10:03 +02:00
|
|
|
type = *pnt++;
|
|
|
|
sub_type = *pnt++;
|
|
|
|
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* See if this RT matches specified VNIs import RTs */
|
|
|
|
irt = lookup_vrf_import_rt(eval);
|
2018-05-22 16:54:20 +02:00
|
|
|
if (irt)
|
2017-10-13 13:10:03 +02:00
|
|
|
if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Also check for non-exact match. In this, we mask out the AS
|
|
|
|
* and
|
|
|
|
* only check on the local-admin sub-field. This is to
|
|
|
|
* facilitate using
|
|
|
|
* VNI as the RT for EBGP peering too.
|
|
|
|
*/
|
|
|
|
irt = NULL;
|
|
|
|
if (type == ECOMMUNITY_ENCODE_AS
|
|
|
|
|| type == ECOMMUNITY_ENCODE_AS4
|
|
|
|
|| type == ECOMMUNITY_ENCODE_IP) {
|
2019-10-22 09:21:28 +02:00
|
|
|
memcpy(&eval_tmp, eval, ecom->unit_size);
|
2017-10-13 13:10:03 +02:00
|
|
|
mask_ecom_global_admin(&eval_tmp, eval);
|
|
|
|
irt = lookup_vrf_import_rt(&eval_tmp);
|
|
|
|
}
|
2018-05-22 16:54:20 +02:00
|
|
|
if (irt)
|
2017-10-13 13:10:03 +02:00
|
|
|
if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Given a route entry and a VNI, see if this route entry should be
|
|
|
|
* imported into the VNI i.e., RTs match.
|
|
|
|
*/
|
|
|
|
static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
struct attr *attr = pi->attr;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity *ecom;
|
2021-01-17 22:08:03 +01:00
|
|
|
uint32_t i;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
assert(attr);
|
|
|
|
/* Route should have valid RT to be even considered. */
|
|
|
|
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
ecom = bgp_attr_get_ecommunity(attr);
|
2017-05-15 23:34:04 +02:00
|
|
|
if (!ecom || !ecom->size)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* For each extended community RT, see if it matches this VNI. If any RT
|
|
|
|
* matches, we're done.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < ecom->size; i++) {
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
|
|
|
uint8_t type, sub_type;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity_val *eval;
|
|
|
|
struct ecommunity_val eval_tmp;
|
|
|
|
struct irt_node *irt;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Only deal with RTs */
|
2019-10-22 09:21:28 +02:00
|
|
|
pnt = (ecom->val + (i * ecom->unit_size));
|
2017-05-15 23:34:04 +02:00
|
|
|
eval = (struct ecommunity_val *)(ecom->val
|
2019-10-22 09:21:28 +02:00
|
|
|
+ (i * ecom->unit_size));
|
2017-05-15 23:34:04 +02:00
|
|
|
type = *pnt++;
|
|
|
|
sub_type = *pnt++;
|
|
|
|
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* See if this RT matches specified VNIs import RTs */
|
|
|
|
irt = lookup_import_rt(bgp, eval);
|
2018-05-22 16:50:53 +02:00
|
|
|
if (irt)
|
2017-05-15 23:34:04 +02:00
|
|
|
if (is_vni_present_in_irt_vnis(irt->vnis, vpn))
|
|
|
|
return 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Also check for non-exact match. In this, we mask out the AS
|
|
|
|
* and
|
|
|
|
* only check on the local-admin sub-field. This is to
|
|
|
|
* facilitate using
|
|
|
|
* VNI as the RT for EBGP peering too.
|
|
|
|
*/
|
|
|
|
irt = NULL;
|
|
|
|
if (type == ECOMMUNITY_ENCODE_AS
|
|
|
|
|| type == ECOMMUNITY_ENCODE_AS4
|
|
|
|
|| type == ECOMMUNITY_ENCODE_IP) {
|
2019-10-22 09:21:28 +02:00
|
|
|
memcpy(&eval_tmp, eval, ecom->unit_size);
|
2017-05-15 23:34:04 +02:00
|
|
|
mask_ecom_global_admin(&eval_tmp, eval);
|
|
|
|
irt = lookup_import_rt(bgp, &eval_tmp);
|
|
|
|
}
|
2018-05-22 16:50:53 +02:00
|
|
|
if (irt)
|
2017-05-15 23:34:04 +02:00
|
|
|
if (is_vni_present_in_irt_vnis(irt->vnis, vpn))
|
|
|
|
return 1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
static bool bgp_evpn_route_matches_macvrf_soo(struct bgp_path_info *pi,
|
|
|
|
const struct prefix_evpn *evp)
|
2023-05-08 04:51:28 +02:00
|
|
|
{
|
|
|
|
struct bgp *bgp_evpn = bgp_get_evpn();
|
2023-05-08 05:54:25 +02:00
|
|
|
struct ecommunity *macvrf_soo;
|
|
|
|
bool ret = false;
|
2023-05-08 04:51:28 +02:00
|
|
|
|
bgpd: check bgp evpn instance presence in soo
(pi=pi@entry=0x55e86ec1a5a0, evp=evp@entry=0x7fff4edc2160)
at bgpd/bgp_evpn.c:3623
3623 bgpd/bgp_evpn.c: No such file or directory.
(gdb) info locals
bgp_evpn = 0x0
macvrf_soo = <optimized out>
ret = false
__func__ = <optimized out>
(pi=pi@entry=0x55e86ec1a5a0, evp=evp@entry=0x7fff4edc2160)
at bgpd/bgp_evpn.c:3623
(bgp=bgp@entry=0x55e86e9cd010, afi=afi@entry=AFI_L2VPN,
safi=safi@entry=SAFI_EVPN, p=p@entry=0x0,
pi=pi@entry=0x55e86ec1a5a0, import=import@entry=1,
in_vrf_rt=true,
in_vni_rt=true) at bgpd/bgp_evpn.c:4200
(import=1, pi=pi@entry=0x55e86ec1a5a0, p=p@entry=0x0,
safi=safi@entry=SAFI_EVPN, afi=afi@entry=AFI_L2VPN,
bgp=bgp@entry=0x55e86e9cd010) at bgpd/bgp_evpn.c:6266
afi=afi@entry=AFI_L2VPN, safi=safi@entry=SAFI_EVPN,
p=p@entry=0x7fff4edc2160, pi=pi@entry=0x55e86ec1a5a0)
at bgpd/bgp_evpn.c:6266
(peer=peer@entry=0x55e86ea35400, p=p@entry=0x7fff4edc2160,
addpath_id=addpath_id@entry=0, attr=attr@entry=0x7fff4edc4400,
afi=afi@entry=AFI_L2VPN, safi=<optimized out>,
safi@entry=SAFI_EVPN, type=9, sub_type=0, prd=0x7fff4edc2120,
label=0x7fff4edc211c, num_labels=1,
soft_reconfig=0, evpn=0x7fff4edc2130) at bgpd/bgp_route.c:4805
(peer=peer@entry=0x55e86ea35400, afi=afi@entry=AFI_L2VPN,
safi=safi@entry=SAFI_EVPN, attr=attr@entry=0x7fff4edc4400,
pfx=<optimized out>, psize=psize@entry=34,
addpath_id=0) at bgpd/bgp_evpn.c:4922
(peer=0x55e86ea35400, attr=0x7fff4edc4400, packet=<optimized out>,
withdraw=0) at bgpd/bgp_evpn.c:5997
(peer=peer@entry=0x55e86ea35400, attr=attr@entry=0x7fff4edc4400,
packet=packet@entry=0x7fff4edc43d0,
mp_withdraw=mp_withdraw@entry=0) at bgpd/bgp_packet.c:363
(peer=peer@entry=0x55e86ea35400, size=size@entry=161)
at bgpd/bgp_packet.c:2076
(thread=<optimized out>) at bgpd/bgp_packet.c:2931
Ticket: #3683053
Signed-off-by: Chirag Shah <chirag@nvidia.com>
2023-12-05 04:23:32 +01:00
|
|
|
if (!bgp_evpn || !bgp_evpn->evpn_info)
|
2023-05-08 04:51:28 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* We only stamp the mac-vrf soo on routes from our local L2VNI.
|
|
|
|
* No need to filter additional EVPN routes that originated outside
|
|
|
|
* the MAC-VRF/L2VNI.
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
|
|
|
|
evp->prefix.route_type != BGP_EVPN_IMET_ROUTE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
macvrf_soo = bgp_evpn->evpn_info->soo;
|
2023-05-08 05:54:25 +02:00
|
|
|
ret = route_matches_soo(pi, macvrf_soo);
|
2023-05-08 04:51:28 +02:00
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
if (ret && bgp_debug_zebra(NULL)) {
|
|
|
|
char *ecom_str;
|
2023-05-08 04:51:28 +02:00
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
ecom_str = ecommunity_ecom2str(macvrf_soo,
|
|
|
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
|
|
|
zlog_debug(
|
|
|
|
"import of evpn prefix %pFX skipped, local mac-vrf soo %s",
|
|
|
|
evp, ecom_str);
|
|
|
|
ecommunity_strfree(&ecom_str);
|
2023-05-08 04:51:28 +02:00
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
return ret;
|
2023-05-08 04:51:28 +02:00
|
|
|
}
|
|
|
|
|
2019-03-13 02:41:01 +01:00
|
|
|
/* This API will scan evpn routes for checking attribute's rmac
|
|
|
|
* macthes with bgp instance router mac. It avoid installing
|
|
|
|
* route into bgp vrf table and remote rmac in bridge table.
|
|
|
|
*/
|
|
|
|
static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
|
2020-03-22 19:50:46 +01:00
|
|
|
const struct prefix_evpn *evp,
|
2019-03-13 02:41:01 +01:00
|
|
|
struct bgp_path_info *pi)
|
|
|
|
{
|
|
|
|
/* evpn route could have learnt prior to L3vni has come up,
|
|
|
|
* perform rmac check before installing route and
|
|
|
|
* remote router mac.
|
|
|
|
* The route will be removed from global bgp table once
|
|
|
|
* SVI comes up with MAC and stored in hash, triggers
|
|
|
|
* bgp_mac_rescan_all_evpn_tables.
|
|
|
|
*/
|
2019-10-16 16:25:19 +02:00
|
|
|
if (memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
|
2019-03-13 02:41:01 +01:00
|
|
|
if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
|
|
|
|
char attr_str[BUFSIZ] = {0};
|
|
|
|
|
2020-08-18 20:43:07 +02:00
|
|
|
bgp_dump_attr(pi->attr, attr_str, sizeof(attr_str));
|
2019-03-13 02:41:01 +01:00
|
|
|
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug(
|
|
|
|
"%s: bgp %u prefix %pFX with attr %s - DENIED due to self mac",
|
|
|
|
__func__, bgp_vrf->vrf_id, evp, attr_str);
|
2019-03-13 02:41:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-09 04:19:57 +02:00
|
|
|
/* don't import hosts that are locally attached */
|
|
|
|
static inline bool
|
2020-08-15 15:41:31 +02:00
|
|
|
bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
|
|
|
|
const struct prefix_evpn *evp,
|
2020-05-09 04:19:57 +02:00
|
|
|
struct bgp_path_info *pi, int install)
|
|
|
|
{
|
2020-05-09 04:36:47 +02:00
|
|
|
esi_t *esi;
|
2020-05-09 04:19:57 +02:00
|
|
|
|
2020-05-09 04:36:47 +02:00
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
esi = bgp_evpn_attr_get_esi(pi->attr);
|
|
|
|
|
|
|
|
/* Don't import routes that point to a local destination */
|
|
|
|
if (bgp_evpn_attr_is_local_es(pi->attr)) {
|
|
|
|
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
|
|
|
|
char esi_buf[ESI_STR_LEN];
|
|
|
|
|
|
|
|
zlog_debug(
|
|
|
|
"vrf %s of evpn prefix %pFX skipped, local es %s",
|
|
|
|
install ? "import" : "unimport", evp,
|
|
|
|
esi_to_str(esi, esi_buf,
|
|
|
|
sizeof(esi_buf)));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-08-18 01:24:50 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2020-05-09 04:36:47 +02:00
|
|
|
|
2020-08-18 01:24:50 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall a mac-ip route in the provided vrf if
|
|
|
|
* there is a rt match
|
|
|
|
*/
|
|
|
|
int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
|
|
|
|
struct bgp_path_info *pi,
|
|
|
|
int install)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
const struct prefix_evpn *evp =
|
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(pi->net);
|
|
|
|
|
|
|
|
/* Consider "valid" remote routes applicable for
|
|
|
|
* this VRF.
|
|
|
|
*/
|
|
|
|
if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
|
|
|
|
&& pi->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& pi->sub_type == BGP_ROUTE_NORMAL))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
|
|
|
|
if (bgp_evpn_route_rmac_self_check(bgp_vrf, evp, pi))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-30 23:05:33 +02:00
|
|
|
/* don't import hosts that are locally attached */
|
2023-05-08 04:51:28 +02:00
|
|
|
if (install && (bgp_evpn_skip_vrf_import_of_local_es(
|
|
|
|
bgp_vrf, evp, pi, install) ||
|
2023-05-08 05:54:25 +02:00
|
|
|
bgp_evpn_route_matches_macvrf_soo(pi, evp)))
|
2022-03-16 14:38:17 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (install)
|
2020-08-18 01:24:50 +02:00
|
|
|
ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi);
|
2020-05-09 04:36:47 +02:00
|
|
|
else
|
2020-08-18 01:24:50 +02:00
|
|
|
ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf, evp,
|
|
|
|
pi);
|
2020-05-09 04:36:47 +02:00
|
|
|
|
2020-08-18 01:24:50 +02:00
|
|
|
if (ret)
|
|
|
|
flog_err(EC_BGP_EVPN_FAIL,
|
|
|
|
"Failed to %s EVPN %pFX route in VRF %s",
|
|
|
|
install ? "install" : "uninstall", evp,
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id));
|
2020-05-09 04:19:57 +02:00
|
|
|
}
|
2020-08-18 01:24:50 +02:00
|
|
|
|
|
|
|
return ret;
|
2020-05-09 04:19:57 +02:00
|
|
|
}
|
|
|
|
|
2017-10-13 13:10:03 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall mac-ip routes are appropriate for this
|
|
|
|
* particular VRF.
|
|
|
|
*/
|
2024-04-11 19:47:57 +02:00
|
|
|
static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install)
|
2017-10-13 13:10:03 +02:00
|
|
|
{
|
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *rd_dest, *dest;
|
2017-10-13 13:10:03 +02:00
|
|
|
struct bgp_table *table;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-10-13 13:10:03 +02:00
|
|
|
int ret;
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-13 13:10:03 +02:00
|
|
|
|
|
|
|
afi = AFI_L2VPN;
|
|
|
|
safi = SAFI_EVPN;
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
2017-10-13 13:10:03 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Walk entire global routing table and evaluate routes which could be
|
|
|
|
* imported into this VRF. Note that we need to loop through all global
|
|
|
|
* routes to determine which route matches the import rt on vrf
|
|
|
|
*/
|
2020-03-27 00:11:58 +01:00
|
|
|
for (rd_dest = bgp_table_top(bgp_evpn->rib[afi][safi]); rd_dest;
|
|
|
|
rd_dest = bgp_route_next(rd_dest)) {
|
|
|
|
table = bgp_dest_get_bgp_table_info(rd_dest);
|
2017-10-13 13:10:03 +02:00
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (dest = bgp_table_top(table); dest;
|
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
const struct prefix_evpn *evp =
|
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(
|
|
|
|
dest);
|
2017-10-13 13:10:03 +02:00
|
|
|
|
2017-10-14 11:56:37 +02:00
|
|
|
/* if not mac-ip route skip this route */
|
2017-11-13 07:48:36 +01:00
|
|
|
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
|| evp->prefix.route_type
|
|
|
|
== BGP_EVPN_IP_PREFIX_ROUTE))
|
2017-10-13 13:10:03 +02:00
|
|
|
continue;
|
|
|
|
|
2017-10-14 11:56:37 +02:00
|
|
|
/* if not a mac+ip route skip this route */
|
2018-04-14 00:37:30 +02:00
|
|
|
if (!(is_evpn_prefix_ipaddr_v4(evp)
|
|
|
|
|| is_evpn_prefix_ipaddr_v6(evp)))
|
2017-10-14 11:56:37 +02:00
|
|
|
continue;
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
|
2018-07-30 17:40:02 +02:00
|
|
|
pi = pi->next) {
|
2020-08-18 01:24:50 +02:00
|
|
|
ret = bgp_evpn_route_entry_install_if_vrf_match(
|
|
|
|
bgp_vrf, pi, install);
|
2023-08-11 15:53:42 +02:00
|
|
|
if (ret) {
|
|
|
|
bgp_dest_unlock_node(rd_dest);
|
|
|
|
bgp_dest_unlock_node(dest);
|
2020-08-18 01:24:50 +02:00
|
|
|
return ret;
|
2023-08-11 15:53:42 +02:00
|
|
|
}
|
2017-10-13 13:10:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall routes of specified type that are appropriate for this
|
|
|
|
* particular VNI.
|
|
|
|
*/
|
|
|
|
static int install_uninstall_routes_for_vni(struct bgp *bgp,
|
2024-04-11 19:47:57 +02:00
|
|
|
struct bgpevpn *vpn, bool install)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2017-08-19 07:43:09 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *rd_dest, *dest;
|
2017-08-19 07:43:09 +02:00
|
|
|
struct bgp_table *table;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-08-19 07:43:09 +02:00
|
|
|
int ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
afi = AFI_L2VPN;
|
|
|
|
safi = SAFI_EVPN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Walk entire global routing table and evaluate routes which could be
|
|
|
|
* imported into this VPN. Note that we cannot just look at the routes
|
|
|
|
* for
|
|
|
|
* the VNI's RD - remote routes applicable for this VNI could have any
|
|
|
|
* RD.
|
|
|
|
*/
|
|
|
|
/* EVPN routes are a 2-level table. */
|
2020-03-27 00:11:58 +01:00
|
|
|
for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
|
|
|
|
rd_dest = bgp_route_next(rd_dest)) {
|
|
|
|
table = bgp_dest_get_bgp_table_info(rd_dest);
|
2017-05-15 23:34:04 +02:00
|
|
|
if (!table)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (dest = bgp_table_top(table); dest;
|
|
|
|
dest = bgp_route_next(dest)) {
|
2020-03-22 05:02:18 +01:00
|
|
|
const struct prefix_evpn *evp =
|
2020-03-27 00:11:58 +01:00
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(
|
|
|
|
dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2024-04-11 19:28:30 +02:00
|
|
|
if (evp->prefix.route_type != BGP_EVPN_IMET_ROUTE &&
|
|
|
|
evp->prefix.route_type != BGP_EVPN_AD_ROUTE &&
|
|
|
|
evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
2017-05-15 23:34:04 +02:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
|
2018-07-30 17:40:02 +02:00
|
|
|
pi = pi->next) {
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Consider "valid" remote routes applicable for
|
|
|
|
* this VNI. */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
|
|
|
|
&& pi->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& pi->sub_type == BGP_ROUTE_NORMAL))
|
2017-05-15 23:34:04 +02:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-05-08 04:51:28 +02:00
|
|
|
if (!is_route_matching_for_vni(bgp, vpn, pi))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (install) {
|
2023-05-08 05:54:25 +02:00
|
|
|
if (bgp_evpn_route_matches_macvrf_soo(
|
|
|
|
pi, evp))
|
2023-05-08 04:51:28 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = install_evpn_route_entry(bgp, vpn,
|
|
|
|
evp, pi);
|
|
|
|
} else
|
|
|
|
ret = uninstall_evpn_route_entry(
|
|
|
|
bgp, vpn, evp, pi);
|
|
|
|
|
|
|
|
if (ret) {
|
2024-04-11 19:28:30 +02:00
|
|
|
flog_err(EC_BGP_EVPN_FAIL,
|
|
|
|
"%u: Failed to %s EVPN %s route in VNI %u",
|
|
|
|
bgp->vrf_id,
|
|
|
|
install ? "install"
|
|
|
|
: "uninstall",
|
|
|
|
evp->prefix.route_type ==
|
|
|
|
BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
? "MACIP"
|
|
|
|
: "IMET",
|
|
|
|
vpn->vni);
|
2023-05-08 04:51:28 +02:00
|
|
|
|
|
|
|
bgp_dest_unlock_node(rd_dest);
|
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
return ret;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 13:10:03 +02:00
|
|
|
/* Install any existing remote routes applicable for this VRF into VRF RIB. This
|
2017-12-27 20:47:10 +01:00
|
|
|
* is invoked upon l3vni-add or l3vni import rt change
|
|
|
|
*/
|
2017-10-13 13:10:03 +02:00
|
|
|
static int install_routes_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2024-04-11 19:47:57 +02:00
|
|
|
install_uninstall_routes_for_vrf(bgp_vrf, true);
|
2017-10-13 13:10:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Install any existing remote routes applicable for this VNI into its
|
|
|
|
* routing table. This is invoked when a VNI becomes "live" or its Import
|
|
|
|
* RT is changed.
|
|
|
|
*/
|
|
|
|
static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2024-04-11 19:28:30 +02:00
|
|
|
/*
|
|
|
|
* Install type-3 routes followed by type-2 routes - the ones applicable
|
2017-05-15 23:34:04 +02:00
|
|
|
* for this VNI.
|
|
|
|
*/
|
2024-04-11 19:47:57 +02:00
|
|
|
return install_uninstall_routes_for_vni(bgp, vpn, true);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-13 13:10:03 +02:00
|
|
|
/* uninstall routes from l3vni vrf. */
|
|
|
|
static int uninstall_routes_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2024-04-11 19:47:57 +02:00
|
|
|
install_uninstall_routes_for_vrf(bgp_vrf, false);
|
2017-10-13 13:10:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-16 00:01:57 +02:00
|
|
|
/*
|
|
|
|
* Uninstall any existing remote routes for this VNI. One scenario in which
|
|
|
|
* this is invoked is upon an import RT change.
|
|
|
|
*/
|
|
|
|
static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2024-04-11 19:28:30 +02:00
|
|
|
/*
|
|
|
|
* Uninstall type-2 routes followed by type-3 routes - the ones
|
|
|
|
* applicable for this VNI.
|
2017-05-16 00:01:57 +02:00
|
|
|
*/
|
2024-04-11 19:47:57 +02:00
|
|
|
return install_uninstall_routes_for_vni(bgp, vpn, false);
|
2017-05-16 00:01:57 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall route in matching VRFs (list).
|
|
|
|
*/
|
|
|
|
static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
|
|
|
|
safi_t safi, struct prefix_evpn *evp,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi,
|
2017-10-11 10:32:54 +02:00
|
|
|
struct list *vrfs, int install)
|
|
|
|
{
|
|
|
|
struct bgp *bgp_vrf;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
|
2017-11-07 10:52:23 +01:00
|
|
|
/* Only type-2/type-5 routes go into a VRF */
|
|
|
|
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
|| evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
|
2017-10-11 10:32:54 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-11-07 10:52:23 +01:00
|
|
|
/* if it is type-2 route and not a mac+ip route skip this route */
|
|
|
|
if ((evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
|
2018-04-14 00:37:30 +02:00
|
|
|
&& !(is_evpn_prefix_ipaddr_v4(evp)
|
|
|
|
|| is_evpn_prefix_ipaddr_v6(evp)))
|
2017-10-15 06:12:06 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-10-11 10:32:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
|
|
|
|
int ret;
|
|
|
|
|
2020-08-15 15:41:31 +02:00
|
|
|
/* don't import hosts that are locally attached */
|
2022-03-16 14:38:17 +01:00
|
|
|
if (install && bgp_evpn_skip_vrf_import_of_local_es(
|
|
|
|
bgp_vrf, evp, pi, install))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (install)
|
2018-10-03 02:43:07 +02:00
|
|
|
ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi);
|
2017-10-11 10:32:54 +02:00
|
|
|
else
|
|
|
|
ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf, evp,
|
2018-10-03 02:43:07 +02:00
|
|
|
pi);
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
if (ret) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_FAIL,
|
2020-10-18 13:33:54 +02:00
|
|
|
"%u: Failed to %s prefix %pFX in VRF %s",
|
2018-09-13 21:38:57 +02:00
|
|
|
bgp_def->vrf_id,
|
2020-10-18 13:33:54 +02:00
|
|
|
install ? "install" : "uninstall", evp,
|
2018-09-13 21:38:57 +02:00
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id));
|
2017-10-11 10:32:54 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall route in matching VNIs (list).
|
|
|
|
*/
|
|
|
|
static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi,
|
|
|
|
safi_t safi, struct prefix_evpn *evp,
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi,
|
2017-05-15 23:34:04 +02:00
|
|
|
struct list *vnis, int install)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(vnis, node, nnode, vpn)) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!is_vni_live(vpn))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (install)
|
2018-10-03 02:43:07 +02:00
|
|
|
ret = install_evpn_route_entry(bgp, vpn, evp, pi);
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2018-10-03 02:43:07 +02:00
|
|
|
ret = uninstall_evpn_route_entry(bgp, vpn, evp, pi);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
if (ret) {
|
2018-09-13 21:38:57 +02:00
|
|
|
flog_err(EC_BGP_EVPN_FAIL,
|
|
|
|
"%u: Failed to %s EVPN %s route in VNI %u",
|
|
|
|
bgp->vrf_id, install ? "install" : "uninstall",
|
|
|
|
evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
? "MACIP"
|
|
|
|
: "IMET",
|
|
|
|
vpn->vni);
|
2017-05-15 23:34:04 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-04-14 00:01:12 +02:00
|
|
|
* Install or uninstall route for appropriate VNIs/ESIs.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
2020-05-09 04:36:47 +02:00
|
|
|
static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
|
|
|
|
safi_t safi, const struct prefix *p,
|
|
|
|
struct bgp_path_info *pi,
|
|
|
|
int import, bool in_vni_rt,
|
|
|
|
bool in_vrf_rt)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn *evp = (struct prefix_evpn *)p;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct attr *attr = pi->attr;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity *ecom;
|
2021-01-17 22:08:03 +01:00
|
|
|
uint32_t i;
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
struct prefix_evpn ad_evp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
assert(attr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-04-12 08:11:57 +02:00
|
|
|
/* Only type-1, type-2, type-3, type-4 and type-5
|
|
|
|
* are supported currently
|
|
|
|
*/
|
2017-05-15 23:34:04 +02:00
|
|
|
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
2017-11-07 10:52:23 +01:00
|
|
|
|| evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
|
2018-04-14 00:01:12 +02:00
|
|
|
|| evp->prefix.route_type == BGP_EVPN_ES_ROUTE
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
|| evp->prefix.route_type == BGP_EVPN_AD_ROUTE
|
2017-11-07 10:52:23 +01:00
|
|
|
|| evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* If we don't have Route Target, nothing much to do. */
|
|
|
|
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
/* EAD prefix in the global table doesn't include the VTEP-IP so
|
|
|
|
* we need to create a different copy for the VNI
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
|
2021-10-26 23:55:54 +02:00
|
|
|
evp = evpn_type1_prefix_vni_ip_copy(&ad_evp, evp,
|
|
|
|
attr->nexthop);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
|
2022-02-04 14:56:20 +01:00
|
|
|
ecom = bgp_attr_get_ecommunity(attr);
|
2017-05-15 23:34:04 +02:00
|
|
|
if (!ecom || !ecom->size)
|
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-05-08 04:51:28 +02:00
|
|
|
/* Filter routes carrying a Site-of-Origin that matches our
|
|
|
|
* local MAC-VRF SoO.
|
|
|
|
*/
|
2023-05-08 05:54:25 +02:00
|
|
|
if (import && bgp_evpn_route_matches_macvrf_soo(pi, evp))
|
2023-05-08 04:51:28 +02:00
|
|
|
return 0;
|
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/* An EVPN route belongs to a VNI or a VRF or an ESI based on the RTs
|
|
|
|
* attached to the route */
|
2017-05-15 23:34:04 +02:00
|
|
|
for (i = 0; i < ecom->size; i++) {
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
|
|
|
uint8_t type, sub_type;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity_val *eval;
|
|
|
|
struct ecommunity_val eval_tmp;
|
2017-10-11 10:32:54 +02:00
|
|
|
struct irt_node *irt; /* import rt for l2vni */
|
|
|
|
struct vrf_irt_node *vrf_irt; /* import rt for l3vni */
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
struct bgp_evpn_es *es;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Only deal with RTs */
|
2019-10-22 09:21:28 +02:00
|
|
|
pnt = (ecom->val + (i * ecom->unit_size));
|
2017-05-15 23:34:04 +02:00
|
|
|
eval = (struct ecommunity_val *)(ecom->val
|
2019-10-22 09:21:28 +02:00
|
|
|
+ (i * ecom->unit_size));
|
2017-05-15 23:34:04 +02:00
|
|
|
type = *pnt++;
|
|
|
|
sub_type = *pnt++;
|
|
|
|
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-18 01:24:50 +02:00
|
|
|
/* non-local MAC-IP routes in the global route table are linked
|
|
|
|
* to the destination ES
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
bgp_evpn_path_es_link(pi, 0,
|
|
|
|
bgp_evpn_attr_get_esi(pi->attr));
|
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/*
|
|
|
|
* macip routes (type-2) are imported into VNI and VRF tables.
|
|
|
|
* IMET route is imported into VNI table.
|
|
|
|
* prefix routes are imported into VRF table.
|
2017-12-27 20:47:10 +01:00
|
|
|
*/
|
2018-04-14 00:01:12 +02:00
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
|
|
|
|
evp->prefix.route_type == BGP_EVPN_IMET_ROUTE ||
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
evp->prefix.route_type == BGP_EVPN_AD_ROUTE ||
|
2018-04-14 00:01:12 +02:00
|
|
|
evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-05-09 04:36:47 +02:00
|
|
|
irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL;
|
2018-04-14 00:01:12 +02:00
|
|
|
if (irt)
|
2018-10-03 02:43:07 +02:00
|
|
|
install_uninstall_route_in_vnis(
|
|
|
|
bgp, afi, safi, evp, pi, irt->vnis,
|
|
|
|
import);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-05-09 04:36:47 +02:00
|
|
|
vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL;
|
2018-04-14 00:01:12 +02:00
|
|
|
if (vrf_irt)
|
2018-10-03 02:43:07 +02:00
|
|
|
install_uninstall_route_in_vrfs(
|
|
|
|
bgp, afi, safi, evp, pi, vrf_irt->vrfs,
|
|
|
|
import);
|
2018-04-14 00:01:12 +02:00
|
|
|
|
|
|
|
/* Also check for non-exact match.
|
|
|
|
* In this, we mask out the AS and
|
|
|
|
* only check on the local-admin sub-field.
|
|
|
|
* This is to facilitate using
|
|
|
|
* VNI as the RT for EBGP peering too.
|
|
|
|
*/
|
|
|
|
irt = NULL;
|
|
|
|
vrf_irt = NULL;
|
|
|
|
if (type == ECOMMUNITY_ENCODE_AS
|
|
|
|
|| type == ECOMMUNITY_ENCODE_AS4
|
|
|
|
|| type == ECOMMUNITY_ENCODE_IP) {
|
2019-10-22 09:21:28 +02:00
|
|
|
memcpy(&eval_tmp, eval, ecom->unit_size);
|
2018-04-14 00:01:12 +02:00
|
|
|
mask_ecom_global_admin(&eval_tmp, eval);
|
2020-05-09 04:36:47 +02:00
|
|
|
if (in_vni_rt)
|
|
|
|
irt = lookup_import_rt(bgp, &eval_tmp);
|
|
|
|
if (in_vrf_rt)
|
|
|
|
vrf_irt =
|
|
|
|
lookup_vrf_import_rt(&eval_tmp);
|
2018-04-14 00:01:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (irt)
|
2018-10-03 02:43:07 +02:00
|
|
|
install_uninstall_route_in_vnis(
|
|
|
|
bgp, afi, safi, evp, pi, irt->vnis,
|
|
|
|
import);
|
2018-04-14 00:01:12 +02:00
|
|
|
if (vrf_irt)
|
2018-10-03 02:43:07 +02:00
|
|
|
install_uninstall_route_in_vrfs(
|
|
|
|
bgp, afi, safi, evp, pi, vrf_irt->vrfs,
|
|
|
|
import);
|
2018-04-14 00:01:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* es route is imported into the es table */
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE) {
|
|
|
|
|
|
|
|
/* we will match based on the entire esi to avoid
|
2022-04-12 08:11:57 +02:00
|
|
|
* import of an es route for esi2 into esi1
|
2018-04-14 00:01:12 +02:00
|
|
|
*/
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
es = bgp_evpn_es_find(&evp->prefix.es_addr.esi);
|
2020-03-28 18:12:04 +01:00
|
|
|
if (es && bgp_evpn_is_es_local(es))
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
bgp_evpn_es_route_install_uninstall(
|
2018-10-03 02:43:07 +02:00
|
|
|
bgp, es, afi, safi, evp, pi, import);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-09 04:36:47 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall route for appropriate VNIs/ESIs.
|
|
|
|
*/
|
|
|
|
static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
|
|
|
const struct prefix *p,
|
|
|
|
struct bgp_path_info *pi, int import)
|
|
|
|
{
|
|
|
|
return bgp_evpn_install_uninstall_table(bgp, afi, safi, p, pi, import,
|
|
|
|
true, true);
|
|
|
|
}
|
|
|
|
|
2020-08-30 23:05:33 +02:00
|
|
|
void bgp_evpn_import_type2_route(struct bgp_path_info *pi, int import)
|
|
|
|
{
|
|
|
|
struct bgp *bgp_evpn;
|
|
|
|
|
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
install_uninstall_evpn_route(bgp_evpn, AFI_L2VPN, SAFI_EVPN,
|
2023-07-31 14:34:48 +02:00
|
|
|
&pi->net->rn->p, pi, import);
|
2020-08-30 23:05:33 +02:00
|
|
|
}
|
|
|
|
|
2018-05-16 14:17:53 +02:00
|
|
|
/*
|
|
|
|
* delete and withdraw all ipv4 and ipv6 routes in the vrf table as type-5
|
|
|
|
* routes
|
|
|
|
*/
|
2017-11-02 10:15:14 +01:00
|
|
|
static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
|
|
|
|
{
|
2018-11-29 04:18:08 +01:00
|
|
|
/* Delete ipv4 default route and withdraw from peers */
|
|
|
|
if (evpn_default_originate_set(bgp_vrf, AFI_IP, SAFI_UNICAST))
|
|
|
|
bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP,
|
|
|
|
SAFI_UNICAST, false);
|
|
|
|
|
2017-11-02 10:15:14 +01:00
|
|
|
/* delete all ipv4 routes and withdraw from peers */
|
2018-02-20 09:23:06 +01:00
|
|
|
if (advertise_type5_routes(bgp_vrf, AFI_IP))
|
|
|
|
bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
|
2017-11-02 10:15:14 +01:00
|
|
|
|
2018-11-29 04:18:08 +01:00
|
|
|
/* Delete ipv6 default route and withdraw from peers */
|
|
|
|
if (evpn_default_originate_set(bgp_vrf, AFI_IP6, SAFI_UNICAST))
|
|
|
|
bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP6,
|
|
|
|
SAFI_UNICAST, false);
|
|
|
|
|
2017-11-02 10:15:14 +01:00
|
|
|
/* delete all ipv6 routes and withdraw from peers */
|
2018-02-20 09:23:06 +01:00
|
|
|
if (advertise_type5_routes(bgp_vrf, AFI_IP6))
|
|
|
|
bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
|
2017-11-02 10:15:14 +01:00
|
|
|
}
|
|
|
|
|
2018-05-16 14:17:53 +02:00
|
|
|
/*
|
|
|
|
* update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5
|
|
|
|
* routes
|
|
|
|
*/
|
2019-04-18 09:17:57 +02:00
|
|
|
void update_advertise_vrf_routes(struct bgp *bgp_vrf)
|
2017-11-02 10:15:14 +01:00
|
|
|
{
|
2019-04-18 09:17:57 +02:00
|
|
|
struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
|
|
|
|
|
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
|
|
|
return;
|
|
|
|
|
2017-11-02 10:15:14 +01:00
|
|
|
/* update all ipv4 routes */
|
2018-02-20 09:23:06 +01:00
|
|
|
if (advertise_type5_routes(bgp_vrf, AFI_IP))
|
|
|
|
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
|
2017-11-02 10:15:14 +01:00
|
|
|
|
2018-11-29 04:18:08 +01:00
|
|
|
/* update ipv4 default route and withdraw from peers */
|
|
|
|
if (evpn_default_originate_set(bgp_vrf, AFI_IP, SAFI_UNICAST))
|
|
|
|
bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP,
|
|
|
|
SAFI_UNICAST, true);
|
|
|
|
|
2017-11-02 10:15:14 +01:00
|
|
|
/* update all ipv6 routes */
|
2018-02-20 09:23:06 +01:00
|
|
|
if (advertise_type5_routes(bgp_vrf, AFI_IP6))
|
|
|
|
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
|
2018-11-29 04:18:08 +01:00
|
|
|
|
|
|
|
/* update ipv6 default route and withdraw from peers */
|
|
|
|
if (evpn_default_originate_set(bgp_vrf, AFI_IP6, SAFI_UNICAST))
|
|
|
|
bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP6,
|
|
|
|
SAFI_UNICAST, true);
|
|
|
|
|
2017-11-02 10:15:14 +01:00
|
|
|
}
|
|
|
|
|
2017-10-26 01:49:18 +02:00
|
|
|
/*
|
|
|
|
* update and advertise local routes for a VRF as type-5 routes.
|
|
|
|
* This is invoked upon RD change for a VRF. Note taht the processing is only
|
|
|
|
* done in the global route table using the routes which already exist in the
|
|
|
|
* VRF routing table
|
|
|
|
*/
|
2017-11-02 10:15:14 +01:00
|
|
|
static void update_router_id_vrf(struct bgp *bgp_vrf)
|
2017-10-26 01:49:18 +02:00
|
|
|
{
|
2017-11-02 10:15:14 +01:00
|
|
|
/* skip if the RD is configured */
|
|
|
|
if (is_vrf_rd_configured(bgp_vrf))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* derive the RD for the VRF based on new router-id */
|
|
|
|
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
|
|
|
|
|
|
|
|
/* update advertise ipv4|ipv6 routes as type-5 routes */
|
|
|
|
update_advertise_vrf_routes(bgp_vrf);
|
2017-10-26 01:49:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete and withdraw all type-5 routes for the RD corresponding to VRF.
|
|
|
|
* This is invoked upon VRF RD change. The processing is done only from global
|
|
|
|
* table.
|
|
|
|
*/
|
2017-11-02 10:15:14 +01:00
|
|
|
static void withdraw_router_id_vrf(struct bgp *bgp_vrf)
|
2017-10-26 01:49:18 +02:00
|
|
|
{
|
2017-11-02 10:15:14 +01:00
|
|
|
/* skip if the RD is configured */
|
|
|
|
if (is_vrf_rd_configured(bgp_vrf))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* delete/withdraw ipv4|ipv6 routes as type-5 routes */
|
|
|
|
delete_withdraw_vrf_routes(bgp_vrf);
|
2017-10-26 01:49:18 +02:00
|
|
|
}
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
struct bgp_dest *dest)
|
|
|
|
{
|
|
|
|
struct bgp_dest *global_dest;
|
|
|
|
struct bgp_path_info *pi, *global_pi;
|
|
|
|
struct attr *attr;
|
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
|
|
|
|
struct prefix_evpn tmp_evp;
|
|
|
|
const struct prefix_evpn *evp =
|
|
|
|
(const struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have already processed type-3 routes.
|
|
|
|
* Process only type-1 and type-2 routes here.
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
|
|
|
|
evp->prefix.route_type != BGP_EVPN_AD_ROUTE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
|
|
|
if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
pi->sub_type == BGP_ROUTE_STATIC)
|
|
|
|
break;
|
|
|
|
if (!pi)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* VNI table MAC-IP prefixes don't have MAC so make sure it's
|
|
|
|
* set from path info here.
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
if (is_evpn_prefix_ipaddr_none(evp)) {
|
|
|
|
/* VNI MAC -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
|
|
|
&tmp_evp, evp, NULL /* mac */,
|
|
|
|
evpn_type2_path_info_get_ip(pi));
|
|
|
|
} else {
|
|
|
|
/* VNI IP -> Global */
|
|
|
|
evpn_type2_prefix_global_copy(
|
|
|
|
&tmp_evp, evp, evpn_type2_path_info_get_mac(pi),
|
|
|
|
NULL /* ip */);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(&tmp_evp, evp, sizeof(tmp_evp));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create route in global routing table using this route entry's
|
|
|
|
* attribute.
|
|
|
|
*/
|
|
|
|
attr = pi->attr;
|
|
|
|
global_dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
|
|
|
|
&tmp_evp, &vpn->prd, NULL);
|
|
|
|
assert(global_dest);
|
|
|
|
|
|
|
|
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
|
|
|
/* Type-2 route */
|
|
|
|
update_evpn_route_entry(
|
|
|
|
bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */,
|
|
|
|
NULL /* ip */, 1, &global_pi, 0,
|
|
|
|
mac_mobility_seqnum(attr), false /* setup_sync */,
|
|
|
|
NULL /* old_is_sync */);
|
|
|
|
} else {
|
|
|
|
/* Type-1 route */
|
|
|
|
struct bgp_evpn_es *es;
|
|
|
|
int route_changed = 0;
|
|
|
|
|
|
|
|
es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi);
|
|
|
|
bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, global_dest,
|
|
|
|
attr, &global_pi, &route_changed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Schedule for processing and unlock node. */
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, global_dest, global_pi, afi, safi);
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp_dest_unlock_node(global_dest);
|
|
|
|
}
|
|
|
|
|
2017-05-16 00:01:57 +02:00
|
|
|
/*
|
|
|
|
* Update and advertise local routes for a VNI. Invoked upon router-id
|
|
|
|
* change. Note that the processing is done only on the global route table
|
|
|
|
* using routes that already exist in the per-VNI table.
|
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
2017-05-16 00:01:57 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn p;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest, *global_dest;
|
2021-10-26 23:55:54 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-05-16 00:01:57 +02:00
|
|
|
struct attr *attr;
|
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-16 00:01:57 +02:00
|
|
|
/* Locate type-3 route for VNI in the per-VNI table and use its
|
|
|
|
* attributes to create and advertise the type-3 route for this VNI
|
|
|
|
* in the global table.
|
2018-10-05 01:20:12 +02:00
|
|
|
*
|
|
|
|
* RT-3 only if doing head-end replication
|
2017-05-16 00:01:57 +02:00
|
|
|
*/
|
2019-03-26 21:26:33 +01:00
|
|
|
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
|
|
|
|
== VXLAN_FLOOD_HEAD_END_REPL) {
|
2018-10-05 01:20:12 +02:00
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
2021-10-26 23:55:54 +02:00
|
|
|
dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
|
2020-03-27 00:11:58 +01:00
|
|
|
if (!dest) /* unexpected */
|
2021-10-26 23:55:54 +02:00
|
|
|
return;
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
2018-10-05 01:20:12 +02:00
|
|
|
if (pi->peer == bgp->peer_self &&
|
|
|
|
pi->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& pi->sub_type == BGP_ROUTE_STATIC)
|
|
|
|
break;
|
2022-09-06 10:49:08 +02:00
|
|
|
if (!pi) {
|
|
|
|
bgp_dest_unlock_node(dest);
|
2021-10-26 23:55:54 +02:00
|
|
|
return;
|
2022-09-06 10:49:08 +02:00
|
|
|
}
|
2021-10-26 23:55:54 +02:00
|
|
|
|
2018-10-05 01:20:12 +02:00
|
|
|
attr = pi->attr;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-07-23 19:35:14 +02:00
|
|
|
global_dest = bgp_evpn_global_node_get(
|
|
|
|
bgp->rib[afi][safi], afi, safi, &p, &vpn->prd, NULL);
|
|
|
|
update_evpn_route_entry(
|
|
|
|
bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */,
|
2021-10-26 23:55:54 +02:00
|
|
|
NULL /* ip */, 1, &pi, 0, mac_mobility_seqnum(attr),
|
2021-07-23 19:35:14 +02:00
|
|
|
false /* setup_sync */, NULL /* old_is_sync */);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-05 01:20:12 +02:00
|
|
|
/* Schedule for processing and unlock node. */
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, global_dest, pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(global_dest);
|
2018-10-05 01:20:12 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/* Now, walk this VNI's MAC & IP route table and use the route and its
|
|
|
|
* attribute to create and schedule route in global table.
|
2017-05-16 00:01:57 +02:00
|
|
|
*/
|
2021-10-26 23:55:54 +02:00
|
|
|
for (dest = bgp_table_top(vpn->mac_table); dest;
|
|
|
|
dest = bgp_route_next(dest))
|
|
|
|
update_advertise_vni_route(bgp, vpn, dest);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
for (dest = bgp_table_top(vpn->ip_table); dest;
|
|
|
|
dest = bgp_route_next(dest))
|
|
|
|
update_advertise_vni_route(bgp, vpn, dest);
|
2017-05-16 00:01:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete (and withdraw) local routes for a VNI - only from the global
|
|
|
|
* table. Invoked upon router-id change.
|
|
|
|
*/
|
|
|
|
static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
struct prefix_evpn p;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *global_dest;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-05-16 00:01:57 +02:00
|
|
|
afi_t afi = AFI_L2VPN;
|
|
|
|
safi_t safi = SAFI_EVPN;
|
|
|
|
|
|
|
|
/* Delete and withdraw locally learnt type-2 routes (MACIP)
|
|
|
|
* for this VNI - from the global table.
|
|
|
|
*/
|
2022-04-26 06:14:34 +02:00
|
|
|
delete_global_type2_routes(bgp, vpn);
|
2017-05-16 00:01:57 +02:00
|
|
|
|
|
|
|
/* Remove type-3 route for this VNI from global table. */
|
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
2023-03-14 11:05:58 +01:00
|
|
|
global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], safi, &p,
|
|
|
|
&vpn->prd, NULL);
|
2020-03-27 00:11:58 +01:00
|
|
|
if (global_dest) {
|
2017-05-16 00:01:57 +02:00
|
|
|
/* Delete route entry in the global EVPN table. */
|
2020-03-27 00:11:58 +01:00
|
|
|
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
|
2017-05-16 00:01:57 +02:00
|
|
|
|
|
|
|
/* Schedule for processing - withdraws to peers happen from
|
|
|
|
* this table.
|
|
|
|
*/
|
2018-10-03 02:43:07 +02:00
|
|
|
if (pi)
|
2024-03-04 16:41:13 +01:00
|
|
|
bgp_process(bgp, global_dest, pi, afi, safi);
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_unlock_node(global_dest);
|
2017-05-16 00:01:57 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 00:54:48 +02:00
|
|
|
|
|
|
|
delete_global_ead_evi_routes(bgp, vpn);
|
2017-05-16 00:01:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-16 00:02:33 +02:00
|
|
|
/*
|
|
|
|
* Handle router-id change. Update and advertise local routes corresponding
|
|
|
|
* to this VNI from peers. Note that this is invoked after updating the
|
|
|
|
* router-id. The routes in the per-VNI table are used to create routes in
|
|
|
|
* the global table and schedule them.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void update_router_id_vni(struct hash_bucket *bucket, struct bgp *bgp)
|
2017-05-16 00:02:33 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
2017-05-16 00:02:33 +02:00
|
|
|
|
|
|
|
/* Skip VNIs with configured RD. */
|
|
|
|
if (is_rd_configured(vpn))
|
|
|
|
return;
|
|
|
|
|
|
|
|
bgp_evpn_derive_auto_rd(bgp, vpn);
|
|
|
|
update_advertise_vni_routes(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle router-id change. Delete and withdraw local routes corresponding
|
|
|
|
* to this VNI from peers. Note that this is invoked prior to updating
|
|
|
|
* the router-id and is done only on the global route table, the routes
|
|
|
|
* are needed in the per-VNI table to re-advertise with new router id.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void withdraw_router_id_vni(struct hash_bucket *bucket, struct bgp *bgp)
|
2017-05-16 00:02:33 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
2017-05-16 00:02:33 +02:00
|
|
|
|
|
|
|
/* Skip VNIs with configured RD. */
|
|
|
|
if (is_rd_configured(vpn))
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete_withdraw_vni_routes(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2018-10-05 01:20:12 +02:00
|
|
|
/*
|
|
|
|
* Create RT-3 for a VNI and schedule for processing and advertisement.
|
|
|
|
* This is invoked upon flooding mode changing to head-end replication.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void create_advertise_type3(struct hash_bucket *bucket, void *data)
|
2018-10-05 01:20:12 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = bucket->data;
|
2018-10-05 01:20:12 +02:00
|
|
|
struct bgp *bgp = data;
|
|
|
|
struct prefix_evpn p;
|
|
|
|
|
2019-03-26 21:26:33 +01:00
|
|
|
if (!vpn || !is_vni_live(vpn) ||
|
|
|
|
bgp_evpn_vni_flood_mode_get(bgp, vpn)
|
|
|
|
!= VXLAN_FLOOD_HEAD_END_REPL)
|
2018-10-05 01:20:12 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
if (update_evpn_route(bgp, vpn, &p, 0, 0, NULL))
|
2018-10-05 01:20:12 +02:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_CREATE,
|
|
|
|
"Type3 route creation failure for VNI %u", vpn->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete RT-3 for a VNI and schedule for processing and withdrawal.
|
|
|
|
* This is invoked upon flooding mode changing to drop BUM packets.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void delete_withdraw_type3(struct hash_bucket *bucket, void *data)
|
2018-10-05 01:20:12 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = bucket->data;
|
2018-10-05 01:20:12 +02:00
|
|
|
struct bgp *bgp = data;
|
|
|
|
struct prefix_evpn p;
|
|
|
|
|
|
|
|
if (!vpn || !is_vni_live(vpn))
|
|
|
|
return;
|
|
|
|
|
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
|
|
|
delete_evpn_route(bgp, vpn, &p);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Process received EVPN type-2 route (advertise or withdraw).
|
|
|
|
*/
|
|
|
|
static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct attr *attr, uint8_t *pfx, int psize,
|
|
|
|
uint32_t addpath_id)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct prefix_rd prd;
|
2020-05-14 01:12:41 +02:00
|
|
|
struct prefix_evpn p = {};
|
|
|
|
struct bgp_route_evpn evpn = {};
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t ipaddr_len;
|
|
|
|
uint8_t macaddr_len;
|
2020-05-14 01:12:41 +02:00
|
|
|
/* holds the VNI(s) as in packet */
|
|
|
|
mpls_label_t label[BGP_MAX_LABELS] = {};
|
2024-02-26 18:11:09 +01:00
|
|
|
uint8_t num_labels = 0;
|
2018-04-06 15:52:48 +02:00
|
|
|
uint32_t eth_tag;
|
2023-01-30 22:02:23 +01:00
|
|
|
int ret = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Type-2 route should be either 33, 37 or 49 bytes or an
|
|
|
|
* additional 3 bytes if there is a second label (VNI):
|
|
|
|
* RD (8), ESI (10), Eth Tag (4), MAC Addr Len (1),
|
|
|
|
* MAC Addr (6), IP len (1), IP (0, 4 or 16),
|
|
|
|
* MPLS Lbl1 (3), MPLS Lbl2 (0 or 3)
|
|
|
|
*/
|
|
|
|
if (psize != 33 && psize != 37 && psize != 49 && psize != 36
|
|
|
|
&& psize != 40 && psize != 52) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
2018-09-13 21:38:57 +02:00
|
|
|
"%u:%s - Rx EVPN Type-2 NLRI with invalid length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2017-05-15 23:34:04 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-05-14 01:12:41 +02:00
|
|
|
struct stream *pkt = stream_new(psize);
|
|
|
|
stream_put(pkt, pfx, psize);
|
2018-04-06 15:52:48 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Make prefix_rd */
|
|
|
|
prd.family = AF_UNSPEC;
|
|
|
|
prd.prefixlen = 64;
|
2020-05-14 01:12:41 +02:00
|
|
|
|
|
|
|
STREAM_GET(&prd.val, pkt, 8);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Make EVPN prefix. */
|
2017-08-08 16:16:12 +02:00
|
|
|
p.family = AF_EVPN;
|
2018-04-14 00:01:12 +02:00
|
|
|
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
|
2017-05-15 23:34:04 +02:00
|
|
|
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-06 15:52:48 +02:00
|
|
|
/* Copy Ethernet Seg Identifier */
|
2020-03-28 18:12:04 +01:00
|
|
|
if (attr) {
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GET(&attr->esi, pkt, sizeof(esi_t));
|
|
|
|
|
2020-08-30 23:05:33 +02:00
|
|
|
if (bgp_evpn_is_esi_local_and_non_bypass(&attr->esi))
|
2020-03-28 18:12:04 +01:00
|
|
|
attr->es_flags |= ATTR_ES_IS_LOCAL;
|
|
|
|
else
|
|
|
|
attr->es_flags &= ~ATTR_ES_IS_LOCAL;
|
2020-05-14 01:12:41 +02:00
|
|
|
} else {
|
|
|
|
STREAM_FORWARD_GETP(pkt, sizeof(esi_t));
|
2020-03-28 18:12:04 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-06 15:52:48 +02:00
|
|
|
/* Copy Ethernet Tag */
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GET(ð_tag, pkt, 4);
|
2018-04-14 00:37:30 +02:00
|
|
|
p.prefix.macip_addr.eth_tag = ntohl(eth_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Get the MAC Addr len */
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GETC(pkt, macaddr_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Get the MAC Addr */
|
2017-08-03 14:45:27 +02:00
|
|
|
if (macaddr_len == (ETH_ALEN * 8)) {
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GET(&p.prefix.macip_addr.mac.octet, pkt, ETH_ALEN);
|
2017-05-15 23:34:04 +02:00
|
|
|
} else {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_ROUTE_INVALID,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, macaddr_len);
|
2020-05-14 01:12:41 +02:00
|
|
|
goto fail;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Get the IP. */
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GETC(pkt, ipaddr_len);
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
if (ipaddr_len != 0 && ipaddr_len != IPV4_MAX_BITLEN
|
|
|
|
&& ipaddr_len != IPV6_MAX_BITLEN) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_ROUTE_INVALID,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, ipaddr_len);
|
2020-05-14 01:12:41 +02:00
|
|
|
goto fail;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
if (ipaddr_len) {
|
|
|
|
ipaddr_len /= 8; /* Convert to bytes. */
|
2018-04-14 00:37:30 +02:00
|
|
|
p.prefix.macip_addr.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN)
|
2017-05-15 23:34:04 +02:00
|
|
|
? IPADDR_V4
|
|
|
|
: IPADDR_V6;
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GET(&p.prefix.macip_addr.ip.ip.addr, pkt, ipaddr_len);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-21 11:42:05 +01:00
|
|
|
/* Get the VNI(s). Stored as bytes here. */
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GET(&label[0], pkt, BGP_LABEL_BYTES);
|
2017-11-21 11:42:05 +01:00
|
|
|
num_labels++;
|
2020-05-14 01:12:41 +02:00
|
|
|
|
2017-11-21 11:42:05 +01:00
|
|
|
/* Do we have a second VNI? */
|
2020-05-14 01:12:41 +02:00
|
|
|
if (STREAM_READABLE(pkt)) {
|
2017-11-21 11:42:05 +01:00
|
|
|
num_labels++;
|
2020-05-14 01:12:41 +02:00
|
|
|
STREAM_GET(&label[1], pkt, BGP_LABEL_BYTES);
|
2017-11-21 11:42:05 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Process the route. */
|
|
|
|
if (attr)
|
2023-01-30 22:02:23 +01:00
|
|
|
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
|
|
|
|
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
|
|
|
|
&label[0], num_labels, 0, &evpn);
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2023-02-21 10:35:59 +01:00
|
|
|
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
|
|
|
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0],
|
|
|
|
num_labels, &evpn);
|
2020-05-14 01:12:41 +02:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
stream_failure:
|
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
|
|
|
"%u:%s - Rx EVPN Type-2 NLRI - corrupt, discarding",
|
|
|
|
peer->bgp->vrf_id, peer->host);
|
|
|
|
ret = -1;
|
|
|
|
done:
|
|
|
|
stream_free(pkt);
|
2017-05-15 23:34:04 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process received EVPN type-3 route (advertise or withdraw).
|
|
|
|
*/
|
|
|
|
static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct attr *attr, uint8_t *pfx, int psize,
|
|
|
|
uint32_t addpath_id)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct prefix_rd prd;
|
|
|
|
struct prefix_evpn p;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t ipaddr_len;
|
2018-04-06 15:52:48 +02:00
|
|
|
uint32_t eth_tag;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Type-3 route should be either 17 or 29 bytes: RD (8), Eth Tag (4),
|
|
|
|
* IP len (1) and IP (4 or 16).
|
|
|
|
*/
|
|
|
|
if (psize != 17 && psize != 29) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
2018-09-13 21:38:57 +02:00
|
|
|
"%u:%s - Rx EVPN Type-3 NLRI with invalid length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2017-05-15 23:34:04 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-04 04:28:50 +01:00
|
|
|
/* If PMSI is present, log if it is anything other than IR.
|
|
|
|
* Note: We just simply ignore the values as it is not clear if
|
|
|
|
* doing anything else is better.
|
|
|
|
*/
|
|
|
|
if (attr &&
|
|
|
|
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
|
2020-11-02 16:52:40 +01:00
|
|
|
enum pta_type pmsi_tnl_type = bgp_attr_get_pmsi_tnl_type(attr);
|
|
|
|
|
|
|
|
if (pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL
|
|
|
|
&& pmsi_tnl_type != PMSI_TNLTYPE_PIM_SM) {
|
|
|
|
flog_warn(
|
|
|
|
EC_BGP_EVPN_PMSI_PRESENT,
|
|
|
|
"%u:%s - Rx EVPN Type-3 NLRI with unsupported PTA %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, pmsi_tnl_type);
|
2018-03-04 04:28:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Make prefix_rd */
|
|
|
|
prd.family = AF_UNSPEC;
|
|
|
|
prd.prefixlen = 64;
|
|
|
|
memcpy(&prd.val, pfx, 8);
|
|
|
|
pfx += 8;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Make EVPN prefix. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&p, 0, sizeof(p));
|
2017-08-08 16:16:12 +02:00
|
|
|
p.family = AF_EVPN;
|
2018-04-14 00:01:12 +02:00
|
|
|
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
|
2017-05-15 23:34:04 +02:00
|
|
|
p.prefix.route_type = BGP_EVPN_IMET_ROUTE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-06 15:52:48 +02:00
|
|
|
/* Copy Ethernet Tag */
|
|
|
|
memcpy(ð_tag, pfx, 4);
|
2018-04-14 00:37:30 +02:00
|
|
|
p.prefix.imet_addr.eth_tag = ntohl(eth_tag);
|
2017-05-15 23:34:04 +02:00
|
|
|
pfx += 4;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Get the IP. */
|
|
|
|
ipaddr_len = *pfx++;
|
|
|
|
if (ipaddr_len == IPV4_MAX_BITLEN) {
|
2018-04-14 00:37:30 +02:00
|
|
|
p.prefix.imet_addr.ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&p.prefix.imet_addr.ip.ip.addr, pfx, IPV4_MAX_BYTELEN);
|
2017-05-15 23:34:04 +02:00
|
|
|
} else {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_ROUTE_INVALID,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, ipaddr_len);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Process the route. */
|
|
|
|
if (attr)
|
2023-01-30 22:02:23 +01:00
|
|
|
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
|
|
|
|
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL,
|
|
|
|
0, 0, NULL);
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2023-02-21 10:35:59 +01:00
|
|
|
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
|
|
|
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
|
|
|
|
NULL);
|
2023-01-30 22:02:23 +01:00
|
|
|
return 0;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process received EVPN type-5 route (advertise or withdraw).
|
|
|
|
*/
|
|
|
|
static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct attr *attr, uint8_t *pfx, int psize,
|
2019-02-25 19:07:05 +01:00
|
|
|
uint32_t addpath_id)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct prefix_rd prd;
|
|
|
|
struct prefix_evpn p;
|
|
|
|
struct bgp_route_evpn evpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t ippfx_len;
|
|
|
|
uint32_t eth_tag;
|
2017-11-21 11:42:05 +01:00
|
|
|
mpls_label_t label; /* holds the VNI as in the packet */
|
2021-01-11 06:40:42 +01:00
|
|
|
bool is_valid_update = true;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Type-5 route should be 34 or 58 bytes:
|
|
|
|
* RD (8), ESI (10), Eth Tag (4), IP len (1), IP (4 or 16),
|
|
|
|
* GW (4 or 16) and VNI (3).
|
|
|
|
* Note that the IP and GW should both be IPv4 or both IPv6.
|
|
|
|
*/
|
|
|
|
if (psize != 34 && psize != 58) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
2018-09-13 21:38:57 +02:00
|
|
|
"%u:%s - Rx EVPN Type-5 NLRI with invalid length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2017-05-15 23:34:04 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Make prefix_rd */
|
|
|
|
prd.family = AF_UNSPEC;
|
|
|
|
prd.prefixlen = 64;
|
|
|
|
memcpy(&prd.val, pfx, 8);
|
|
|
|
pfx += 8;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Make EVPN prefix. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&p, 0, sizeof(p));
|
2017-08-08 16:16:12 +02:00
|
|
|
p.family = AF_EVPN;
|
2018-04-14 00:01:12 +02:00
|
|
|
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
|
2017-05-15 23:34:04 +02:00
|
|
|
p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Additional information outside of prefix - ESI and GW IP */
|
|
|
|
memset(&evpn, 0, sizeof(evpn));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-01-11 06:40:42 +01:00
|
|
|
/* Fetch ESI overlay index */
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
if (attr)
|
2021-01-11 06:40:42 +01:00
|
|
|
memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t));
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
pfx += ESI_BYTES;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Fetch Ethernet Tag. */
|
|
|
|
memcpy(ð_tag, pfx, 4);
|
2018-04-14 00:37:30 +02:00
|
|
|
p.prefix.prefix_addr.eth_tag = ntohl(eth_tag);
|
2017-05-15 23:34:04 +02:00
|
|
|
pfx += 4;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Fetch IP prefix length. */
|
|
|
|
ippfx_len = *pfx++;
|
|
|
|
if (ippfx_len > IPV6_MAX_BITLEN) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_ROUTE_INVALID,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, ippfx_len);
|
|
|
|
return -1;
|
|
|
|
}
|
2018-04-14 00:37:30 +02:00
|
|
|
p.prefix.prefix_addr.ip_prefix_length = ippfx_len;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Determine IPv4 or IPv6 prefix */
|
|
|
|
/* Since the address and GW are from the same family, this just becomes
|
|
|
|
* a simple check on the total size.
|
|
|
|
*/
|
|
|
|
if (psize == 34) {
|
2018-04-14 00:37:30 +02:00
|
|
|
SET_IPADDR_V4(&p.prefix.prefix_addr.ip);
|
|
|
|
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4);
|
2017-05-15 23:34:04 +02:00
|
|
|
pfx += 4;
|
2022-01-19 21:06:45 +01:00
|
|
|
SET_IPADDR_V4(&evpn.gw_ip);
|
|
|
|
memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4);
|
2017-05-15 23:34:04 +02:00
|
|
|
pfx += 4;
|
|
|
|
} else {
|
2018-04-14 00:37:30 +02:00
|
|
|
SET_IPADDR_V6(&p.prefix.prefix_addr.ip);
|
2021-07-01 22:29:26 +02:00
|
|
|
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx,
|
|
|
|
IPV6_MAX_BYTELEN);
|
|
|
|
pfx += IPV6_MAX_BYTELEN;
|
2022-01-19 21:06:45 +01:00
|
|
|
SET_IPADDR_V6(&evpn.gw_ip);
|
|
|
|
memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN);
|
2021-07-01 22:29:26 +02:00
|
|
|
pfx += IPV6_MAX_BYTELEN;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-21 11:42:05 +01:00
|
|
|
/* Get the VNI (in MPLS label field). Stored as bytes here. */
|
|
|
|
memset(&label, 0, sizeof(label));
|
|
|
|
memcpy(&label, pfx, BGP_LABEL_BYTES);
|
2018-01-24 23:03:05 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If in future, we are required to access additional fields,
|
2018-02-05 22:24:57 +01:00
|
|
|
* we MUST increment pfx by BGP_LABEL_BYTES in before reading the next
|
|
|
|
* field
|
2018-01-24 23:03:05 +01:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-01-11 06:40:42 +01:00
|
|
|
/*
|
|
|
|
* An update containing a non-zero gateway IP and a non-zero ESI
|
|
|
|
* at the same time is should be treated as withdraw
|
|
|
|
*/
|
2022-01-19 21:06:45 +01:00
|
|
|
if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) &&
|
|
|
|
!ipaddr_is_zero(&evpn.gw_ip)) {
|
2021-01-11 06:40:42 +01:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
|
|
|
"%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.",
|
|
|
|
peer->host);
|
|
|
|
is_valid_update = false;
|
|
|
|
} else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id))
|
|
|
|
evpn.type = OVERLAY_INDEX_ESI;
|
2022-01-19 21:06:45 +01:00
|
|
|
else if (!ipaddr_is_zero(&evpn.gw_ip))
|
2021-01-11 06:40:42 +01:00
|
|
|
evpn.type = OVERLAY_INDEX_GATEWAY_IP;
|
2020-02-10 20:38:27 +01:00
|
|
|
if (attr) {
|
2022-01-19 21:06:45 +01:00
|
|
|
if (is_zero_mac(&attr->rmac) &&
|
|
|
|
!bgp_evpn_is_esi_valid(&evpn.eth_s_id) &&
|
|
|
|
ipaddr_is_zero(&evpn.gw_ip) && label == 0) {
|
2021-01-11 06:40:42 +01:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
|
|
|
"%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero",
|
|
|
|
peer->host);
|
2020-02-10 20:38:27 +01:00
|
|
|
is_valid_update = false;
|
2021-01-11 06:40:42 +01:00
|
|
|
}
|
2020-02-10 20:38:27 +01:00
|
|
|
|
|
|
|
if (is_mcast_mac(&attr->rmac) || is_bcast_mac(&attr->rmac))
|
|
|
|
is_valid_update = false;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Process the route. */
|
2021-01-11 06:40:42 +01:00
|
|
|
if (attr && is_valid_update)
|
2023-01-30 22:02:23 +01:00
|
|
|
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
|
|
|
|
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
|
|
|
|
&label, 1, 0, &evpn);
|
2021-01-11 06:40:42 +01:00
|
|
|
else {
|
|
|
|
if (!is_valid_update) {
|
|
|
|
char attr_str[BUFSIZ] = {0};
|
|
|
|
|
|
|
|
bgp_dump_attr(attr, attr_str, BUFSIZ);
|
|
|
|
zlog_warn(
|
|
|
|
"Invalid update from peer %s vrf %u prefix %pFX attr %s - treat as withdraw",
|
|
|
|
peer->hostname, peer->bgp->vrf_id, &p,
|
|
|
|
attr_str);
|
|
|
|
}
|
2023-02-21 10:35:59 +01:00
|
|
|
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
|
|
|
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1,
|
|
|
|
&evpn);
|
2021-01-11 06:40:42 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-01-30 22:02:23 +01:00
|
|
|
return 0;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-24 12:58:08 +01:00
|
|
|
static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
|
|
|
|
const struct prefix_rd *prd,
|
2024-02-26 18:11:09 +01:00
|
|
|
mpls_label_t *label, uint8_t num_labels,
|
2020-03-24 12:58:08 +01:00
|
|
|
struct attr *attr)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
int len;
|
|
|
|
char temp[16];
|
2020-03-24 12:58:08 +01:00
|
|
|
const struct evpn_addr *p_evpn_p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-05-11 12:10:23 +02:00
|
|
|
memset(&temp, 0, sizeof(temp));
|
2017-08-08 16:16:12 +02:00
|
|
|
if (p->family != AF_EVPN)
|
2017-05-15 23:34:04 +02:00
|
|
|
return;
|
|
|
|
p_evpn_p = &(p->u.prefix_evpn);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-06 23:32:32 +01:00
|
|
|
/* len denites the total len of IP and GW-IP in the route
|
2017-12-27 20:47:10 +01:00
|
|
|
IP and GW-IP have to be both ipv4 or ipv6
|
|
|
|
*/
|
2018-04-14 00:37:30 +02:00
|
|
|
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
|
2017-11-06 23:32:32 +01:00
|
|
|
len = 8; /* IP and GWIP are both ipv4 */
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2017-11-06 23:32:32 +01:00
|
|
|
len = 32; /* IP and GWIP are both ipv6 */
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
|
|
|
|
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
|
|
|
|
stream_put(s, prd->val, 8);
|
2021-01-11 03:32:34 +01:00
|
|
|
if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI)
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
stream_put(s, &attr->esi, sizeof(esi_t));
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
stream_put(s, 0, sizeof(esi_t));
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_putl(s, p_evpn_p->prefix_addr.eth_tag);
|
|
|
|
stream_putc(s, p_evpn_p->prefix_addr.ip_prefix_length);
|
|
|
|
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
|
|
|
|
stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr);
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16);
|
2021-01-11 03:32:34 +01:00
|
|
|
if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
|
2020-11-02 18:55:45 +01:00
|
|
|
const struct bgp_route_evpn *evpn_overlay =
|
|
|
|
bgp_attr_get_evpn_overlay(attr);
|
|
|
|
|
2018-04-14 00:37:30 +02:00
|
|
|
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
|
2022-01-19 21:06:45 +01:00
|
|
|
stream_put_ipv4(s,
|
|
|
|
evpn_overlay->gw_ip.ipaddr_v4.s_addr);
|
2017-05-15 23:34:04 +02:00
|
|
|
else
|
2022-01-19 21:06:45 +01:00
|
|
|
stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16);
|
2017-05-15 23:34:04 +02:00
|
|
|
} else {
|
2018-04-14 00:37:30 +02:00
|
|
|
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
|
2017-05-15 23:34:04 +02:00
|
|
|
stream_put_ipv4(s, 0);
|
|
|
|
else
|
|
|
|
stream_put(s, &temp, 16);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-21 11:42:05 +01:00
|
|
|
if (num_labels)
|
2017-05-15 23:34:04 +02:00
|
|
|
stream_put(s, label, 3);
|
|
|
|
else
|
|
|
|
stream_put3(s, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void cleanup_vni_on_disable(struct hash_bucket *bucket, struct bgp *bgp)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Remove EVPN routes and schedule for processing. */
|
|
|
|
delete_routes_for_vni(bgp, vpn);
|
|
|
|
|
|
|
|
/* Clear "live" flag and see if hash needs to be freed. */
|
|
|
|
UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE);
|
|
|
|
if (!is_vni_configured(vpn))
|
|
|
|
bgp_evpn_free(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free a VNI entry; iterator function called during cleanup.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void free_vni_entry(struct hash_bucket *bucket, struct bgp *bgp)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
delete_all_vni_routes(bgp, vpn);
|
|
|
|
bgp_evpn_free(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2017-10-09 03:34:29 +02:00
|
|
|
/*
|
|
|
|
* Derive AUTO import RT for BGP VRF - L3VNI
|
|
|
|
*/
|
|
|
|
static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl, true);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
|
|
|
/* Map RT to VRF */
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
2021-02-25 22:27:07 +01:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
if (!bgp_evpn)
|
2017-10-10 03:12:05 +02:00
|
|
|
return;
|
2021-02-25 22:27:07 +01:00
|
|
|
|
2017-10-10 03:12:05 +02:00
|
|
|
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete AUTO import RT from BGP VRF - L3VNI
|
|
|
|
*/
|
|
|
|
static void evpn_auto_rt_import_delete_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2021-02-17 22:11:49 +01:00
|
|
|
evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl,
|
|
|
|
true);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Derive AUTO export RT for BGP VRF - L3VNI
|
|
|
|
*/
|
|
|
|
static void evpn_auto_rt_export_add_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl, true);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete AUTO export RT from BGP VRF - L3VNI
|
|
|
|
*/
|
|
|
|
static void evpn_auto_rt_export_delete_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2021-02-17 22:11:49 +01:00
|
|
|
evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl,
|
|
|
|
true);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
2017-10-09 11:06:34 +02:00
|
|
|
static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-09 11:06:34 +02:00
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct bgpevpn *vpn = NULL;
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
2017-10-09 11:06:34 +02:00
|
|
|
return;
|
|
|
|
|
2017-11-04 00:45:55 +01:00
|
|
|
/* update all type-5 routes */
|
|
|
|
update_advertise_vrf_routes(bgp_vrf);
|
|
|
|
|
|
|
|
/* update all type-2 routes */
|
2017-10-09 11:06:34 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
|
2019-03-06 19:10:02 +01:00
|
|
|
update_routes_for_vni(bgp_evpn, vpn);
|
2017-10-09 11:06:34 +02:00
|
|
|
}
|
|
|
|
|
2017-04-12 11:24:07 +02:00
|
|
|
/*
|
|
|
|
* Handle autort change for a given VNI.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp)
|
2017-04-12 11:24:07 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = bucket->data;
|
2017-04-12 11:24:07 +02:00
|
|
|
|
|
|
|
if (!is_import_rt_configured(vpn)) {
|
|
|
|
if (is_vni_live(vpn))
|
|
|
|
bgp_evpn_uninstall_routes(bgp, vpn);
|
|
|
|
bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
|
|
|
|
list_delete_all_node(vpn->import_rtl);
|
|
|
|
bgp_evpn_derive_auto_rt_import(bgp, vpn);
|
|
|
|
if (is_vni_live(vpn))
|
|
|
|
bgp_evpn_install_routes(bgp, vpn);
|
|
|
|
}
|
|
|
|
if (!is_export_rt_configured(vpn)) {
|
|
|
|
list_delete_all_node(vpn->export_rtl);
|
|
|
|
bgp_evpn_derive_auto_rt_export(bgp, vpn);
|
|
|
|
if (is_vni_live(vpn))
|
|
|
|
bgp_evpn_handle_export_rt_change(bgp, vpn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 14:42:30 +02:00
|
|
|
/*
|
|
|
|
* Handle autort change for L3VNI.
|
|
|
|
*/
|
|
|
|
static void update_autort_l3vni(struct bgp *bgp)
|
|
|
|
{
|
|
|
|
if ((CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
|
|
|
|
&& (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
|
|
|
|
if (is_l3vni_live(bgp))
|
|
|
|
uninstall_routes_for_vrf(bgp);
|
|
|
|
|
|
|
|
/* Cleanup the RT to VRF mapping */
|
|
|
|
bgp_evpn_unmap_vrf_from_its_rts(bgp);
|
|
|
|
|
|
|
|
/* Remove auto generated RT */
|
|
|
|
evpn_auto_rt_import_delete_for_vrf(bgp);
|
|
|
|
|
|
|
|
list_delete_all_node(bgp->vrf_import_rtl);
|
|
|
|
|
|
|
|
/* Map auto derive or configured RTs */
|
|
|
|
evpn_auto_rt_import_add_for_vrf(bgp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
|
|
|
|
list_delete_all_node(bgp->vrf_export_rtl);
|
|
|
|
|
|
|
|
evpn_auto_rt_export_delete_for_vrf(bgp);
|
|
|
|
|
|
|
|
evpn_auto_rt_export_add_for_vrf(bgp);
|
|
|
|
|
|
|
|
if (is_l3vni_live(bgp))
|
|
|
|
bgp_evpn_map_vrf_to_its_rts(bgp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_l3vni_live(bgp))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* advertise type-5 routes if needed */
|
|
|
|
update_advertise_vrf_routes(bgp);
|
|
|
|
|
|
|
|
/* install all remote routes belonging to this l3vni
|
|
|
|
* into corresponding vrf
|
|
|
|
*/
|
|
|
|
install_routes_for_vrf(bgp);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Public functions.
|
|
|
|
*/
|
|
|
|
|
2017-11-09 11:37:09 +01:00
|
|
|
/* withdraw type-5 route corresponding to ip prefix */
|
2020-03-22 19:50:46 +01:00
|
|
|
void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, const struct prefix *p,
|
2017-11-09 11:37:09 +01:00
|
|
|
afi_t afi, safi_t safi)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct prefix_evpn evp;
|
|
|
|
|
2017-11-20 06:47:04 +01:00
|
|
|
build_type5_prefix_from_ip_prefix(&evp, p);
|
2017-11-09 11:37:09 +01:00
|
|
|
ret = delete_evpn_type5_route(bgp_vrf, &evp);
|
2020-10-18 13:33:54 +02:00
|
|
|
if (ret)
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_ROUTE_DELETE,
|
2020-10-18 13:33:54 +02:00
|
|
|
"%u failed to delete type-5 route for prefix %pFX in vrf %s",
|
|
|
|
bgp_vrf->vrf_id, p, vrf_id_to_name(bgp_vrf->vrf_id));
|
2017-11-09 11:37:09 +01:00
|
|
|
}
|
|
|
|
|
2017-10-27 23:15:45 +02:00
|
|
|
/* withdraw all type-5 routes for an address family */
|
|
|
|
void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
|
|
|
|
{
|
|
|
|
struct bgp_table *table = NULL;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest = NULL;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2017-11-05 02:24:02 +01:00
|
|
|
table = bgp_vrf->rib[afi][safi];
|
2020-03-27 00:11:58 +01:00
|
|
|
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
|
2019-02-28 17:01:38 +01:00
|
|
|
/* Only care about "selected" routes. Also ensure that
|
|
|
|
* these are routes that are injectable into EVPN.
|
|
|
|
*/
|
2018-01-19 18:29:49 +01:00
|
|
|
/* TODO: Support for AddPath for EVPN. */
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
2019-02-28 17:01:38 +01:00
|
|
|
&& is_route_injectable_into_evpn(pi)) {
|
2020-03-22 05:02:18 +01:00
|
|
|
bgp_evpn_withdraw_type5_route(
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_vrf, bgp_dest_get_prefix(dest), afi,
|
2020-03-22 05:02:18 +01:00
|
|
|
safi);
|
2018-01-19 18:29:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-09 11:37:09 +01:00
|
|
|
}
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2018-11-29 04:18:08 +01:00
|
|
|
/*
|
|
|
|
* evpn - enable advertisement of default g/w
|
|
|
|
*/
|
|
|
|
void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf, afi_t afi,
|
|
|
|
safi_t safi, bool add)
|
|
|
|
{
|
|
|
|
struct prefix ip_prefix;
|
|
|
|
|
|
|
|
/* form the default prefix 0.0.0.0/0 */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&ip_prefix, 0, sizeof(ip_prefix));
|
2018-11-29 04:18:08 +01:00
|
|
|
ip_prefix.family = afi2family(afi);
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
|
|
|
|
NULL, afi, safi);
|
|
|
|
} else {
|
|
|
|
bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
|
|
|
|
afi, safi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-04 18:52:54 +01:00
|
|
|
/*
|
|
|
|
* Advertise IP prefix as type-5 route. The afi/safi and src_attr passed
|
|
|
|
* to this function correspond to those of the source IP prefix (best
|
|
|
|
* path in the case of the attr. In the case of a local prefix (when we
|
|
|
|
* are advertising local subnets), the src_attr will be NULL.
|
|
|
|
*/
|
2020-03-22 19:50:46 +01:00
|
|
|
void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, const struct prefix *p,
|
2017-12-04 18:52:54 +01:00
|
|
|
struct attr *src_attr, afi_t afi,
|
2017-11-09 11:37:09 +01:00
|
|
|
safi_t safi)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct prefix_evpn evp;
|
2018-05-18 03:32:21 +02:00
|
|
|
|
2017-11-20 06:47:04 +01:00
|
|
|
build_type5_prefix_from_ip_prefix(&evp, p);
|
2021-01-11 03:32:34 +01:00
|
|
|
ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr, afi, safi);
|
2017-12-04 18:52:54 +01:00
|
|
|
if (ret)
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_CREATE,
|
2020-10-18 13:33:54 +02:00
|
|
|
"%u: Failed to create type-5 route for prefix %pFX",
|
|
|
|
bgp_vrf->vrf_id, p);
|
2017-10-27 23:15:45 +02:00
|
|
|
}
|
|
|
|
|
2017-12-04 18:52:54 +01:00
|
|
|
/* Inject all prefixes of a particular address-family (currently, IPv4 or
|
|
|
|
* IPv6 unicast) into EVPN as type-5 routes. This is invoked when the
|
|
|
|
* advertisement is enabled.
|
|
|
|
*/
|
2017-10-27 23:15:45 +02:00
|
|
|
void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
2017-11-05 02:24:02 +01:00
|
|
|
safi_t safi)
|
2017-10-27 23:15:45 +02:00
|
|
|
{
|
|
|
|
struct bgp_table *table = NULL;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest = NULL;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2017-10-27 23:15:45 +02:00
|
|
|
|
2017-11-05 02:24:02 +01:00
|
|
|
table = bgp_vrf->rib[afi][safi];
|
2020-03-27 00:11:58 +01:00
|
|
|
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
|
2017-12-04 18:52:54 +01:00
|
|
|
/* Need to identify the "selected" route entry to use its
|
2019-02-28 17:01:38 +01:00
|
|
|
* attribute. Also, ensure that the route is injectable
|
|
|
|
* into EVPN.
|
2017-12-04 18:52:54 +01:00
|
|
|
* TODO: Support for AddPath for EVPN.
|
|
|
|
*/
|
2020-03-27 00:11:58 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
|
2018-10-03 02:43:07 +02:00
|
|
|
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
2019-02-28 17:01:38 +01:00
|
|
|
&& is_route_injectable_into_evpn(pi)) {
|
2018-02-09 10:09:20 +01:00
|
|
|
|
|
|
|
/* apply the route-map */
|
|
|
|
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
route_map_result_t ret;
|
2020-03-18 23:40:04 +01:00
|
|
|
struct bgp_path_info tmp_pi;
|
|
|
|
struct bgp_path_info_extra tmp_pie;
|
|
|
|
struct attr tmp_attr;
|
|
|
|
|
|
|
|
tmp_attr = *pi->attr;
|
|
|
|
|
|
|
|
/* Fill temp path_info */
|
2020-03-27 00:11:58 +01:00
|
|
|
prep_for_rmap_apply(&tmp_pi, &tmp_pie,
|
|
|
|
dest, pi, pi->peer,
|
|
|
|
&tmp_attr);
|
2020-03-18 23:40:04 +01:00
|
|
|
|
|
|
|
RESET_FLAG(tmp_attr.rmap_change_flags);
|
2018-02-09 10:09:20 +01:00
|
|
|
|
|
|
|
ret = route_map_apply(
|
|
|
|
bgp_vrf->adv_cmd_rmap[afi][safi]
|
|
|
|
.map,
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_get_prefix(dest),
|
2020-11-14 01:35:20 +01:00
|
|
|
&tmp_pi);
|
2020-03-18 23:40:04 +01:00
|
|
|
if (ret == RMAP_DENYMATCH) {
|
|
|
|
bgp_attr_flush(&tmp_attr);
|
2018-02-09 10:09:20 +01:00
|
|
|
continue;
|
2020-03-18 23:40:04 +01:00
|
|
|
}
|
|
|
|
bgp_evpn_advertise_type5_route(
|
2020-03-22 05:02:18 +01:00
|
|
|
bgp_vrf,
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_get_prefix(dest),
|
2020-03-22 05:02:18 +01:00
|
|
|
&tmp_attr, afi, safi);
|
2020-03-18 23:40:04 +01:00
|
|
|
} else
|
|
|
|
bgp_evpn_advertise_type5_route(
|
2020-03-22 05:02:18 +01:00
|
|
|
bgp_vrf,
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp_dest_get_prefix(dest),
|
2020-03-22 05:02:18 +01:00
|
|
|
pi->attr, afi, safi);
|
2017-12-04 18:52:54 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-11-20 06:47:04 +01:00
|
|
|
}
|
2017-10-27 23:15:45 +02:00
|
|
|
}
|
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
static void rt_list_remove_node(struct list *rt_list,
|
|
|
|
struct ecommunity *ecomdel, bool is_l3)
|
2017-10-09 03:34:29 +02:00
|
|
|
{
|
2021-02-17 22:11:49 +01:00
|
|
|
struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
|
|
|
|
struct vrf_route_target *l3rt = NULL;
|
|
|
|
struct ecommunity *ecom = NULL;
|
|
|
|
|
|
|
|
if (is_l3) {
|
|
|
|
for (ALL_LIST_ELEMENTS(rt_list, node, nnode, l3rt)) {
|
|
|
|
if (ecommunity_match(l3rt->ecom, ecomdel)) {
|
|
|
|
evpn_vrf_rt_del(l3rt);
|
|
|
|
node_to_del = node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (ALL_LIST_ELEMENTS(rt_list, node, nnode, ecom)) {
|
|
|
|
if (ecommunity_match(ecom, ecomdel)) {
|
|
|
|
ecommunity_free(&ecom);
|
|
|
|
node_to_del = node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
if (node_to_del)
|
|
|
|
list_delete_node(rt_list, node_to_del);
|
|
|
|
}
|
|
|
|
|
|
|
|
void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl,
|
|
|
|
bool is_l3)
|
|
|
|
{
|
|
|
|
struct ecommunity *ecom_auto;
|
2017-10-09 03:34:29 +02:00
|
|
|
struct ecommunity_val eval;
|
|
|
|
|
2017-04-12 11:24:07 +02:00
|
|
|
if (bgp->advertise_autort_rfc8365)
|
|
|
|
vni |= EVPN_AUTORT_VXLAN;
|
2021-02-25 22:27:07 +01:00
|
|
|
|
2023-04-10 21:40:30 +02:00
|
|
|
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
|
|
|
ecom_auto = ecommunity_new();
|
2020-03-24 21:50:20 +01:00
|
|
|
ecommunity_add_val(ecom_auto, &eval, false, false);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
rt_list_remove_node(rtl, ecom_auto, is_l3);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
|
|
|
ecommunity_free(&ecom_auto);
|
|
|
|
}
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
static void evpn_vrf_rt_routes_map(struct bgp *bgp_vrf)
|
2017-10-09 03:34:29 +02:00
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
/* map VRFs to its RTs and install routes matching this new RT */
|
|
|
|
if (is_l3vni_live(bgp_vrf)) {
|
|
|
|
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
|
|
|
install_routes_for_vrf(bgp_vrf);
|
|
|
|
}
|
|
|
|
}
|
2021-02-17 22:11:49 +01:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
static void evpn_vrf_rt_routes_unmap(struct bgp *bgp_vrf)
|
2017-10-09 03:34:29 +02:00
|
|
|
{
|
2017-10-13 13:10:03 +02:00
|
|
|
/* uninstall routes from vrf */
|
2019-08-19 08:07:59 +02:00
|
|
|
if (is_l3vni_live(bgp_vrf))
|
|
|
|
uninstall_routes_for_vrf(bgp_vrf);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
|
|
|
/* Cleanup the RT to VRF mapping */
|
|
|
|
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
2021-02-25 22:27:07 +01:00
|
|
|
}
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
static bool rt_list_has_cfgd_rt(struct list *rt_list)
|
|
|
|
{
|
|
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
struct vrf_route_target *l3rt = NULL;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(rt_list, node, nnode, l3rt)) {
|
|
|
|
if (!CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unconfigure_import_rt_for_vrf_fini(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
if (!bgp_vrf->vrf_import_rtl)
|
|
|
|
return; /* this should never fail */
|
|
|
|
|
|
|
|
if (!is_l3vni_live(bgp_vrf))
|
|
|
|
return; /* Nothing to do if no vni */
|
|
|
|
|
|
|
|
/* fall back to auto-generated RT if this was the last RT */
|
|
|
|
if (list_isempty(bgp_vrf->vrf_import_rtl))
|
|
|
|
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unconfigure_export_rt_for_vrf_fini(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!bgp_vrf->vrf_export_rtl)
|
|
|
|
return; /* this should never fail */
|
|
|
|
|
|
|
|
if (!is_l3vni_live(bgp_vrf))
|
|
|
|
return; /* Nothing to do if no vni */
|
|
|
|
|
|
|
|
/* fall back to auto-generated RT if this was the last RT */
|
|
|
|
if (list_isempty(bgp_vrf->vrf_export_rtl))
|
|
|
|
evpn_auto_rt_export_add_for_vrf(bgp_vrf);
|
|
|
|
|
|
|
|
bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
|
|
|
struct ecommunity *ecomadd,
|
|
|
|
bool is_wildcard)
|
|
|
|
{
|
|
|
|
struct vrf_route_target *newrt;
|
|
|
|
|
|
|
|
newrt = evpn_vrf_rt_new(ecomadd);
|
|
|
|
|
|
|
|
if (is_wildcard)
|
|
|
|
SET_FLAG(newrt->flags, BGP_VRF_RT_WILD);
|
|
|
|
|
|
|
|
evpn_vrf_rt_routes_unmap(bgp_vrf);
|
|
|
|
|
|
|
|
/* Remove auto generated RT if not configured */
|
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
|
|
|
|
evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
|
|
|
/* Add the newly configured RT to RT list */
|
2021-02-17 22:11:49 +01:00
|
|
|
listnode_add_sort(bgp_vrf->vrf_import_rtl, newrt);
|
2021-02-25 22:27:07 +01:00
|
|
|
|
2017-10-09 03:34:29 +02:00
|
|
|
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
evpn_vrf_rt_routes_map(bgp_vrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
|
|
|
|
return; /* Already configured */
|
|
|
|
|
|
|
|
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD);
|
|
|
|
|
|
|
|
if (!is_l3vni_live(bgp_vrf))
|
|
|
|
return; /* Wait for VNI before adding rts */
|
|
|
|
|
|
|
|
evpn_vrf_rt_routes_unmap(bgp_vrf);
|
|
|
|
|
|
|
|
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
|
|
|
|
|
|
|
|
evpn_vrf_rt_routes_map(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
|
|
|
struct ecommunity *ecomdel)
|
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
|
|
|
|
return; /* Already un-configured */
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
evpn_vrf_rt_routes_unmap(bgp_vrf);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
/* Remove rt */
|
|
|
|
rt_list_remove_node(bgp_vrf->vrf_import_rtl, ecomdel, true);
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
if (!rt_list_has_cfgd_rt(bgp_vrf->vrf_import_rtl))
|
2017-10-09 03:34:29 +02:00
|
|
|
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
unconfigure_import_rt_for_vrf_fini(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
evpn_vrf_rt_routes_map(bgp_vrf);
|
|
|
|
}
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
|
|
|
|
return; /* Already un-configured */
|
|
|
|
|
|
|
|
evpn_vrf_rt_routes_unmap(bgp_vrf);
|
|
|
|
|
|
|
|
/* remove auto-generated RT */
|
|
|
|
evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
|
|
|
|
|
|
|
|
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD);
|
|
|
|
|
|
|
|
unconfigure_import_rt_for_vrf_fini(bgp_vrf);
|
|
|
|
|
|
|
|
evpn_vrf_rt_routes_map(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
|
|
|
struct ecommunity *ecomadd)
|
|
|
|
{
|
2021-02-17 22:11:49 +01:00
|
|
|
struct vrf_route_target *newrt;
|
|
|
|
|
|
|
|
newrt = evpn_vrf_rt_new(ecomadd);
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
/* Remove auto generated RT if not configured */
|
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
|
|
|
|
evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
|
|
|
/* Add the new RT to the RT list */
|
2021-02-17 22:11:49 +01:00
|
|
|
listnode_add_sort(bgp_vrf->vrf_export_rtl, newrt);
|
2021-02-25 22:27:07 +01:00
|
|
|
|
2017-10-09 03:34:29 +02:00
|
|
|
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
|
|
|
|
|
2020-06-23 01:38:48 +02:00
|
|
|
if (is_l3vni_live(bgp_vrf))
|
|
|
|
bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
|
|
|
|
return; /* Already configured */
|
|
|
|
|
|
|
|
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD);
|
|
|
|
|
|
|
|
if (!is_l3vni_live(bgp_vrf))
|
|
|
|
return; /* Wait for VNI before adding rts */
|
|
|
|
|
|
|
|
evpn_auto_rt_export_add_for_vrf(bgp_vrf);
|
|
|
|
|
|
|
|
bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
|
|
|
|
}
|
|
|
|
|
2017-10-09 03:34:29 +02:00
|
|
|
void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
|
|
|
struct ecommunity *ecomdel)
|
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
|
|
|
|
return; /* Already un-configured */
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-17 22:11:49 +01:00
|
|
|
/* Remove rt */
|
|
|
|
rt_list_remove_node(bgp_vrf->vrf_export_rtl, ecomdel, true);
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
if (!rt_list_has_cfgd_rt(bgp_vrf->vrf_export_rtl))
|
2017-10-09 03:34:29 +02:00
|
|
|
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
unconfigure_export_rt_for_vrf_fini(bgp_vrf);
|
|
|
|
}
|
2018-06-01 03:32:37 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
void bgp_evpn_unconfigure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
|
|
|
|
return; /* Already un-configured */
|
2017-10-09 03:34:29 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
/* remove auto-generated RT */
|
|
|
|
evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
|
|
|
|
|
|
|
|
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD);
|
|
|
|
|
|
|
|
unconfigure_export_rt_for_vrf_fini(bgp_vrf);
|
2017-10-09 03:34:29 +02:00
|
|
|
}
|
|
|
|
|
2017-05-16 00:02:33 +02:00
|
|
|
/*
|
|
|
|
* Handle change to BGP router id. This is invoked twice by the change
|
|
|
|
* handler, first before the router id has been changed and then after
|
|
|
|
* the router id has been changed. The first invocation will result in
|
2017-10-26 01:49:18 +02:00
|
|
|
* local routes for all VNIs/VRF being deleted and withdrawn and the next
|
2017-05-16 00:02:33 +02:00
|
|
|
* will result in the routes being re-advertised.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
|
|
|
|
{
|
2019-04-18 09:17:57 +02:00
|
|
|
struct listnode *node;
|
|
|
|
struct bgp *bgp_vrf;
|
|
|
|
|
2017-10-26 01:49:18 +02:00
|
|
|
if (withdraw) {
|
|
|
|
|
|
|
|
/* delete and withdraw all the type-5 routes
|
2017-12-27 20:47:10 +01:00
|
|
|
stored in the global table for this vrf
|
|
|
|
*/
|
2017-11-02 10:15:14 +01:00
|
|
|
withdraw_router_id_vrf(bgp);
|
2017-10-26 01:49:18 +02:00
|
|
|
|
|
|
|
/* delete all the VNI routes (type-2/type-3) routes for all the
|
2017-12-27 20:47:10 +01:00
|
|
|
* L2-VNIs
|
|
|
|
*/
|
2017-05-16 00:02:33 +02:00
|
|
|
hash_iterate(bgp->vnihash,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-05-16 00:02:33 +02:00
|
|
|
void *))withdraw_router_id_vni,
|
|
|
|
bgp);
|
2019-04-18 09:17:57 +02:00
|
|
|
|
|
|
|
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
|
|
|
|
if (bgp_vrf->evpn_info->advertise_pip &&
|
|
|
|
(bgp_vrf->evpn_info->pip_ip_static.s_addr
|
|
|
|
== INADDR_ANY))
|
|
|
|
bgp_vrf->evpn_info->pip_ip.s_addr
|
|
|
|
= INADDR_ANY;
|
|
|
|
}
|
|
|
|
}
|
2017-10-26 01:49:18 +02:00
|
|
|
} else {
|
|
|
|
|
2019-04-18 09:17:57 +02:00
|
|
|
/* Assign new default instance router-id */
|
|
|
|
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
|
|
|
|
if (bgp_vrf->evpn_info->advertise_pip &&
|
|
|
|
(bgp_vrf->evpn_info->pip_ip_static.s_addr
|
|
|
|
== INADDR_ANY)) {
|
|
|
|
bgp_vrf->evpn_info->pip_ip =
|
|
|
|
bgp->router_id;
|
|
|
|
/* advertise type-5 routes with
|
|
|
|
* new nexthop
|
|
|
|
*/
|
|
|
|
update_advertise_vrf_routes(bgp_vrf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-26 01:49:18 +02:00
|
|
|
/* advertise all routes in the vrf as type-5 routes with the new
|
2017-12-27 20:47:10 +01:00
|
|
|
* RD
|
|
|
|
*/
|
2017-11-02 10:15:14 +01:00
|
|
|
update_router_id_vrf(bgp);
|
2017-10-26 01:49:18 +02:00
|
|
|
|
|
|
|
/* advertise all the VNI routes (type-2/type-3) routes with the
|
2017-12-27 20:47:10 +01:00
|
|
|
* new RD
|
|
|
|
*/
|
2017-05-16 00:02:33 +02:00
|
|
|
hash_iterate(bgp->vnihash,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-05-16 00:02:33 +02:00
|
|
|
void *))update_router_id_vni,
|
|
|
|
bgp);
|
2017-10-26 01:49:18 +02:00
|
|
|
}
|
2017-05-16 00:02:33 +02:00
|
|
|
}
|
|
|
|
|
2017-04-12 11:24:07 +02:00
|
|
|
/*
|
|
|
|
* Handle change to auto-RT algorithm - update and advertise local routes.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_handle_autort_change(struct bgp *bgp)
|
|
|
|
{
|
|
|
|
hash_iterate(bgp->vnihash,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-04-12 11:24:07 +02:00
|
|
|
void*))update_autort_vni,
|
|
|
|
bgp);
|
2021-08-17 14:42:30 +02:00
|
|
|
if (bgp->l3vni)
|
|
|
|
update_autort_l3vni(bgp);
|
2017-04-12 11:24:07 +02:00
|
|
|
}
|
|
|
|
|
2017-05-16 00:01:57 +02:00
|
|
|
/*
|
|
|
|
* Handle change to export RT - update and advertise local routes.
|
|
|
|
*/
|
|
|
|
int bgp_evpn_handle_export_rt_change(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
return update_routes_for_vni(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2017-10-26 01:49:18 +02:00
|
|
|
void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf, int withdraw)
|
|
|
|
{
|
|
|
|
if (withdraw)
|
|
|
|
delete_withdraw_vrf_routes(bgp_vrf);
|
|
|
|
else
|
|
|
|
update_advertise_vrf_routes(bgp_vrf);
|
|
|
|
}
|
|
|
|
|
2017-05-16 00:01:57 +02:00
|
|
|
/*
|
|
|
|
* Handle change to RD. This is invoked twice by the change handler,
|
|
|
|
* first before the RD has been changed and then after the RD has
|
|
|
|
* been changed. The first invocation will result in local routes
|
|
|
|
* of this VNI being deleted and withdrawn and the next will result
|
|
|
|
* in the routes being re-advertised.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
|
|
|
|
int withdraw)
|
|
|
|
{
|
|
|
|
if (withdraw)
|
|
|
|
delete_withdraw_vni_routes(bgp, vpn);
|
|
|
|
else
|
|
|
|
update_advertise_vni_routes(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* "mac-vrf soo" vty handler
|
2023-05-08 04:51:28 +02:00
|
|
|
* Handle change to the global MAC-VRF Site-of-Origin:
|
|
|
|
* - Unimport routes with new SoO from VNI/VRF
|
|
|
|
* - Import routes with old SoO into VNI/VRF
|
|
|
|
* - Update SoO on local VNI routes + re-advertise
|
|
|
|
*/
|
|
|
|
void bgp_evpn_handle_global_macvrf_soo_change(struct bgp *bgp,
|
|
|
|
struct ecommunity *new_soo)
|
|
|
|
{
|
|
|
|
struct ecommunity *old_soo;
|
|
|
|
|
|
|
|
old_soo = bgp->evpn_info->soo;
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* cleanup and bail out if old_soo == new_soo */
|
2023-05-08 04:51:28 +02:00
|
|
|
if (ecommunity_match(old_soo, new_soo)) {
|
|
|
|
ecommunity_free(&new_soo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* set new_soo */
|
2023-05-08 04:51:28 +02:00
|
|
|
bgp->evpn_info->soo = new_soo;
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* Unimport routes matching the new_soo */
|
|
|
|
bgp_filter_evpn_routes_upon_martian_change(bgp, BGP_MARTIAN_SOO);
|
|
|
|
|
|
|
|
/* Reimport routes with old_soo and !new_soo.
|
|
|
|
*/
|
|
|
|
bgp_reimport_evpn_routes_upon_martian_change(
|
|
|
|
bgp, BGP_MARTIAN_SOO, (void *)old_soo, (void *)new_soo);
|
|
|
|
|
|
|
|
/* Update locally originated routes for all L2VNIs */
|
2023-05-08 04:51:28 +02:00
|
|
|
hash_iterate(bgp->vnihash,
|
|
|
|
(void (*)(struct hash_bucket *,
|
2023-05-08 05:54:25 +02:00
|
|
|
void *))update_routes_for_vni_hash,
|
2023-05-08 04:51:28 +02:00
|
|
|
bgp);
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* clear old_soo */
|
|
|
|
ecommunity_free(&old_soo);
|
2023-05-08 04:51:28 +02:00
|
|
|
}
|
|
|
|
|
2017-05-16 00:01:57 +02:00
|
|
|
/*
|
|
|
|
* Install routes for this VNI. Invoked upon change to Import RT.
|
|
|
|
*/
|
|
|
|
int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
return install_routes_for_vni(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall all routes installed for this VNI. Invoked upon change
|
|
|
|
* to Import RT.
|
|
|
|
*/
|
|
|
|
int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
return uninstall_routes_for_vni(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:52:17 +02:00
|
|
|
/*
|
2017-11-21 11:42:05 +01:00
|
|
|
* TODO: Hardcoded for a maximum of 2 VNIs right now
|
2017-05-15 23:52:17 +02:00
|
|
|
*/
|
2024-02-26 18:11:09 +01:00
|
|
|
char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf,
|
2017-11-21 11:42:05 +01:00
|
|
|
int len)
|
2017-05-15 23:52:17 +02:00
|
|
|
{
|
2017-11-21 11:42:05 +01:00
|
|
|
vni_t vni1, vni2;
|
2017-05-15 23:52:17 +02:00
|
|
|
|
2017-11-21 11:42:05 +01:00
|
|
|
vni1 = label2vni(label);
|
|
|
|
if (num_labels == 2) {
|
|
|
|
vni2 = label2vni(label + 1);
|
|
|
|
snprintf(buf, len, "%u/%u", vni1, vni2);
|
|
|
|
} else
|
|
|
|
snprintf(buf, len, "%u", vni1);
|
2017-05-15 23:52:17 +02:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2017-07-21 02:42:20 +02:00
|
|
|
/*
|
|
|
|
* Function to convert evpn route to json format.
|
|
|
|
* NOTE: We don't use prefix2str as the output here is a bit different.
|
|
|
|
*/
|
2020-03-22 19:50:46 +01:00
|
|
|
void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json)
|
2017-07-21 02:42:20 +02:00
|
|
|
{
|
2017-08-14 06:52:04 +02:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[PREFIX2STR_BUFFER];
|
2019-09-11 09:01:39 +02:00
|
|
|
uint8_t family;
|
|
|
|
uint8_t prefixlen;
|
2017-07-21 02:42:20 +02:00
|
|
|
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!json)
|
|
|
|
return;
|
2017-07-21 02:42:20 +02:00
|
|
|
|
2019-09-11 09:01:39 +02:00
|
|
|
json_object_int_add(json, "routeType", p->prefix.route_type);
|
|
|
|
|
|
|
|
switch (p->prefix.route_type) {
|
|
|
|
case BGP_EVPN_MAC_IP_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
json_object_int_add(json, "ethTag",
|
2019-09-11 09:01:39 +02:00
|
|
|
p->prefix.macip_addr.eth_tag);
|
|
|
|
json_object_int_add(json, "macLen", 8 * ETH_ALEN);
|
|
|
|
json_object_string_add(json, "mac",
|
|
|
|
prefix_mac2str(&p->prefix.macip_addr.mac, buf1,
|
|
|
|
sizeof(buf1)));
|
|
|
|
|
|
|
|
if (!is_evpn_prefix_ipaddr_none(p)) {
|
|
|
|
family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET :
|
|
|
|
AF_INET6;
|
|
|
|
prefixlen = (family == AF_INET) ?
|
|
|
|
IPV4_MAX_BITLEN : IPV6_MAX_BITLEN;
|
|
|
|
inet_ntop(family, &p->prefix.macip_addr.ip.ip.addr,
|
|
|
|
buf2, PREFIX2STR_BUFFER);
|
|
|
|
json_object_int_add(json, "ipLen", prefixlen);
|
|
|
|
json_object_string_add(json, "ip", buf2);
|
|
|
|
}
|
|
|
|
break;
|
2017-08-07 22:57:44 +02:00
|
|
|
|
2019-09-11 09:01:39 +02:00
|
|
|
case BGP_EVPN_IMET_ROUTE:
|
|
|
|
json_object_int_add(json, "ethTag",
|
|
|
|
p->prefix.imet_addr.eth_tag);
|
|
|
|
family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
|
|
|
|
prefixlen = (family == AF_INET) ? IPV4_MAX_BITLEN :
|
|
|
|
IPV6_MAX_BITLEN;
|
|
|
|
inet_ntop(family, &p->prefix.imet_addr.ip.ip.addr, buf2,
|
|
|
|
PREFIX2STR_BUFFER);
|
|
|
|
json_object_int_add(json, "ipLen", prefixlen);
|
|
|
|
json_object_string_add(json, "ip", buf2);
|
|
|
|
break;
|
2017-08-07 22:57:44 +02:00
|
|
|
|
2019-09-11 09:01:39 +02:00
|
|
|
case BGP_EVPN_IP_PREFIX_ROUTE:
|
|
|
|
json_object_int_add(json, "ethTag",
|
|
|
|
p->prefix.prefix_addr.eth_tag);
|
|
|
|
family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
|
|
|
|
inet_ntop(family, &p->prefix.prefix_addr.ip.ip.addr,
|
|
|
|
buf2, sizeof(buf2));
|
|
|
|
json_object_int_add(json, "ipLen",
|
|
|
|
p->prefix.prefix_addr.ip_prefix_length);
|
|
|
|
json_object_string_add(json, "ip", buf2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2017-08-07 22:57:44 +02:00
|
|
|
}
|
2017-07-21 02:42:20 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Encode EVPN prefix in Update (MP_REACH)
|
|
|
|
*/
|
2020-03-24 12:58:08 +01:00
|
|
|
void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p,
|
|
|
|
const struct prefix_rd *prd, mpls_label_t *label,
|
2024-02-26 18:11:09 +01:00
|
|
|
uint8_t num_labels, struct attr *attr,
|
2022-01-27 08:51:59 +01:00
|
|
|
bool addpath_capable, uint32_t addpath_tx_id)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn *evp = (struct prefix_evpn *)p;
|
2017-11-21 11:42:05 +01:00
|
|
|
int len, ipa_len = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-27 08:51:59 +01:00
|
|
|
if (addpath_capable)
|
2017-05-15 23:34:04 +02:00
|
|
|
stream_putl(s, addpath_tx_id);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Route type */
|
|
|
|
stream_putc(s, evp->prefix.route_type);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
switch (evp->prefix.route_type) {
|
|
|
|
case BGP_EVPN_MAC_IP_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_v4(evp))
|
2017-05-15 23:34:04 +02:00
|
|
|
ipa_len = IPV4_MAX_BYTELEN;
|
2018-04-14 00:37:30 +02:00
|
|
|
else if (is_evpn_prefix_ipaddr_v6(evp))
|
2017-05-15 23:34:04 +02:00
|
|
|
ipa_len = IPV6_MAX_BYTELEN;
|
2017-11-21 11:42:05 +01:00
|
|
|
/* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */
|
|
|
|
len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3;
|
|
|
|
if (ipa_len && num_labels > 1) /* There are 2 VNIs */
|
|
|
|
len += 3;
|
|
|
|
stream_putc(s, len);
|
2017-05-15 23:34:04 +02:00
|
|
|
stream_put(s, prd->val, 8); /* RD */
|
2018-04-06 15:52:48 +02:00
|
|
|
if (attr)
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
stream_put(s, &attr->esi, ESI_BYTES);
|
2018-04-06 15:52:48 +02:00
|
|
|
else
|
|
|
|
stream_put(s, 0, 10);
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_putl(s, evp->prefix.macip_addr.eth_tag); /* Ethernet Tag ID */
|
2017-08-03 14:45:27 +02:00
|
|
|
stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_put(s, evp->prefix.macip_addr.mac.octet, 6); /* Mac Addr */
|
|
|
|
stream_putc(s, 8 * ipa_len); /* IP address Length */
|
|
|
|
if (ipa_len) /* IP */
|
|
|
|
stream_put(s, &evp->prefix.macip_addr.ip.ip.addr,
|
|
|
|
ipa_len);
|
2017-11-21 11:42:05 +01:00
|
|
|
/* 1st label is the L2 VNI */
|
|
|
|
stream_put(s, label, BGP_LABEL_BYTES);
|
|
|
|
/* Include 2nd label (L3 VNI) if advertising MAC+IP */
|
|
|
|
if (ipa_len && num_labels > 1)
|
|
|
|
stream_put(s, label + 1, BGP_LABEL_BYTES);
|
2017-05-15 23:34:04 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
case BGP_EVPN_IMET_ROUTE:
|
|
|
|
stream_putc(s, 17); // TODO: length - assumes IPv4 address
|
|
|
|
stream_put(s, prd->val, 8); /* RD */
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_putl(s, evp->prefix.imet_addr.eth_tag); /* Ethernet Tag ID */
|
2017-05-15 23:34:04 +02:00
|
|
|
stream_putc(s, IPV4_MAX_BITLEN); /* IP address Length - bits */
|
|
|
|
/* Originating Router's IP Addr */
|
2018-04-14 00:37:30 +02:00
|
|
|
stream_put_in_addr(s, &evp->prefix.imet_addr.ip.ipaddr_v4);
|
2017-05-15 23:34:04 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
case BGP_EVPN_ES_ROUTE:
|
|
|
|
stream_putc(s, 23); /* TODO: length: assumes ipv4 VTEP */
|
|
|
|
stream_put(s, prd->val, 8); /* RD */
|
|
|
|
stream_put(s, evp->prefix.es_addr.esi.val, 10); /* ESI */
|
|
|
|
stream_putc(s, IPV4_MAX_BITLEN); /* IP address Length - bits */
|
2018-05-16 14:17:53 +02:00
|
|
|
/* VTEP IP */
|
|
|
|
stream_put_in_addr(s, &evp->prefix.es_addr.ip.ipaddr_v4);
|
2018-04-14 00:01:12 +02:00
|
|
|
break;
|
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
case BGP_EVPN_AD_ROUTE:
|
|
|
|
/* RD, ESI, EthTag, 1 VNI */
|
|
|
|
len = RD_BYTES + ESI_BYTES + EVPN_ETH_TAG_BYTES + BGP_LABEL_BYTES;
|
|
|
|
stream_putc(s, len);
|
|
|
|
stream_put(s, prd->val, RD_BYTES); /* RD */
|
|
|
|
stream_put(s, evp->prefix.ead_addr.esi.val, ESI_BYTES); /* ESI */
|
|
|
|
stream_putl(s, evp->prefix.ead_addr.eth_tag); /* Ethernet Tag */
|
|
|
|
stream_put(s, label, BGP_LABEL_BYTES);
|
|
|
|
break;
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
case BGP_EVPN_IP_PREFIX_ROUTE:
|
|
|
|
/* TODO: AddPath support. */
|
2017-11-21 11:42:05 +01:00
|
|
|
evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr);
|
2017-05-15 23:34:04 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
|
2023-04-05 21:25:57 +02:00
|
|
|
struct bgp_nlri *packet, bool withdraw)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
|
|
|
uint8_t *lim;
|
2017-05-15 23:34:04 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t addpath_id;
|
2022-01-27 08:51:59 +01:00
|
|
|
bool addpath_capable;
|
2017-05-15 23:34:04 +02:00
|
|
|
int psize = 0;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t rtype;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct prefix p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Start processing the NLRI - there may be multiple in the MP_REACH */
|
|
|
|
pnt = packet->nlri;
|
|
|
|
lim = pnt + packet->length;
|
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
for (; pnt < lim; pnt += psize) {
|
|
|
|
/* Clear prefix structure. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&p, 0, sizeof(p));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Deal with path-id if AddPath is supported. */
|
2022-01-27 08:51:59 +01:00
|
|
|
if (addpath_capable) {
|
2017-05-15 23:34:04 +02:00
|
|
|
/* When packet overflow occurs return immediately. */
|
|
|
|
if (pnt + BGP_ADDPATH_ID_LEN > lim)
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-01-07 16:47:13 +01:00
|
|
|
memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
|
|
|
|
addpath_id = ntohl(addpath_id);
|
2017-05-15 23:34:04 +02:00
|
|
|
pnt += BGP_ADDPATH_ID_LEN;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* All EVPN NLRI types start with type and length. */
|
|
|
|
if (pnt + 2 > lim)
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_EVPN_MISSING_TYPE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
rtype = *pnt++;
|
2018-07-07 22:34:25 +02:00
|
|
|
psize = *pnt++;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* When packet overflow occur return immediately. */
|
|
|
|
if (pnt + psize > lim)
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
switch (rtype) {
|
|
|
|
case BGP_EVPN_MAC_IP_ROUTE:
|
|
|
|
if (process_type2_route(peer, afi, safi,
|
|
|
|
withdraw ? NULL : attr, pnt,
|
|
|
|
psize, addpath_id)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_FAIL,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Error in processing EVPN type-2 NLRI size %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_EVPN_TYPE2_SIZE;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
case BGP_EVPN_IMET_ROUTE:
|
|
|
|
if (process_type3_route(peer, afi, safi,
|
|
|
|
withdraw ? NULL : attr, pnt,
|
|
|
|
psize, addpath_id)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_PKT_PROCESS,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Error in processing EVPN type-3 NLRI size %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_EVPN_TYPE3_SIZE;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
case BGP_EVPN_ES_ROUTE:
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
if (bgp_evpn_type4_route_process(peer, afi, safi,
|
2018-04-14 00:01:12 +02:00
|
|
|
withdraw ? NULL : attr, pnt,
|
|
|
|
psize, addpath_id)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_PKT_PROCESS,
|
2018-04-14 00:01:12 +02:00
|
|
|
"%u:%s - Error in processing EVPN type-4 NLRI size %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_EVPN_TYPE4_SIZE;
|
2018-04-14 00:01:12 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
case BGP_EVPN_AD_ROUTE:
|
|
|
|
if (bgp_evpn_type1_route_process(peer, afi, safi,
|
|
|
|
withdraw ? NULL : attr, pnt,
|
|
|
|
psize, addpath_id)) {
|
|
|
|
flog_err(
|
|
|
|
EC_BGP_PKT_PROCESS,
|
|
|
|
"%u:%s - Error in processing EVPN type-1 NLRI size %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
|
|
|
return BGP_NLRI_PARSE_ERROR_EVPN_TYPE1_SIZE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
case BGP_EVPN_IP_PREFIX_ROUTE:
|
2019-02-25 19:07:05 +01:00
|
|
|
if (process_type5_route(peer, afi, safi,
|
|
|
|
withdraw ? NULL : attr, pnt,
|
|
|
|
psize, addpath_id)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_PKT_PROCESS,
|
2017-05-15 23:34:04 +02:00
|
|
|
"%u:%s - Error in processing EVPN type-5 NLRI size %d",
|
|
|
|
peer->bgp->vrf_id, peer->host, psize);
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_EVPN_TYPE5_SIZE;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Packet length consistency check. */
|
|
|
|
if (pnt != lim)
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-04-15 22:53:20 +02:00
|
|
|
return BGP_NLRI_PARSE_OK;
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-10 03:12:05 +02:00
|
|
|
/*
|
|
|
|
* Map the RTs (configured or automatically derived) of a VRF to the VRF.
|
|
|
|
* The mapping will be used during route processing.
|
|
|
|
* bgp_vrf: specific bgp vrf instance on which RT is configured
|
|
|
|
*/
|
|
|
|
void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
|
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
struct listnode *node, *nnode;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct vrf_route_target *l3rt;
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt))
|
|
|
|
map_vrf_to_rt(bgp_vrf, l3rt);
|
2017-10-10 03:12:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unmap the RTs (configured or automatically derived) of a VRF from the VRF.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
struct listnode *node, *nnode;
|
2021-02-17 22:11:49 +01:00
|
|
|
struct vrf_route_target *l3rt;
|
2017-10-10 03:12:05 +02:00
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt))
|
|
|
|
unmap_vrf_from_rt(bgp_vrf, l3rt);
|
2017-10-10 03:12:05 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Map the RTs (configured or automatically derived) of a VNI to the VNI.
|
|
|
|
* The mapping will be used during route processing.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2021-01-17 22:08:03 +01:00
|
|
|
uint32_t i;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity_val *eval;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct ecommunity *ecom;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
|
|
|
|
for (i = 0; i < ecom->size; i++) {
|
|
|
|
eval = (struct ecommunity_val *)(ecom->val
|
|
|
|
+ (i
|
|
|
|
* ECOMMUNITY_SIZE));
|
|
|
|
map_vni_to_rt(bgp, vpn, eval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unmap the RTs (configured or automatically derived) of a VNI from the VNI.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2021-01-17 22:08:03 +01:00
|
|
|
uint32_t i;
|
2017-05-15 23:34:04 +02:00
|
|
|
struct ecommunity_val *eval;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct ecommunity *ecom;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
|
|
|
|
for (i = 0; i < ecom->size; i++) {
|
|
|
|
struct irt_node *irt;
|
|
|
|
struct ecommunity_val eval_tmp;
|
|
|
|
|
|
|
|
eval = (struct ecommunity_val *)(ecom->val
|
|
|
|
+ (i
|
|
|
|
* ECOMMUNITY_SIZE));
|
|
|
|
/* If using "automatic" RT, we only care about the
|
|
|
|
* local-admin sub-field.
|
|
|
|
* This is to facilitate using VNI as the RT for EBGP
|
|
|
|
* peering too.
|
|
|
|
*/
|
|
|
|
memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
|
|
|
|
if (!is_import_rt_configured(vpn))
|
|
|
|
mask_ecom_global_admin(&eval_tmp, eval);
|
|
|
|
|
|
|
|
irt = lookup_import_rt(bgp, &eval_tmp);
|
|
|
|
if (irt)
|
|
|
|
unmap_vni_from_rt(bgp, vpn, irt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Derive Import RT automatically for VNI and map VNI to RT.
|
|
|
|
* The mapping will be used during route processing.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
form_auto_rt(bgp, vpn->vni, vpn->import_rtl, false);
|
2017-05-15 23:34:04 +02:00
|
|
|
UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
|
|
|
|
|
|
|
|
/* Map RT to VNI */
|
|
|
|
bgp_evpn_map_vni_to_its_rts(bgp, vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Derive Export RT automatically for VNI.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2021-02-25 22:27:07 +01:00
|
|
|
form_auto_rt(bgp, vpn->vni, vpn->export_rtl, false);
|
2017-05-15 23:34:04 +02:00
|
|
|
UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
|
|
|
|
}
|
|
|
|
|
2017-10-26 01:49:18 +02:00
|
|
|
/*
|
|
|
|
* Derive RD automatically for VNI using passed information - it
|
|
|
|
* is of the form RouterId:unique-id-for-vni.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
|
|
|
|
{
|
2019-03-20 01:06:10 +01:00
|
|
|
if (is_vrf_rd_configured(bgp))
|
|
|
|
return;
|
|
|
|
|
2018-03-27 02:11:39 +02:00
|
|
|
form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd);
|
2017-10-26 01:49:18 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Derive RD automatically for VNI using passed information - it
|
|
|
|
* is of the form RouterId:unique-id-for-vni.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
char buf[BGP_EVPN_PREFIX_RD_LEN];
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
vpn->prd.family = AF_UNSPEC;
|
|
|
|
vpn->prd.prefixlen = 64;
|
2020-10-15 21:33:09 +02:00
|
|
|
snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, vpn->rd_id);
|
2017-10-23 23:19:26 +02:00
|
|
|
(void)str2prefix_rd(buf, &vpn->prd);
|
2022-11-22 11:20:51 +01:00
|
|
|
if (vpn->prd_pretty)
|
2023-11-15 20:52:10 +01:00
|
|
|
XFREE(MTYPE_BGP_NAME, vpn->prd_pretty);
|
2017-05-15 23:34:04 +02:00
|
|
|
UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
|
|
|
|
}
|
|
|
|
|
2018-08-01 03:45:39 +02:00
|
|
|
/*
|
|
|
|
* Lookup L3-VNI
|
|
|
|
*/
|
|
|
|
bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni)
|
|
|
|
{
|
|
|
|
struct list *inst = bm->bgp;
|
|
|
|
struct listnode *node;
|
|
|
|
struct bgp *bgp_vrf;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(inst, node, bgp_vrf)) {
|
|
|
|
if (bgp_vrf->l3vni == vni)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Lookup VNI.
|
|
|
|
*/
|
|
|
|
struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
struct bgpevpn tmp;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
2017-05-15 23:34:04 +02:00
|
|
|
tmp.vni = vni;
|
|
|
|
vpn = hash_lookup(bgp->vnihash, &tmp);
|
|
|
|
return vpn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new vpn - invoked upon configuration or zebra notification.
|
|
|
|
*/
|
|
|
|
struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
|
2019-03-19 19:08:24 +01:00
|
|
|
struct in_addr originator_ip,
|
|
|
|
vrf_id_t tenant_vrf_id,
|
2021-01-11 09:14:05 +01:00
|
|
|
struct in_addr mcast_grp,
|
|
|
|
ifindex_t svi_ifindex)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
|
|
|
|
vpn = XCALLOC(MTYPE_BGP_EVPN, sizeof(struct bgpevpn));
|
|
|
|
|
|
|
|
/* Set values - RD and RT set to defaults. */
|
|
|
|
vpn->vni = vni;
|
|
|
|
vpn->originator_ip = originator_ip;
|
2017-10-08 05:26:16 +02:00
|
|
|
vpn->tenant_vrf_id = tenant_vrf_id;
|
2019-03-19 19:08:24 +01:00
|
|
|
vpn->mcast_grp = mcast_grp;
|
2021-01-11 09:14:05 +01:00
|
|
|
vpn->svi_ifindex = svi_ifindex;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Initialize route-target import and export lists */
|
|
|
|
vpn->import_rtl = list_new();
|
2021-05-12 01:45:55 +02:00
|
|
|
vpn->import_rtl->cmp =
|
|
|
|
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
|
|
|
|
vpn->import_rtl->del = bgp_evpn_xxport_delete_ecomm;
|
2017-05-15 23:34:04 +02:00
|
|
|
vpn->export_rtl = list_new();
|
2021-05-12 01:45:55 +02:00
|
|
|
vpn->export_rtl->cmp =
|
|
|
|
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
|
|
|
|
vpn->export_rtl->del = bgp_evpn_xxport_delete_ecomm;
|
2017-10-26 01:13:32 +02:00
|
|
|
bf_assign_index(bm->rd_idspace, vpn->rd_id);
|
2017-05-15 23:34:04 +02:00
|
|
|
derive_rd_rt_for_vni(bgp, vpn);
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
/* Initialize EVPN route tables. */
|
|
|
|
vpn->ip_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
|
|
|
|
vpn->mac_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Add to hash */
|
2022-04-20 12:57:53 +02:00
|
|
|
(void)hash_get(bgp->vnihash, vpn, hash_alloc_intern);
|
2017-10-09 05:43:14 +02:00
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
bgp_evpn_remote_ip_hash_init(vpn);
|
|
|
|
bgp_evpn_link_to_vni_svi_hash(bgp, vpn);
|
|
|
|
|
2017-10-09 05:43:14 +02:00
|
|
|
/* add to l2vni list on corresponding vrf */
|
|
|
|
bgpevpn_link_to_l3vni(vpn);
|
|
|
|
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
bgp_evpn_vni_es_init(vpn);
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
QOBJ_REG(vpn, bgpevpn);
|
|
|
|
return vpn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free a given VPN - called in multiple scenarios such as zebra
|
|
|
|
* notification, configuration being deleted, advertise-all-vni disabled etc.
|
|
|
|
* This just frees appropriate memory, caller should have taken other
|
|
|
|
* needed actions.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
2024-02-15 20:23:51 +01:00
|
|
|
struct bgp_dest *dest = NULL;
|
2024-05-18 00:43:59 +02:00
|
|
|
uint32_t ann_count = zebra_announce_count(&bm->zebra_announce_head);
|
2024-02-15 20:23:51 +01:00
|
|
|
|
2024-05-18 00:43:59 +02:00
|
|
|
while (ann_count) {
|
2024-02-15 20:23:51 +01:00
|
|
|
dest = zebra_announce_pop(&bm->zebra_announce_head);
|
2024-05-18 00:43:59 +02:00
|
|
|
ann_count--;
|
2024-02-15 20:23:51 +01:00
|
|
|
if (dest->za_vpn == vpn) {
|
|
|
|
bgp_path_info_unlock(dest->za_bgp_pi);
|
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
} else
|
|
|
|
zebra_announce_add_tail(&bm->zebra_announce_head, dest);
|
|
|
|
}
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
bgp_evpn_remote_ip_hash_destroy(vpn);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
bgp_evpn_vni_es_cleanup(vpn);
|
2017-10-09 05:43:14 +02:00
|
|
|
bgpevpn_unlink_from_l3vni(vpn);
|
2021-10-26 23:55:54 +02:00
|
|
|
bgp_table_unlock(vpn->ip_table);
|
|
|
|
bgp_table_unlock(vpn->mac_table);
|
2017-05-15 23:34:04 +02:00
|
|
|
bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&vpn->import_rtl);
|
|
|
|
list_delete(&vpn->export_rtl);
|
2017-10-26 01:13:32 +02:00
|
|
|
bf_release_index(bm->rd_idspace, vpn->rd_id);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
hash_release(bgp->vni_svi_hash, vpn);
|
2017-05-15 23:34:04 +02:00
|
|
|
hash_release(bgp->vnihash, vpn);
|
2022-11-22 11:20:51 +01:00
|
|
|
if (vpn->prd_pretty)
|
2023-11-15 20:52:10 +01:00
|
|
|
XFREE(MTYPE_BGP_NAME, vpn->prd_pretty);
|
2017-05-15 23:34:04 +02:00
|
|
|
QOBJ_UNREG(vpn);
|
|
|
|
XFREE(MTYPE_BGP_EVPN, vpn);
|
|
|
|
}
|
|
|
|
|
2022-08-30 12:46:26 +02:00
|
|
|
static void hash_evpn_free(struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_BGP_EVPN, vpn);
|
|
|
|
}
|
|
|
|
|
2018-04-14 00:01:12 +02:00
|
|
|
/*
|
|
|
|
* Import evpn route from global table to VNI/VRF/ESI.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
|
|
|
int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
2020-03-22 02:56:36 +01:00
|
|
|
const struct prefix *p, struct bgp_path_info *pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 1);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-04-14 00:01:12 +02:00
|
|
|
* Unimport evpn route from VNI/VRF/ESI.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
|
|
|
int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
2020-03-22 02:56:36 +01:00
|
|
|
const struct prefix *p, struct bgp_path_info *pi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
2018-10-03 02:43:07 +02:00
|
|
|
return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 0);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* Refresh previously-discarded EVPN routes carrying "self" MAC-VRF SoO.
|
|
|
|
* Walk global EVPN rib + import remote routes with old_soo && !new_soo.
|
|
|
|
*/
|
|
|
|
void bgp_reimport_evpn_routes_upon_macvrf_soo_change(struct bgp *bgp,
|
|
|
|
struct ecommunity *old_soo,
|
|
|
|
struct ecommunity *new_soo)
|
|
|
|
{
|
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
|
|
|
struct bgp_dest *rd_dest, *dest;
|
|
|
|
struct bgp_table *table;
|
|
|
|
struct bgp_path_info *pi;
|
|
|
|
|
|
|
|
afi = AFI_L2VPN;
|
|
|
|
safi = SAFI_EVPN;
|
|
|
|
|
|
|
|
/* EVPN routes are a 2-level table: outer=prefix_rd, inner=prefix_evpn.
|
|
|
|
* A remote route could have any RD, so we need to walk them all.
|
|
|
|
*/
|
|
|
|
for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
|
|
|
|
rd_dest = bgp_route_next(rd_dest)) {
|
|
|
|
table = bgp_dest_get_bgp_table_info(rd_dest);
|
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (dest = bgp_table_top(table); dest;
|
|
|
|
dest = bgp_route_next(dest)) {
|
|
|
|
const struct prefix *p;
|
|
|
|
struct prefix_evpn *evp;
|
|
|
|
|
|
|
|
p = bgp_dest_get_prefix(dest);
|
|
|
|
evp = (struct prefix_evpn *)p;
|
|
|
|
|
|
|
|
/* On export we only add MAC-VRF SoO to RT-2/3, so we
|
|
|
|
* can skip evaluation of other RTs.
|
|
|
|
*/
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
|
|
|
|
evp->prefix.route_type != BGP_EVPN_IMET_ROUTE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
|
|
|
|
pi = pi->next) {
|
|
|
|
bool old_soo_fnd = false;
|
|
|
|
bool new_soo_fnd = false;
|
|
|
|
|
|
|
|
/* Only consider routes learned from peers */
|
|
|
|
if (!(pi->type == ZEBRA_ROUTE_BGP &&
|
|
|
|
pi->sub_type == BGP_ROUTE_NORMAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
old_soo_fnd = route_matches_soo(pi, old_soo);
|
|
|
|
new_soo_fnd = route_matches_soo(pi, new_soo);
|
|
|
|
|
|
|
|
if (old_soo_fnd && !new_soo_fnd) {
|
|
|
|
if (bgp_debug_update(pi->peer, p, NULL,
|
|
|
|
1)) {
|
|
|
|
char attr_str[BUFSIZ] = {0};
|
|
|
|
|
|
|
|
bgp_dump_attr(pi->attr,
|
|
|
|
attr_str, BUFSIZ);
|
|
|
|
|
|
|
|
zlog_debug(
|
|
|
|
"mac-vrf soo changed: evaluating reimport of prefix %pBD with attr %s",
|
|
|
|
dest, attr_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
bgp_evpn_import_route(bgp, afi, safi, p,
|
|
|
|
pi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Filter learned (!local) EVPN routes carrying "self" attributes.
|
2023-03-27 21:49:41 +02:00
|
|
|
* Walk the Global EVPN loc-rib unimporting martian routes from the appropriate
|
|
|
|
* L2VNIs (MAC-VRFs) / L3VNIs (IP-VRFs), and deleting them from the Global
|
|
|
|
* loc-rib when applicable (based on martian_type).
|
|
|
|
* This function is the handler for new martian entries, which is triggered by
|
|
|
|
* events occurring on the local system,
|
|
|
|
* e.g.
|
|
|
|
* - New VTEP-IP
|
|
|
|
* + bgp_zebra_process_local_vni
|
|
|
|
* + bgp_zebra_process_local_l3vni
|
|
|
|
* - New MAC-VRF Site-of-Origin
|
|
|
|
* + bgp_evpn_handle_global_macvrf_soo_change
|
|
|
|
* This will likely be extended in the future to cover these events too:
|
|
|
|
* - New Interface IP
|
|
|
|
* + bgp_interface_address_add
|
|
|
|
* - New Interface MAC
|
|
|
|
* + bgp_ifp_up
|
|
|
|
* + bgp_ifp_create
|
|
|
|
* - New RMAC
|
|
|
|
* + bgp_zebra_process_local_l3vni
|
|
|
|
*/
|
|
|
|
void bgp_filter_evpn_routes_upon_martian_change(
|
|
|
|
struct bgp *bgp, enum bgp_martian_type martian_type)
|
2017-08-17 08:19:58 +02:00
|
|
|
{
|
2017-08-19 07:43:09 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *rd_dest, *dest;
|
2017-08-19 07:43:09 +02:00
|
|
|
struct bgp_table *table;
|
2018-10-03 02:43:07 +02:00
|
|
|
struct bgp_path_info *pi;
|
2023-05-08 05:54:25 +02:00
|
|
|
struct ecommunity *macvrf_soo;
|
2017-08-17 08:19:58 +02:00
|
|
|
|
|
|
|
afi = AFI_L2VPN;
|
|
|
|
safi = SAFI_EVPN;
|
2023-05-08 05:54:25 +02:00
|
|
|
macvrf_soo = bgp->evpn_info->soo;
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2023-03-27 21:49:41 +02:00
|
|
|
/* EVPN routes are a 2-level table: outer=prefix_rd, inner=prefix_evpn.
|
|
|
|
* A remote route could have any RD, so we need to walk them all.
|
2017-08-17 08:19:58 +02:00
|
|
|
*/
|
2020-03-27 00:11:58 +01:00
|
|
|
for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
|
|
|
|
rd_dest = bgp_route_next(rd_dest)) {
|
|
|
|
table = bgp_dest_get_bgp_table_info(rd_dest);
|
2017-08-17 08:19:58 +02:00
|
|
|
if (!table)
|
|
|
|
continue;
|
|
|
|
|
2020-03-27 00:11:58 +01:00
|
|
|
for (dest = bgp_table_top(table); dest;
|
|
|
|
dest = bgp_route_next(dest)) {
|
2024-03-19 17:26:14 +01:00
|
|
|
struct bgp_path_info *next;
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2024-03-19 17:26:14 +01:00
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest);
|
|
|
|
(pi != NULL) && (next = pi->next, 1); pi = next) {
|
2023-03-27 21:49:41 +02:00
|
|
|
bool affected = false;
|
|
|
|
const struct prefix *p;
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2023-03-27 21:49:41 +02:00
|
|
|
/* Only consider routes learned from peers */
|
2018-10-03 02:43:07 +02:00
|
|
|
if (!(pi->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& pi->sub_type == BGP_ROUTE_NORMAL))
|
2017-08-17 08:19:58 +02:00
|
|
|
continue;
|
|
|
|
|
2023-03-27 21:49:41 +02:00
|
|
|
p = bgp_dest_get_prefix(dest);
|
|
|
|
|
|
|
|
switch (martian_type) {
|
|
|
|
case BGP_MARTIAN_TUN_IP:
|
|
|
|
affected = bgp_nexthop_self(
|
|
|
|
bgp, afi, pi->type,
|
|
|
|
pi->sub_type, pi->attr, dest);
|
|
|
|
break;
|
|
|
|
case BGP_MARTIAN_SOO:
|
2023-05-08 05:54:25 +02:00
|
|
|
affected = route_matches_soo(
|
|
|
|
pi, macvrf_soo);
|
2023-03-27 21:49:41 +02:00
|
|
|
break;
|
|
|
|
case BGP_MARTIAN_IF_IP:
|
|
|
|
case BGP_MARTIAN_IF_MAC:
|
|
|
|
case BGP_MARTIAN_RMAC:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (affected) {
|
2020-03-22 05:02:18 +01:00
|
|
|
if (bgp_debug_update(pi->peer, p, NULL,
|
|
|
|
1)) {
|
|
|
|
char attr_str[BUFSIZ] = {0};
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2020-03-22 05:02:18 +01:00
|
|
|
bgp_dump_attr(pi->attr,
|
2020-08-18 20:43:07 +02:00
|
|
|
attr_str,
|
|
|
|
sizeof(attr_str));
|
2017-08-17 08:19:58 +02:00
|
|
|
|
|
|
|
zlog_debug(
|
2023-03-27 21:49:41 +02:00
|
|
|
"%u: prefix %pBD with attr %s - DISCARDED due to Martian/%s",
|
2020-03-27 00:11:58 +01:00
|
|
|
bgp->vrf_id, dest,
|
2023-03-27 21:49:41 +02:00
|
|
|
attr_str,
|
|
|
|
bgp_martian_type2str(
|
|
|
|
martian_type));
|
2020-03-22 05:02:18 +01:00
|
|
|
}
|
2023-03-27 21:49:41 +02:00
|
|
|
|
|
|
|
|
2017-08-17 08:19:58 +02:00
|
|
|
bgp_evpn_unimport_route(bgp, afi, safi,
|
2020-03-22 05:02:18 +01:00
|
|
|
p, pi);
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2023-03-27 21:49:41 +02:00
|
|
|
/* For now, retain existing handling of
|
|
|
|
* tip_hash updates: (Self SoO routes
|
|
|
|
* are unimported from L2VNI/VRF but
|
|
|
|
* retained in global loc-rib, but Self
|
|
|
|
* IP/MAC routes are also deleted from
|
|
|
|
* global loc-rib).
|
|
|
|
* TODO: use consistent handling for all
|
|
|
|
* martian types
|
|
|
|
*/
|
|
|
|
if (martian_type == BGP_MARTIAN_TUN_IP)
|
|
|
|
bgp_rib_remove(dest, pi,
|
|
|
|
pi->peer, afi,
|
|
|
|
safi);
|
2017-08-17 08:19:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 05:54:25 +02:00
|
|
|
/* Refresh previously-discarded EVPN routes carrying "self" attributes.
|
|
|
|
* This function is the handler for deleted martian entries, which is triggered
|
|
|
|
* by events occurring on the local system,
|
|
|
|
* e.g.
|
|
|
|
* - Del MAC-VRF Site-of-Origin
|
|
|
|
* + bgp_evpn_handle_global_macvrf_soo_change
|
|
|
|
* This will likely be extended in the future to cover these events too:
|
|
|
|
* - Del VTEP-IP
|
|
|
|
* + bgp_zebra_process_local_vni
|
|
|
|
* + bgp_zebra_process_local_l3vni
|
|
|
|
* - Del Interface IP
|
|
|
|
* + bgp_interface_address_delete
|
|
|
|
* - Del Interface MAC
|
|
|
|
* + bgp_ifp_down
|
|
|
|
* + bgp_ifp_destroy
|
|
|
|
* - Del RMAC
|
|
|
|
* + bgp_zebra_process_local_l3vni
|
|
|
|
*/
|
|
|
|
void bgp_reimport_evpn_routes_upon_martian_change(
|
|
|
|
struct bgp *bgp, enum bgp_martian_type martian_type, void *old_martian,
|
|
|
|
void *new_martian)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct peer *peer;
|
|
|
|
safi_t safi;
|
|
|
|
afi_t afi;
|
|
|
|
struct ecommunity *old_soo, *new_soo;
|
|
|
|
|
|
|
|
afi = AFI_L2VPN;
|
|
|
|
safi = SAFI_EVPN;
|
|
|
|
|
|
|
|
/* Self-SoO routes are held in the global EVPN loc-rib, so we can
|
|
|
|
* reimport routes w/o triggering soft-reconfig/route-refresh.
|
|
|
|
*/
|
|
|
|
if (martian_type == BGP_MARTIAN_SOO) {
|
|
|
|
old_soo = (struct ecommunity *)old_martian;
|
|
|
|
new_soo = (struct ecommunity *)new_martian;
|
|
|
|
|
|
|
|
/* If !old_soo, then we can skip the reimport because we
|
|
|
|
* wouldn't have filtered anything via the self-SoO import check
|
|
|
|
*/
|
|
|
|
if (old_martian)
|
|
|
|
bgp_reimport_evpn_routes_upon_macvrf_soo_change(
|
|
|
|
bgp, old_soo, new_soo);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Self-TIP/IP/MAC/RMAC routes are deleted from the global EVPN
|
|
|
|
* loc-rib, so we need to re-learn the routes via soft-reconfig/
|
|
|
|
* route-refresh.
|
|
|
|
*/
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
|
|
|
|
|
|
|
|
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
|
|
|
|
continue;
|
|
|
|
|
2021-08-10 05:43:46 +02:00
|
|
|
if (peer->connection->status != Established)
|
2023-05-08 05:54:25 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(peer->af_flags[afi][safi],
|
|
|
|
PEER_FLAG_SOFT_RECONFIG)) {
|
|
|
|
if (bgp_debug_update(peer, NULL, NULL, 1))
|
|
|
|
zlog_debug(
|
|
|
|
"Processing EVPN Martian/%s change on peer %s (inbound, soft-reconfig)",
|
|
|
|
bgp_martian_type2str(martian_type),
|
|
|
|
peer->host);
|
|
|
|
|
|
|
|
bgp_soft_reconfig_in(peer, afi, safi);
|
|
|
|
} else {
|
|
|
|
if (bgp_debug_update(peer, NULL, NULL, 1))
|
|
|
|
zlog_debug(
|
|
|
|
"Processing EVPN Martian/%s change on peer %s",
|
|
|
|
bgp_martian_type2str(martian_type),
|
|
|
|
peer->host);
|
|
|
|
bgp_route_refresh_send(peer, afi, safi, 0,
|
|
|
|
REFRESH_IMMEDIATE, 0,
|
|
|
|
BGP_ROUTE_REFRESH_NORMAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Handle del of a local MACIP.
|
|
|
|
*/
|
|
|
|
int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
|
2019-01-15 00:24:43 +01:00
|
|
|
struct ipaddr *ip, int state)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
struct prefix_evpn p;
|
2020-03-27 00:11:58 +01:00
|
|
|
struct bgp_dest *dest;
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
/* Lookup VNI hash - should exist. */
|
|
|
|
vpn = bgp_evpn_lookup_vni(bgp, vni);
|
|
|
|
if (!vpn || !is_vni_live(vpn)) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_warn(EC_BGP_EVPN_VPN_VNI,
|
2018-08-16 14:58:01 +02:00
|
|
|
"%u: VNI hash entry for VNI %u %s at MACIP DEL",
|
2017-05-15 23:34:04 +02:00
|
|
|
bgp->vrf_id, vni, vpn ? "not live" : "not found");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
build_evpn_type2_prefix(&p, mac, ip);
|
2019-01-15 00:24:43 +01:00
|
|
|
if (state == ZEBRA_NEIGH_ACTIVE) {
|
|
|
|
/* Remove EVPN type-2 route and schedule for processing. */
|
|
|
|
delete_evpn_route(bgp, vpn, &p);
|
|
|
|
} else {
|
|
|
|
/* Re-instate the current remote best path if any */
|
2021-10-26 23:55:54 +02:00
|
|
|
dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
|
2021-06-22 22:14:47 +02:00
|
|
|
if (dest) {
|
2020-03-27 00:11:58 +01:00
|
|
|
evpn_zebra_reinstall_best_route(bgp, vpn, dest);
|
2021-06-22 22:14:47 +02:00
|
|
|
bgp_dest_unlock_node(dest);
|
|
|
|
}
|
2019-01-15 00:24:43 +01:00
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle add of a local MACIP.
|
|
|
|
*/
|
|
|
|
int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
struct ipaddr *ip, uint8_t flags, uint32_t seq, esi_t *esi)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
struct prefix_evpn p;
|
|
|
|
|
|
|
|
/* Lookup VNI hash - should exist. */
|
|
|
|
vpn = bgp_evpn_lookup_vni(bgp, vni);
|
|
|
|
if (!vpn || !is_vni_live(vpn)) {
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_warn(EC_BGP_EVPN_VPN_VNI,
|
2018-08-16 14:58:01 +02:00
|
|
|
"%u: VNI hash entry for VNI %u %s at MACIP ADD",
|
2017-05-15 23:34:04 +02:00
|
|
|
bgp->vrf_id, vni, vpn ? "not live" : "not found");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create EVPN type-2 route and schedule for processing. */
|
|
|
|
build_evpn_type2_prefix(&p, mac, ip);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
if (update_evpn_route(bgp, vpn, &p, flags, seq, esi)) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_EVPN_ROUTE_CREATE,
|
2021-03-10 01:50:42 +01:00
|
|
|
"%u:Failed to create Type-2 route, VNI %u %s MAC %pEA IP %pIA (flags: 0x%x)",
|
2017-06-28 10:51:10 +02:00
|
|
|
bgp->vrf_id, vpn->vni,
|
2018-01-18 19:27:26 +01:00
|
|
|
CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)
|
|
|
|
? "sticky gateway"
|
2017-06-28 10:51:10 +02:00
|
|
|
: "",
|
2021-03-10 01:50:42 +01:00
|
|
|
mac, ip, flags);
|
2017-05-15 23:34:04 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket,
|
2017-10-09 05:43:14 +02:00
|
|
|
struct bgp *bgp_vrf)
|
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL;
|
2017-10-09 05:43:14 +02:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
assert(bgp_evpn);
|
2017-10-09 05:43:14 +02:00
|
|
|
|
|
|
|
if (vpn->tenant_vrf_id == bgp_vrf->vrf_id)
|
|
|
|
bgpevpn_link_to_l3vni(vpn);
|
|
|
|
}
|
|
|
|
|
2019-08-05 01:51:33 +02:00
|
|
|
int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
|
|
|
|
struct ethaddr *svi_rmac,
|
|
|
|
struct ethaddr *vrr_rmac,
|
2019-02-27 12:52:34 +01:00
|
|
|
struct in_addr originator_ip, int filter,
|
2019-08-05 01:51:33 +02:00
|
|
|
ifindex_t svi_ifindex,
|
|
|
|
bool is_anycast_mac)
|
2017-10-09 02:46:08 +02:00
|
|
|
{
|
|
|
|
struct bgp *bgp_vrf = NULL; /* bgp VRF instance */
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
|
2017-10-09 11:06:34 +02:00
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct bgpevpn *vpn = NULL;
|
2017-10-09 02:46:08 +02:00
|
|
|
as_t as = 0;
|
|
|
|
|
2019-03-06 19:30:00 +01:00
|
|
|
/* get the EVPN instance - required to get the AS number for VRF
|
2017-12-27 20:47:10 +01:00
|
|
|
* auto-creatio
|
|
|
|
*/
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_NO_DFLT,
|
2019-03-06 19:30:00 +01:00
|
|
|
"Cannot process L3VNI %u ADD - EVPN BGP instance not yet created",
|
2017-10-09 02:46:08 +02:00
|
|
|
l3vni);
|
|
|
|
return -1;
|
|
|
|
}
|
2023-04-10 19:59:48 +02:00
|
|
|
|
|
|
|
if (CHECK_FLAG(bgp_evpn->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
|
|
|
|
flog_err(EC_BGP_NO_DFLT,
|
|
|
|
"Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down",
|
|
|
|
l3vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
as = bgp_evpn->as;
|
2017-10-09 02:46:08 +02:00
|
|
|
|
2018-10-25 20:06:59 +02:00
|
|
|
/* if the BGP vrf instance doesn't exist - create one */
|
2019-03-06 19:30:00 +01:00
|
|
|
bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
|
2017-10-09 02:46:08 +02:00
|
|
|
if (!bgp_vrf) {
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
2019-08-01 18:50:56 +02:00
|
|
|
ret = bgp_get_vty(&bgp_vrf, &as, vrf_id_to_name(vrf_id),
|
|
|
|
vrf_id == VRF_DEFAULT
|
2022-11-15 16:42:40 +01:00
|
|
|
? BGP_INSTANCE_TYPE_DEFAULT
|
|
|
|
: BGP_INSTANCE_TYPE_VRF,
|
bgpd: add as-notation keyword to 'router bgp' vty command
A new keyword permits changing the BGP as-notation output:
- [no] router bgp <> [vrf BLABLA] [as-notation [<dot|plain|dot+>]]
At the BGP instance creation, the output will inherit the way the
BGP instance is declared. For instance, the 'router bgp 1.1'
command will configure the output in the dot format. However, if
the client wants to choose an alternate output, he will have to
add the extra command: 'router bgp 1.1 as-notation dot+'.
Also, if the user wants to have plain format, even if the BGP
instance is declared in dot format, the keyword can also be used
for that.
The as-notation output is only taken into account at the BGP
instance creation. In the case where VPN instances are used,
a separate instance may be dynamically created. In that case,
the real as-notation format will be taken into acccount at the
first configuration.
Linking the as-notation format with the BGP instance makes sense,
as the operators want to keep consistency of what they configure.
One technical reason why to link the as-notation output with the
BGP instance creation is that the as-path segment lists stored
in the BGP updates use a string representation to handle aspath
operations (by using regexp for instance). Changing on the fly
the output needs to regenerate this string representation to the
correct format. Linking the configuration to the BGP instance
creation avoids refreshing the BGP updates. A similar mechanism
is put in place in junos too.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2022-11-03 21:17:57 +01:00
|
|
|
NULL, ASNOTATION_UNDEFINED);
|
2017-10-09 02:46:08 +02:00
|
|
|
switch (ret) {
|
|
|
|
case BGP_ERR_AS_MISMATCH:
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_AS_MISMATCH,
|
2022-11-15 16:42:40 +01:00
|
|
|
"BGP instance is already running; AS is %s",
|
|
|
|
bgp_vrf->as_pretty);
|
2017-10-09 02:46:08 +02:00
|
|
|
return -1;
|
|
|
|
case BGP_ERR_INSTANCE_MISMATCH:
|
2018-09-13 20:23:42 +02:00
|
|
|
flog_err(EC_BGP_EVPN_INSTANCE_MISMATCH,
|
2021-04-23 20:36:12 +02:00
|
|
|
"BGP instance type mismatch");
|
2017-10-09 02:46:08 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mark as auto created */
|
|
|
|
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO);
|
|
|
|
}
|
|
|
|
|
2019-02-27 12:52:34 +01:00
|
|
|
/* associate the vrf with l3vni and related parameters */
|
2017-10-09 02:46:08 +02:00
|
|
|
bgp_vrf->l3vni = l3vni;
|
2019-02-27 12:52:34 +01:00
|
|
|
bgp_vrf->l3vni_svi_ifindex = svi_ifindex;
|
2019-08-05 01:51:33 +02:00
|
|
|
bgp_vrf->evpn_info->is_anycast_mac = is_anycast_mac;
|
2017-10-31 00:58:15 +01:00
|
|
|
|
2023-05-08 05:26:25 +02:00
|
|
|
/* Update tip_hash of the EVPN underlay BGP instance (bgp_evpn)
|
|
|
|
* if the VTEP-IP (originator_ip) has changed
|
|
|
|
*/
|
|
|
|
handle_tunnel_ip_change(bgp_vrf, bgp_evpn, vpn, originator_ip);
|
|
|
|
|
2019-08-05 01:51:33 +02:00
|
|
|
/* copy anycast MAC from VRR MAC */
|
|
|
|
memcpy(&bgp_vrf->rmac, vrr_rmac, ETH_ALEN);
|
|
|
|
/* copy sys RMAC from SVI MAC */
|
|
|
|
memcpy(&bgp_vrf->evpn_info->pip_rmac_zebra, svi_rmac, ETH_ALEN);
|
|
|
|
/* PIP user configured mac is not present use svi mac as sys mac */
|
|
|
|
if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static))
|
|
|
|
memcpy(&bgp_vrf->evpn_info->pip_rmac, svi_rmac, ETH_ALEN);
|
|
|
|
|
2021-03-10 01:50:42 +01:00
|
|
|
if (bgp_debug_zebra(NULL))
|
|
|
|
zlog_debug(
|
|
|
|
"VRF %s vni %u pip %s RMAC %pEA sys RMAC %pEA static RMAC %pEA is_anycast_mac %s",
|
|
|
|
vrf_id_to_name(bgp_vrf->vrf_id), bgp_vrf->l3vni,
|
|
|
|
bgp_vrf->evpn_info->advertise_pip ? "enable"
|
|
|
|
: "disable",
|
|
|
|
&bgp_vrf->rmac, &bgp_vrf->evpn_info->pip_rmac,
|
|
|
|
&bgp_vrf->evpn_info->pip_rmac_static,
|
|
|
|
is_anycast_mac ? "Enable" : "Disable");
|
|
|
|
|
2018-02-06 23:28:22 +01:00
|
|
|
/* set the right filter - are we using l3vni only for prefix routes? */
|
2020-05-07 22:33:02 +02:00
|
|
|
if (filter) {
|
2018-02-06 23:28:22 +01:00
|
|
|
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
|
|
|
|
|
2020-05-07 22:33:02 +02:00
|
|
|
/*
|
|
|
|
* VNI_FLAG_USE_TWO_LABELS flag for linked L2VNIs should not be
|
|
|
|
* set before linking vrf to L3VNI. Thus, no need to clear
|
|
|
|
* that explicitly.
|
|
|
|
*/
|
|
|
|
} else {
|
|
|
|
UNSET_FLAG(bgp_vrf->vrf_flags,
|
|
|
|
BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) {
|
|
|
|
if (!CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are flapping VNI_FLAG_USE_TWO_LABELS
|
|
|
|
* flag, update all MACIP routes in this VNI
|
|
|
|
*/
|
|
|
|
SET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
|
|
|
|
update_all_type2_routes(bgp_evpn, vpn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-07 03:03:58 +01:00
|
|
|
/* Map auto derive or configured RTs */
|
2021-02-25 22:27:07 +01:00
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD) ||
|
|
|
|
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
|
2017-10-09 03:34:29 +02:00
|
|
|
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
|
2018-12-07 03:03:58 +01:00
|
|
|
else
|
|
|
|
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
|
|
|
|
2021-02-25 22:27:07 +01:00
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD) ||
|
|
|
|
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
|
2017-10-09 03:34:29 +02:00
|
|
|
evpn_auto_rt_export_add_for_vrf(bgp_vrf);
|
2018-12-07 03:03:58 +01:00
|
|
|
|
|
|
|
/* auto derive RD */
|
2017-10-26 01:49:18 +02:00
|
|
|
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
|
2017-10-09 02:46:08 +02:00
|
|
|
|
2017-10-09 05:43:14 +02:00
|
|
|
/* link all corresponding l2vnis */
|
2019-03-06 19:10:02 +01:00
|
|
|
hash_iterate(bgp_evpn->vnihash,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-10-09 05:43:14 +02:00
|
|
|
void *))link_l2vni_hash_to_l3vni,
|
|
|
|
bgp_vrf);
|
|
|
|
|
2018-02-06 23:28:22 +01:00
|
|
|
/* Only update all corresponding type-2 routes if we are advertising two
|
|
|
|
* labels along with type-2 routes
|
|
|
|
*/
|
|
|
|
if (!filter)
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
|
2019-03-06 19:10:02 +01:00
|
|
|
update_routes_for_vni(bgp_evpn, vpn);
|
2017-10-09 02:46:08 +02:00
|
|
|
|
2017-11-03 22:54:20 +01:00
|
|
|
/* advertise type-5 routes if needed */
|
|
|
|
update_advertise_vrf_routes(bgp_vrf);
|
|
|
|
|
2017-10-13 13:10:03 +02:00
|
|
|
/* install all remote routes belonging to this l3vni into correspondng
|
|
|
|
* vrf */
|
|
|
|
install_routes_for_vrf(bgp_vrf);
|
2017-10-09 02:46:08 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
struct bgp *bgp_vrf = NULL; /* bgp vrf instance */
|
2019-03-06 19:10:02 +01:00
|
|
|
struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
|
2017-10-09 11:06:34 +02:00
|
|
|
struct listnode *node = NULL;
|
2018-03-30 02:13:58 +02:00
|
|
|
struct listnode *next = NULL;
|
2017-10-09 11:06:34 +02:00
|
|
|
struct bgpevpn *vpn = NULL;
|
2017-10-09 02:46:08 +02:00
|
|
|
|
|
|
|
bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
|
|
|
|
if (!bgp_vrf) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_NO_DFLT,
|
2017-10-09 02:46:08 +02:00
|
|
|
"Cannot process L3VNI %u Del - Could not find BGP instance",
|
|
|
|
l3vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 20:23:42 +02:00
|
|
|
EC_BGP_NO_DFLT,
|
2019-03-06 19:30:00 +01:00
|
|
|
"Cannot process L3VNI %u Del - Could not find EVPN BGP instance",
|
2017-10-09 11:06:34 +02:00
|
|
|
l3vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 19:59:48 +02:00
|
|
|
if (CHECK_FLAG(bgp_evpn->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
|
|
|
|
flog_err(EC_BGP_NO_DFLT,
|
|
|
|
"Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down",
|
|
|
|
l3vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-06-30 08:58:54 +02:00
|
|
|
/* Remove remote routes from BGT VRF even if BGP_VRF_AUTO is configured,
|
2018-10-03 00:15:34 +02:00
|
|
|
* bgp_delete would not remove/decrement bgp_path_info of the ip_prefix
|
2018-06-30 08:58:54 +02:00
|
|
|
* routes. This will uninstalling the routes from zebra and decremnt the
|
|
|
|
* bgp info count.
|
2017-12-27 20:47:10 +01:00
|
|
|
*/
|
2018-06-30 08:58:54 +02:00
|
|
|
uninstall_routes_for_vrf(bgp_vrf);
|
2017-10-13 13:10:03 +02:00
|
|
|
|
2017-11-03 22:54:20 +01:00
|
|
|
/* delete/withdraw all type-5 routes */
|
|
|
|
delete_withdraw_vrf_routes(bgp_vrf);
|
|
|
|
|
2023-05-08 05:26:25 +02:00
|
|
|
/* Tunnel is no longer active.
|
|
|
|
* Delete VTEP-IP from EVPN underlay's tip_hash.
|
|
|
|
*/
|
|
|
|
bgp_tip_del(bgp_evpn, &bgp_vrf->originator_ip);
|
|
|
|
|
2017-10-09 02:46:08 +02:00
|
|
|
/* remove the l3vni from vrf instance */
|
|
|
|
bgp_vrf->l3vni = 0;
|
|
|
|
|
|
|
|
/* remove the Rmac from the BGP vrf */
|
|
|
|
memset(&bgp_vrf->rmac, 0, sizeof(struct ethaddr));
|
2019-08-05 01:51:33 +02:00
|
|
|
memset(&bgp_vrf->evpn_info->pip_rmac_zebra, 0, ETH_ALEN);
|
|
|
|
if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static) &&
|
|
|
|
!is_zero_mac(&bgp_vrf->evpn_info->pip_rmac))
|
|
|
|
memset(&bgp_vrf->evpn_info->pip_rmac, 0, ETH_ALEN);
|
2017-10-09 02:46:08 +02:00
|
|
|
|
2018-12-07 03:03:58 +01:00
|
|
|
/* remove default import RT or Unmap non-default import RT */
|
2018-06-01 03:32:37 +02:00
|
|
|
if (!list_isempty(bgp_vrf->vrf_import_rtl)) {
|
2017-10-10 03:12:05 +02:00
|
|
|
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
2018-12-07 03:03:58 +01:00
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
|
|
|
|
list_delete_all_node(bgp_vrf->vrf_import_rtl);
|
2017-10-09 11:49:39 +02:00
|
|
|
}
|
2018-12-07 03:03:58 +01:00
|
|
|
|
|
|
|
/* remove default export RT */
|
|
|
|
if (!list_isempty(bgp_vrf->vrf_export_rtl) &&
|
|
|
|
!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
|
2017-10-13 13:10:03 +02:00
|
|
|
list_delete_all_node(bgp_vrf->vrf_export_rtl);
|
2017-10-09 11:49:39 +02:00
|
|
|
}
|
2017-10-09 02:46:08 +02:00
|
|
|
|
2017-10-09 11:06:34 +02:00
|
|
|
/* update all corresponding local mac-ip routes */
|
2018-02-06 23:28:22 +01:00
|
|
|
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) {
|
|
|
|
UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
|
2019-03-06 19:10:02 +01:00
|
|
|
update_routes_for_vni(bgp_evpn, vpn);
|
2018-02-06 23:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
2017-10-09 02:46:08 +02:00
|
|
|
|
2018-03-30 02:13:58 +02:00
|
|
|
/* If any L2VNIs point to this instance, unlink them. */
|
|
|
|
for (ALL_LIST_ELEMENTS(bgp_vrf->l2vnis, node, next, vpn))
|
|
|
|
bgpevpn_unlink_from_l3vni(vpn);
|
|
|
|
|
2019-08-27 23:41:00 +02:00
|
|
|
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
|
|
|
|
|
2017-10-09 02:46:08 +02:00
|
|
|
/* Delete the instance if it was autocreated */
|
|
|
|
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
|
|
|
|
bgp_delete(bgp_vrf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-05-27 11:03:30 +02:00
|
|
|
/*
|
|
|
|
* When bgp instance goes down also clean up what might have been left over
|
|
|
|
* from evpn.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_instance_down(struct bgp *bgp)
|
|
|
|
{
|
|
|
|
/* If we have a stale local vni, delete it */
|
|
|
|
if (bgp->l3vni)
|
|
|
|
bgp_evpn_local_l3vni_del(bgp->l3vni, bgp->vrf_id);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/*
|
|
|
|
* Handle del of a local VNI.
|
|
|
|
*/
|
|
|
|
int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
|
|
|
|
/* Locate VNI hash */
|
|
|
|
vpn = bgp_evpn_lookup_vni(bgp, vni);
|
2022-11-13 05:52:09 +01:00
|
|
|
if (!vpn)
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Remove all local EVPN routes and schedule for processing (to
|
|
|
|
* withdraw from peers).
|
|
|
|
*/
|
|
|
|
delete_routes_for_vni(bgp, vpn);
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
bgp_evpn_unlink_from_vni_svi_hash(bgp, vpn);
|
|
|
|
|
2021-01-11 09:14:05 +01:00
|
|
|
vpn->svi_ifindex = 0;
|
2023-05-08 05:26:25 +02:00
|
|
|
/* Tunnel is no longer active.
|
|
|
|
* Delete VTEP-IP from EVPN underlay's tip_hash.
|
2017-08-17 08:19:58 +02:00
|
|
|
*/
|
|
|
|
bgp_tip_del(bgp, &vpn->originator_ip);
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Clear "live" flag and see if hash needs to be freed. */
|
|
|
|
UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE);
|
|
|
|
if (!is_vni_configured(vpn))
|
|
|
|
bgp_evpn_free(bgp, vpn);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-01-25 07:41:44 +01:00
|
|
|
* Handle add (or update) of a local VNI. The VNI changes we care
|
|
|
|
* about are for the local-tunnel-ip and the (tenant) VRF.
|
2017-05-15 23:34:04 +02:00
|
|
|
*/
|
|
|
|
int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
|
2019-03-19 19:08:24 +01:00
|
|
|
struct in_addr originator_ip,
|
|
|
|
vrf_id_t tenant_vrf_id,
|
2021-01-11 09:14:05 +01:00
|
|
|
struct in_addr mcast_grp,
|
|
|
|
ifindex_t svi_ifindex)
|
2017-05-15 23:34:04 +02:00
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
struct prefix_evpn p;
|
2023-03-27 21:49:41 +02:00
|
|
|
struct bgp *bgp_evpn = bgp_get_evpn();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Lookup VNI. If present and no change, exit. */
|
|
|
|
vpn = bgp_evpn_lookup_vni(bgp, vni);
|
2017-07-07 01:33:50 +02:00
|
|
|
if (vpn) {
|
2017-10-08 05:26:16 +02:00
|
|
|
|
2018-01-25 07:41:44 +01:00
|
|
|
if (is_vni_live(vpn)
|
|
|
|
&& IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)
|
2019-03-19 19:08:24 +01:00
|
|
|
&& IPV4_ADDR_SAME(&vpn->mcast_grp, &mcast_grp)
|
2021-01-11 09:14:05 +01:00
|
|
|
&& vpn->tenant_vrf_id == tenant_vrf_id
|
|
|
|
&& vpn->svi_ifindex == svi_ifindex)
|
2018-01-25 07:41:44 +01:00
|
|
|
/* Probably some other param has changed that we don't
|
|
|
|
* care about. */
|
|
|
|
return 0;
|
|
|
|
|
2019-03-19 19:08:24 +01:00
|
|
|
bgp_evpn_mcast_grp_change(bgp, vpn, mcast_grp);
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
if (vpn->svi_ifindex != svi_ifindex) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unresolve all the gateway IP nexthops for this VNI
|
|
|
|
* for old SVI
|
|
|
|
*/
|
2021-05-12 00:26:29 +02:00
|
|
|
bgp_evpn_remote_ip_hash_iterate(
|
|
|
|
vpn,
|
|
|
|
(void (*)(struct hash_bucket *, void *))
|
|
|
|
bgp_evpn_remote_ip_hash_unlink_nexthop,
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
vpn);
|
|
|
|
bgp_evpn_unlink_from_vni_svi_hash(bgp, vpn);
|
|
|
|
vpn->svi_ifindex = svi_ifindex;
|
|
|
|
bgp_evpn_link_to_vni_svi_hash(bgp, vpn);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Resolve all the gateway IP nexthops for this VNI
|
|
|
|
* for new SVI
|
|
|
|
*/
|
2021-05-12 00:26:29 +02:00
|
|
|
bgp_evpn_remote_ip_hash_iterate(
|
|
|
|
vpn,
|
|
|
|
(void (*)(struct hash_bucket *, void *))
|
|
|
|
bgp_evpn_remote_ip_hash_link_nexthop,
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
vpn);
|
|
|
|
}
|
2021-01-11 09:14:05 +01:00
|
|
|
|
2018-01-25 07:41:44 +01:00
|
|
|
/* Update tenant_vrf_id if it has changed. */
|
2017-10-09 05:43:14 +02:00
|
|
|
if (vpn->tenant_vrf_id != tenant_vrf_id) {
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Unresolve all the gateway IP nexthops for this VNI
|
|
|
|
* in old tenant vrf
|
|
|
|
*/
|
2021-05-12 00:26:29 +02:00
|
|
|
bgp_evpn_remote_ip_hash_iterate(
|
|
|
|
vpn,
|
|
|
|
(void (*)(struct hash_bucket *, void *))
|
|
|
|
bgp_evpn_remote_ip_hash_unlink_nexthop,
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
vpn);
|
2017-10-09 05:43:14 +02:00
|
|
|
bgpevpn_unlink_from_l3vni(vpn);
|
2017-10-08 05:26:16 +02:00
|
|
|
vpn->tenant_vrf_id = tenant_vrf_id;
|
2017-10-09 05:43:14 +02:00
|
|
|
bgpevpn_link_to_l3vni(vpn);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Resolve all the gateway IP nexthops for this VNI
|
|
|
|
* in new tenant vrf
|
|
|
|
*/
|
2021-05-12 00:26:29 +02:00
|
|
|
bgp_evpn_remote_ip_hash_iterate(
|
|
|
|
vpn,
|
|
|
|
(void (*)(struct hash_bucket *, void *))
|
|
|
|
bgp_evpn_remote_ip_hash_link_nexthop,
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
vpn);
|
2017-10-09 05:43:14 +02:00
|
|
|
}
|
2017-10-08 05:26:16 +02:00
|
|
|
|
2018-01-25 07:41:44 +01:00
|
|
|
/* If tunnel endpoint IP has changed, update (and delete prior
|
|
|
|
* type-3 route, if needed.)
|
|
|
|
*/
|
2023-05-08 05:26:25 +02:00
|
|
|
handle_tunnel_ip_change(NULL, bgp, vpn, originator_ip);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-01-25 07:41:44 +01:00
|
|
|
/* Update all routes with new endpoint IP and/or export RT
|
|
|
|
* for VRFs
|
|
|
|
*/
|
|
|
|
if (is_vni_live(vpn))
|
|
|
|
update_routes_for_vni(bgp, vpn);
|
2022-05-06 11:52:12 +02:00
|
|
|
} else {
|
|
|
|
/* Create or update as appropriate. */
|
2019-03-19 19:08:24 +01:00
|
|
|
vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id,
|
2022-05-06 11:52:12 +02:00
|
|
|
mcast_grp, svi_ifindex);
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-17 08:19:58 +02:00
|
|
|
/* if the VNI is live already, there is nothing more to do */
|
2017-07-07 01:33:50 +02:00
|
|
|
if (is_vni_live(vpn))
|
|
|
|
return 0;
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* Mark as "live" */
|
|
|
|
SET_FLAG(vpn->flags, VNI_FLAG_LIVE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-05-08 05:26:25 +02:00
|
|
|
/* Tunnel is newly active.
|
|
|
|
* Add TIP to tip_hash of the EVPN underlay instance (bgp_get_evpn()).
|
|
|
|
*/
|
2023-01-25 19:07:43 +01:00
|
|
|
if (bgp_tip_add(bgp, &originator_ip))
|
|
|
|
/* The originator_ip was not already present in the
|
|
|
|
* bgp martian next-hop table as a tunnel-ip, so we
|
|
|
|
* need to go back and filter routes matching the new
|
|
|
|
* martian next-hop.
|
|
|
|
*/
|
2023-03-27 21:49:41 +02:00
|
|
|
bgp_filter_evpn_routes_upon_martian_change(bgp_evpn,
|
|
|
|
BGP_MARTIAN_TUN_IP);
|
2017-08-17 08:19:58 +02:00
|
|
|
|
2018-10-05 01:20:12 +02:00
|
|
|
/*
|
|
|
|
* Create EVPN type-3 route and schedule for processing.
|
|
|
|
*
|
|
|
|
* RT-3 only if doing head-end replication
|
|
|
|
*/
|
2019-03-26 21:26:33 +01:00
|
|
|
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
|
|
|
|
== VXLAN_FLOOD_HEAD_END_REPL) {
|
2018-10-05 01:20:12 +02:00
|
|
|
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
bgpd: support for Ethernet Segments and Type-1/EAD routes
This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
active-active multihoming
- Initial infra for consistency checking. Consistency checking
is a fundamental feature for active-active solutions like MLAG.
We will try to levarage the info in the EAD-ES/EAD-EVI routes to
detect inconsitencies in access config across VTEPs attached to
the same Ethernet Segment.
Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.
EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)
3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)
Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-03-27 22:43:50 +01:00
|
|
|
if (update_evpn_route(bgp, vpn, &p, 0, 0, NULL)) {
|
2018-10-05 01:20:12 +02:00
|
|
|
flog_err(EC_BGP_EVPN_ROUTE_CREATE,
|
|
|
|
"%u: Type3 route creation failure for VNI %u",
|
|
|
|
bgp->vrf_id, vni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 23:34:04 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
/* If we have learnt and retained remote routes (VTEPs, MACs) for this
|
|
|
|
* VNI,
|
|
|
|
* install them.
|
|
|
|
*/
|
|
|
|
install_routes_for_vni(bgp, vpn);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-28 02:11:48 +02:00
|
|
|
/* If we are advertising gateway mac-ip
|
|
|
|
It needs to be conveyed again to zebra */
|
|
|
|
bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip, vpn->vni);
|
|
|
|
|
2019-08-20 03:24:28 +02:00
|
|
|
/* advertise svi mac-ip knob to zebra */
|
|
|
|
bgp_zebra_advertise_svi_macip(bgp, vpn->advertise_svi_macip, vpn->vni);
|
|
|
|
|
2017-05-15 23:34:04 +02:00
|
|
|
return 0;
|
2016-09-05 14:19:40 +02:00
|
|
|
}
|
2017-05-15 23:27:51 +02:00
|
|
|
|
2018-10-05 01:20:12 +02:00
|
|
|
/*
|
|
|
|
* Handle change in setting for BUM handling. The supported values
|
|
|
|
* are head-end replication and dropping all BUM packets. Any change
|
|
|
|
* should be registered with zebra. Also, if doing head-end replication,
|
|
|
|
* need to advertise local VNIs as EVPN RT-3 wheras, if BUM packets are
|
|
|
|
* to be dropped, the RT-3s must be withdrawn.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_flood_control_change(struct bgp *bgp)
|
|
|
|
{
|
|
|
|
zlog_info("L2VPN EVPN BUM handling is %s",
|
|
|
|
bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL ?
|
|
|
|
"Flooding" : "Flooding Disabled");
|
|
|
|
|
|
|
|
bgp_zebra_vxlan_flood_control(bgp, bgp->vxlan_flood_ctrl);
|
|
|
|
if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL)
|
|
|
|
hash_iterate(bgp->vnihash, create_advertise_type3, bgp);
|
|
|
|
else if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_DISABLED)
|
|
|
|
hash_iterate(bgp->vnihash, delete_withdraw_type3, bgp);
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:30:19 +02:00
|
|
|
/*
|
|
|
|
* Cleanup EVPN information on disable - Need to delete and withdraw
|
|
|
|
* EVPN routes from peers.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_cleanup_on_disable(struct bgp *bgp)
|
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *,
|
2017-07-22 14:52:33 +02:00
|
|
|
void *))cleanup_vni_on_disable,
|
|
|
|
bgp);
|
2017-05-15 23:30:19 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:27:51 +02:00
|
|
|
/*
|
|
|
|
* Cleanup EVPN information - invoked at the time of bgpd exit or when the
|
|
|
|
* BGP instance (default) is being freed.
|
|
|
|
*/
|
|
|
|
void bgp_evpn_cleanup(struct bgp *bgp)
|
|
|
|
{
|
2018-06-01 03:32:37 +02:00
|
|
|
hash_iterate(bgp->vnihash,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))free_vni_entry,
|
2018-06-01 03:32:37 +02:00
|
|
|
bgp);
|
|
|
|
|
2023-03-21 13:54:21 +01:00
|
|
|
hash_clean_and_free(&bgp->import_rt_hash,
|
|
|
|
(void (*)(void *))hash_import_rt_free);
|
|
|
|
|
|
|
|
hash_clean_and_free(&bgp->vrf_import_rt_hash,
|
|
|
|
(void (*)(void *))hash_vrf_import_rt_free);
|
|
|
|
|
|
|
|
hash_clean_and_free(&bgp->vni_svi_hash,
|
|
|
|
(void (*)(void *))hash_evpn_free);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Why is the vnihash freed at the top of this function and
|
|
|
|
* then deleted here?
|
|
|
|
*/
|
|
|
|
hash_clean_and_free(&bgp->vnihash, NULL);
|
2018-06-01 03:32:37 +02:00
|
|
|
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&bgp->vrf_import_rtl);
|
|
|
|
list_delete(&bgp->vrf_export_rtl);
|
|
|
|
list_delete(&bgp->l2vnis);
|
2022-11-22 11:20:51 +01:00
|
|
|
|
2023-05-08 04:51:28 +02:00
|
|
|
if (bgp->evpn_info) {
|
|
|
|
ecommunity_free(&bgp->evpn_info->soo);
|
|
|
|
XFREE(MTYPE_BGP_EVPN_INFO, bgp->evpn_info);
|
|
|
|
}
|
2023-05-08 04:28:21 +02:00
|
|
|
|
2022-11-22 11:20:51 +01:00
|
|
|
if (bgp->vrf_prd_pretty)
|
2023-11-15 20:52:10 +01:00
|
|
|
XFREE(MTYPE_BGP_NAME, bgp->vrf_prd_pretty);
|
2017-05-15 23:27:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialization for EVPN
|
|
|
|
* Create
|
|
|
|
* VNI hash table
|
|
|
|
* hash for RT to VNI
|
|
|
|
*/
|
|
|
|
void bgp_evpn_init(struct bgp *bgp)
|
|
|
|
{
|
|
|
|
bgp->vnihash =
|
|
|
|
hash_create(vni_hash_key_make, vni_hash_cmp, "BGP VNI Hash");
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
bgp->vni_svi_hash =
|
|
|
|
hash_create(vni_svi_hash_key_make, vni_svi_hash_cmp,
|
|
|
|
"BGP VNI hash based on SVI ifindex");
|
2017-05-15 23:27:51 +02:00
|
|
|
bgp->import_rt_hash =
|
|
|
|
hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
|
|
|
|
"BGP Import RT Hash");
|
2017-10-10 03:12:05 +02:00
|
|
|
bgp->vrf_import_rt_hash =
|
|
|
|
hash_create(vrf_import_rt_hash_key_make, vrf_import_rt_hash_cmp,
|
|
|
|
"BGP VRF Import RT Hash");
|
2017-10-09 03:34:29 +02:00
|
|
|
bgp->vrf_import_rtl = list_new();
|
|
|
|
bgp->vrf_import_rtl->cmp =
|
2021-02-17 22:11:49 +01:00
|
|
|
(int (*)(void *, void *))evpn_vrf_route_target_cmp;
|
|
|
|
bgp->vrf_import_rtl->del = evpn_vrf_rt_del;
|
2017-10-09 03:34:29 +02:00
|
|
|
bgp->vrf_export_rtl = list_new();
|
|
|
|
bgp->vrf_export_rtl->cmp =
|
2021-02-17 22:11:49 +01:00
|
|
|
(int (*)(void *, void *))evpn_vrf_route_target_cmp;
|
|
|
|
bgp->vrf_export_rtl->del = evpn_vrf_rt_del;
|
2017-10-09 05:43:14 +02:00
|
|
|
bgp->l2vnis = list_new();
|
2018-10-15 17:41:39 +02:00
|
|
|
bgp->l2vnis->cmp = vni_list_cmp;
|
2023-05-08 04:28:21 +02:00
|
|
|
bgp->evpn_info =
|
|
|
|
XCALLOC(MTYPE_BGP_EVPN_INFO, sizeof(struct bgp_evpn_info));
|
2018-11-01 00:53:28 +01:00
|
|
|
/* By default Duplicate Address Dection is enabled.
|
|
|
|
* Max-moves (N) 5, detection time (M) 180
|
|
|
|
* default action is warning-only
|
|
|
|
* freeze action permanently freezes address,
|
|
|
|
* and freeze time (auto-recovery) is disabled.
|
|
|
|
*/
|
|
|
|
if (bgp->evpn_info) {
|
|
|
|
bgp->evpn_info->dup_addr_detect = true;
|
|
|
|
bgp->evpn_info->dad_time = EVPN_DAD_DEFAULT_TIME;
|
|
|
|
bgp->evpn_info->dad_max_moves = EVPN_DAD_DEFAULT_MAX_MOVES;
|
|
|
|
bgp->evpn_info->dad_freeze = false;
|
|
|
|
bgp->evpn_info->dad_freeze_time = 0;
|
2018-11-01 16:28:08 +01:00
|
|
|
/* Initialize zebra vxlan */
|
|
|
|
bgp_zebra_dup_addr_detection(bgp);
|
2019-04-18 09:17:57 +02:00
|
|
|
/* Enable PIP feature by default for bgp vrf instance */
|
|
|
|
if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
|
|
|
|
struct bgp *bgp_default;
|
|
|
|
|
|
|
|
bgp->evpn_info->advertise_pip = true;
|
|
|
|
bgp_default = bgp_get_default();
|
|
|
|
if (bgp_default)
|
|
|
|
bgp->evpn_info->pip_ip = bgp_default->router_id;
|
|
|
|
}
|
2018-11-01 00:53:28 +01:00
|
|
|
}
|
2018-10-05 01:20:12 +02:00
|
|
|
|
|
|
|
/* Default BUM handling is to do head-end replication. */
|
|
|
|
bgp->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;
|
2020-09-12 19:36:01 +02:00
|
|
|
|
|
|
|
bgp_evpn_nh_init(bgp);
|
2017-05-15 23:27:51 +02:00
|
|
|
}
|
2017-10-10 03:12:05 +02:00
|
|
|
|
|
|
|
void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
|
|
|
|
{
|
|
|
|
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
2020-09-12 19:36:01 +02:00
|
|
|
bgp_evpn_nh_finish(bgp_vrf);
|
2017-10-10 03:12:05 +02:00
|
|
|
}
|
2019-09-11 09:01:39 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the prefixlen of the ip prefix carried within the type5 evpn route.
|
|
|
|
*/
|
2020-03-24 12:58:08 +01:00
|
|
|
int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx)
|
2019-09-11 09:01:39 +02:00
|
|
|
{
|
|
|
|
struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
|
|
|
|
|
|
|
|
if (!pfx || pfx->family != AF_EVPN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return evp->prefix.prefix_addr.ip_prefix_length;
|
|
|
|
}
|
2019-11-14 01:46:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Should we register nexthop for this EVPN prefix for nexthop tracking?
|
|
|
|
*/
|
2020-03-22 02:56:36 +01:00
|
|
|
bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
|
2019-11-14 01:46:56 +01:00
|
|
|
{
|
|
|
|
struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
|
|
|
|
|
|
|
|
/*
|
2020-05-26 08:00:49 +02:00
|
|
|
* EVPN routes should be marked as valid only if the nexthop is
|
|
|
|
* reachable. Only if this happens, the route should be imported
|
|
|
|
* (into VNI or VRF routing tables) and/or advertised.
|
2022-04-12 08:11:57 +02:00
|
|
|
* Note: This is currently applied for EVPN type-1, type-2,
|
|
|
|
* type-3, type-4 and type-5 routes.
|
|
|
|
* It may be tweaked later on for other routes, or
|
2020-05-26 08:00:49 +02:00
|
|
|
* even removed completely when all routes are handled.
|
2019-11-14 01:46:56 +01:00
|
|
|
*/
|
2021-06-08 23:14:58 +02:00
|
|
|
if (pfx && pfx->family == AF_EVPN
|
|
|
|
&& (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
|| evp->prefix.route_type == BGP_EVPN_AD_ROUTE
|
|
|
|
|| evp->prefix.route_type == BGP_EVPN_ES_ROUTE
|
|
|
|
|| evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
|
|
|
|
|| evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
|
2019-11-14 01:46:56 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
static void *bgp_evpn_remote_ip_hash_alloc(void *p)
|
|
|
|
{
|
|
|
|
const struct evpn_remote_ip *key = (const struct evpn_remote_ip *)p;
|
|
|
|
struct evpn_remote_ip *ip;
|
|
|
|
|
|
|
|
ip = XMALLOC(MTYPE_EVPN_REMOTE_IP, sizeof(struct evpn_remote_ip));
|
|
|
|
*ip = *key;
|
|
|
|
ip->macip_path_list = list_new();
|
|
|
|
|
|
|
|
return ip;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int bgp_evpn_remote_ip_hash_key_make(const void *p)
|
|
|
|
{
|
|
|
|
const struct evpn_remote_ip *ip = p;
|
|
|
|
const struct ipaddr *addr = &ip->addr;
|
|
|
|
|
|
|
|
if (IS_IPADDR_V4(addr))
|
|
|
|
return jhash_1word(addr->ipaddr_v4.s_addr, 0);
|
|
|
|
|
|
|
|
return jhash2(addr->ipaddr_v6.s6_addr32,
|
|
|
|
array_size(addr->ipaddr_v6.s6_addr32), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool bgp_evpn_remote_ip_hash_cmp(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
const struct evpn_remote_ip *ip1 = p1;
|
|
|
|
const struct evpn_remote_ip *ip2 = p2;
|
|
|
|
|
2022-01-18 09:36:13 +01:00
|
|
|
return !ipaddr_cmp(&ip1->addr, &ip2->addr);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *vpn)
|
|
|
|
{
|
2021-05-12 00:26:29 +02:00
|
|
|
if (!evpn_resolve_overlay_index())
|
|
|
|
return;
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
vpn->remote_ip_hash = hash_create(bgp_evpn_remote_ip_hash_key_make,
|
|
|
|
bgp_evpn_remote_ip_hash_cmp,
|
|
|
|
"BGP EVPN remote IP hash");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_remote_ip_hash_free(struct hash_bucket *bucket, void *args)
|
|
|
|
{
|
|
|
|
struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
|
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)args;
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
|
|
|
|
|
|
|
|
list_delete(&ip->macip_path_list);
|
|
|
|
|
|
|
|
hash_release(vpn->remote_ip_hash, ip);
|
|
|
|
XFREE(MTYPE_EVPN_REMOTE_IP, ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *vpn)
|
|
|
|
{
|
2021-05-12 00:26:29 +02:00
|
|
|
if (!evpn_resolve_overlay_index() || vpn->remote_ip_hash == NULL)
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
hash_iterate(vpn->remote_ip_hash,
|
|
|
|
(void (*)(struct hash_bucket *, void *))bgp_evpn_remote_ip_hash_free,
|
|
|
|
vpn);
|
|
|
|
|
|
|
|
hash_free(vpn->remote_ip_hash);
|
|
|
|
vpn->remote_ip_hash = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add a remote MAC/IP route to hash table */
|
|
|
|
static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
|
|
|
|
struct bgp_path_info *pi)
|
|
|
|
{
|
|
|
|
struct evpn_remote_ip tmp;
|
|
|
|
struct evpn_remote_ip *ip;
|
|
|
|
struct prefix_evpn *evp;
|
|
|
|
|
2021-05-12 00:26:29 +02:00
|
|
|
if (!evpn_resolve_overlay_index())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pi->type != ZEBRA_ROUTE_BGP || pi->sub_type != BGP_ROUTE_IMPORTED
|
|
|
|
|| !CHECK_FLAG(pi->flags, BGP_PATH_VALID))
|
|
|
|
return;
|
|
|
|
|
2023-07-31 14:34:48 +02:00
|
|
|
evp = (struct prefix_evpn *)&pi->net->rn->p;
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
if (evp->family != AF_EVPN
|
|
|
|
|| evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
|| is_evpn_prefix_ipaddr_none(evp))
|
|
|
|
return;
|
|
|
|
|
|
|
|
tmp.addr = evp->prefix.macip_addr.ip;
|
|
|
|
ip = hash_lookup(vpn->remote_ip_hash, &tmp);
|
|
|
|
if (ip) {
|
|
|
|
if (listnode_lookup(ip->macip_path_list, pi) != NULL)
|
|
|
|
return;
|
|
|
|
(void)listnode_add(ip->macip_path_list, pi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ip = hash_get(vpn->remote_ip_hash, &tmp, bgp_evpn_remote_ip_hash_alloc);
|
|
|
|
(void)listnode_add(ip->macip_path_list, pi);
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete a remote MAC/IP route from hash table */
|
|
|
|
static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
|
|
|
|
struct bgp_path_info *pi)
|
|
|
|
{
|
|
|
|
struct evpn_remote_ip tmp;
|
|
|
|
struct evpn_remote_ip *ip;
|
|
|
|
struct prefix_evpn *evp;
|
|
|
|
|
2021-05-12 00:26:29 +02:00
|
|
|
if (!evpn_resolve_overlay_index())
|
|
|
|
return;
|
|
|
|
|
2023-07-31 14:34:48 +02:00
|
|
|
evp = (struct prefix_evpn *)&pi->net->rn->p;
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
if (evp->family != AF_EVPN
|
|
|
|
|| evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
|
|
|
|
|| is_evpn_prefix_ipaddr_none(evp))
|
|
|
|
return;
|
|
|
|
|
|
|
|
tmp.addr = evp->prefix.macip_addr.ip;
|
|
|
|
ip = hash_lookup(vpn->remote_ip_hash, &tmp);
|
|
|
|
if (ip == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
listnode_delete(ip->macip_path_list, pi);
|
|
|
|
|
|
|
|
if (ip->macip_path_list->count == 0) {
|
|
|
|
bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
|
|
|
|
hash_release(vpn->remote_ip_hash, ip);
|
2022-12-15 19:49:43 +01:00
|
|
|
list_delete(&ip->macip_path_list);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
XFREE(MTYPE_EVPN_REMOTE_IP, ip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-12 00:26:29 +02:00
|
|
|
static void bgp_evpn_remote_ip_hash_iterate(struct bgpevpn *vpn,
|
|
|
|
void (*func)(struct hash_bucket *,
|
|
|
|
void *),
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
if (!evpn_resolve_overlay_index())
|
|
|
|
return;
|
|
|
|
|
|
|
|
hash_iterate(vpn->remote_ip_hash, func, arg);
|
|
|
|
}
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
static void show_remote_ip_entry(struct hash_bucket *bucket, void *args)
|
|
|
|
{
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct bgp_path_info *pi = NULL;
|
|
|
|
struct vty *vty = (struct vty *)args;
|
|
|
|
struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
|
|
|
|
|
|
|
|
vty_out(vty, " Remote IP: %s\n",
|
|
|
|
ipaddr2str(&ip->addr, buf, sizeof(buf)));
|
|
|
|
vty_out(vty, " Linked MAC/IP routes:\n");
|
2022-08-25 12:46:58 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(ip->macip_path_list, node, pi))
|
2023-07-31 14:34:48 +02:00
|
|
|
vty_out(vty, " %pFX\n", &pi->net->rn->p);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket, void *args)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
|
|
|
struct vty *vty = (struct vty *)args;
|
|
|
|
|
|
|
|
vty_out(vty, "VNI: %u\n", vpn->vni);
|
2021-05-12 00:26:29 +02:00
|
|
|
bgp_evpn_remote_ip_hash_iterate(
|
|
|
|
vpn,
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))show_remote_ip_entry,
|
|
|
|
vty);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_remote_ip_hash_link_nexthop(struct hash_bucket *bucket,
|
|
|
|
void *args)
|
|
|
|
{
|
|
|
|
struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
|
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)args;
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,
|
|
|
|
void *args)
|
|
|
|
{
|
|
|
|
struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
|
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)args;
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int vni_svi_hash_key_make(const void *p)
|
|
|
|
{
|
|
|
|
const struct bgpevpn *vpn = p;
|
|
|
|
|
|
|
|
return jhash_1word(vpn->svi_ifindex, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool vni_svi_hash_cmp(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
const struct bgpevpn *vpn1 = p1;
|
|
|
|
const struct bgpevpn *vpn2 = p2;
|
|
|
|
|
|
|
|
return (vpn1->svi_ifindex == vpn2->svi_ifindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bgpevpn *bgp_evpn_vni_svi_hash_lookup(struct bgp *bgp,
|
|
|
|
ifindex_t svi)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn;
|
|
|
|
struct bgpevpn tmp;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
tmp.svi_ifindex = svi;
|
|
|
|
vpn = hash_lookup(bgp->vni_svi_hash, &tmp);
|
|
|
|
return vpn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_link_to_vni_svi_hash(struct bgp *bgp, struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
if (vpn->svi_ifindex == 0)
|
|
|
|
return;
|
|
|
|
|
*: remove the checking returned value for hash_get()
Firstly, *keep no change* for `hash_get()` with NULL
`alloc_func`.
Only focus on cases with non-NULL `alloc_func` of
`hash_get()`.
Since `hash_get()` with non-NULL `alloc_func` parameter
shall not fail, just ignore the returned value of it.
The returned value must not be NULL.
So in this case, remove the unnecessary checking NULL
or not for the returned value and add `void` in front
of it.
Importantly, also *keep no change* for the two cases with
non-NULL `alloc_func` -
1) Use `assert(<returned_data> == <searching_data>)` to
ensure it is a created node, not a found node.
Refer to `isis_vertex_queue_insert()` of isisd, there
are many examples of this case in isid.
2) Use `<returned_data> != <searching_data>` to judge it
is a found node, then free <searching_data>.
Refer to `aspath_intern()` of bgpd, there are many
examples of this case in bgpd.
Here, <returned_data> is the returned value from `hash_get()`,
and <searching_data> is the data, which is to be put into
hash table.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-04-21 08:37:12 +02:00
|
|
|
(void)hash_get(bgp->vni_svi_hash, vpn, hash_alloc_intern);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void bgp_evpn_unlink_from_vni_svi_hash(struct bgp *bgp,
|
|
|
|
struct bgpevpn *vpn)
|
|
|
|
{
|
|
|
|
if (vpn->svi_ifindex == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hash_release(bgp->vni_svi_hash, vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_show_vni_svi_hash(struct hash_bucket *bucket, void *args)
|
|
|
|
{
|
|
|
|
struct bgpevpn *evpn = (struct bgpevpn *)bucket->data;
|
|
|
|
struct vty *vty = (struct vty *)args;
|
|
|
|
|
|
|
|
vty_out(vty, "SVI: %u VNI: %u\n", evpn->svi_ifindex, evpn->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function is called for a bgp_nexthop_cache entry when the nexthop is
|
|
|
|
* gateway IP overlay index.
|
|
|
|
* This function returns true if there is a remote MAC/IP route for the gateway
|
|
|
|
* IP in the EVI of the nexthop SVI.
|
|
|
|
*/
|
|
|
|
bool bgp_evpn_is_gateway_ip_resolved(struct bgp_nexthop_cache *bnc)
|
|
|
|
{
|
|
|
|
struct bgp *bgp_evpn = NULL;
|
|
|
|
struct bgpevpn *vpn = NULL;
|
|
|
|
struct evpn_remote_ip tmp;
|
|
|
|
struct prefix *p;
|
|
|
|
|
2021-05-12 00:26:29 +02:00
|
|
|
if (!evpn_resolve_overlay_index())
|
|
|
|
return false;
|
|
|
|
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
if (!bnc->nexthop || bnc->nexthop->ifindex == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bgp_evpn = bgp_get_evpn();
|
|
|
|
if (!bgp_evpn)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gateway IP is resolved by nht over SVI interface.
|
|
|
|
* Use this SVI to find corresponding EVI(L2 context)
|
|
|
|
*/
|
|
|
|
vpn = bgp_evpn_vni_svi_hash_lookup(bgp_evpn, bnc->nexthop->ifindex);
|
|
|
|
if (!vpn)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vpn->bgp_vrf != bnc->bgp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the gateway IP is present in the EVI remote_ip_hash table
|
|
|
|
* which stores all the remote IP addresses received via MAC/IP routes
|
|
|
|
* in this EVI
|
|
|
|
*/
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
p = &bnc->prefix;
|
|
|
|
if (p->family == AF_INET) {
|
|
|
|
tmp.addr.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(tmp.addr.ipaddr_v4), &(p->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (p->family == AF_INET6) {
|
|
|
|
tmp.addr.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(tmp.addr.ipaddr_v6), &(p->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (hash_lookup(vpn->remote_ip_hash, &tmp) == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resolve/Unresolve nexthops when a MAC/IP route is added/deleted */
|
|
|
|
static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
|
|
|
|
struct ipaddr *addr,
|
|
|
|
bool resolve)
|
|
|
|
{
|
|
|
|
afi_t afi;
|
|
|
|
struct prefix p;
|
|
|
|
struct bgp_nexthop_cache *bnc;
|
|
|
|
struct bgp_nexthop_cache_head *tree = NULL;
|
|
|
|
|
|
|
|
if (!vpn->bgp_vrf || vpn->svi_ifindex == 0)
|
|
|
|
return;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&p, 0, sizeof(p));
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
if (addr->ipa_type == IPADDR_V4) {
|
|
|
|
afi = AFI_IP;
|
|
|
|
p.family = AF_INET;
|
|
|
|
memcpy(&(p.u.prefix4), &(addr->ipaddr_v4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
p.prefixlen = IPV4_MAX_BITLEN;
|
|
|
|
} else if (addr->ipa_type == IPADDR_V6) {
|
|
|
|
afi = AFI_IP6;
|
|
|
|
p.family = AF_INET6;
|
|
|
|
memcpy(&(p.u.prefix6), &(addr->ipaddr_v6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
p.prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
} else
|
|
|
|
return;
|
|
|
|
|
|
|
|
tree = &vpn->bgp_vrf->nexthop_cache_table[afi];
|
2022-07-21 21:42:51 +02:00
|
|
|
bnc = bnc_find(tree, &p, 0, 0);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
if (!bnc || !bnc->is_evpn_gwip_nexthop)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!bnc->nexthop || bnc->nexthop->ifindex != vpn->svi_ifindex)
|
|
|
|
return;
|
|
|
|
|
2022-08-25 12:46:58 +02:00
|
|
|
if (BGP_DEBUG(nht, NHT))
|
|
|
|
zlog_debug("%s(%u): vni %u mac/ip %s for NH %pFX",
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
vpn->bgp_vrf->name_pretty, vpn->tenant_vrf_id,
|
2022-08-25 12:46:58 +02:00
|
|
|
vpn->vni, (resolve ? "add" : "delete"),
|
|
|
|
&bnc->prefix);
|
bgpd: EVPN route type-5 to type-2 recursive resolution using gateway IP
When EVPN prefix route with a gateway IP overlay index is imported into the IP
vrf at the ingress PE, BGP nexthop of this route is set to the gateway IP.
For this vrf route to be valid, following conditions must be met.
- Gateway IP nexthop of this route should be L3 reachable, i.e., this route
should be resolved in RIB.
- A remote MAC/IP route should be present for the gateway IP address in the
EVI(L2VPN table).
To check for the first condition, gateway IP is registered with nht (nexthop
tracking) to receive the reachability notifications for this IP from zebra RIB.
If the gateway IP is reachable, zebra sends the reachability information (i.e.,
nexthop interface) for the gateway IP.
This nexthop interface should be the SVI interface.
Now, to find out type-2 route corresponding to the gateway IP, we need to fetch
the VNI for the above SVI.
To do this VNI lookup effitiently, define a hashtable of struct bgpevpn with
svi_ifindex as key.
struct hash *vni_svi_hash;
An EVI instance is added to vni_svi_hash if its svi_ifindex is nonzero.
Using this hash, we obtain struct bgpevpn corresponding to the gateway IP.
For gateway IP overlay index recursive lookup, once we find the correct EVI, we
have to lookup its route table for a MAC/IP prefix. As we have to iterate the
entire route table for every lookup, this lookup is expensive. We can optimize
this lookup by adding all the remote IP addresses in a hash table.
Following hash table is defined for this purpose in struct bgpevpn
Struct hash *remote_ip_hash;
When a MAC/IP route is installed in the EVI table, it is also added to
remote_ip_hash.
It is possible to have multiple MAC/IP routes with the same IP address because
of host move scenarios. Thus, for every address addr in remote_ip_hash, we
maintain list of all the MAC/IP routes having addr as their IP address.
Following structure defines an address in remote_ip_hash.
struct evpn_remote_ip {
struct ipaddr addr;
struct list *macip_path_list;
};
A Boolean field is added to struct bgp_nexthop_cache to indicate that the
nexthop is EVPN gateway IP overlay index.
bool is_evpn_gwip_nexthop;
A flag BGP_NEXTHOP_EVPN_INCOMPLETE is added to struct bgp_nexthop_cache.
This flag is set when the gateway IP is L3 reachable but not yet resolved by a
MAC/IP route.
Following table explains the combination of L3 and L2 reachability w.r.t.
BGP_NEXTHOP_VALID and BGP_NEXTHOP_EVPN_INCOMPLETE flags
* | MACIP resolved | MACIP unresolved
*----------------|----------------|------------------
* L3 reachable | VALID = 1 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 1
* ---------------|----------------|--------------------
* L3 unreachable | VALID = 0 | VALID = 0
* | INCOMPLETE = 0 | INCOMPLETE = 0
Procedure that we use to check if the gateway IP is resolvable by a MAC/IP
route:
- Find the EVI/L2VRF that belongs to the nexthop SVI using vni_svi_hash.
- Check if the gateway IP is present in remote_ip_hash in this EVI.
When the gateway IP is L3 reachable and it is also resolved by a MAC/IP route,
unset BGP_NEXTHOP_EVPN_INCOMPLETE flag and set BGP_NEXTHOP_VALID flag.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2021-01-11 12:51:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* MAC/IP route or SVI or tenant vrf being added to EVI.
|
|
|
|
* Set nexthop as valid only if it is already L3 reachable
|
|
|
|
*/
|
|
|
|
if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) {
|
|
|
|
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
|
|
|
|
bnc->flags |= BGP_NEXTHOP_VALID;
|
|
|
|
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
|
|
|
|
evaluate_paths(bnc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MAC/IP route or SVI or tenant vrf being deleted from EVI */
|
|
|
|
if (!resolve && bnc->flags & BGP_NEXTHOP_VALID) {
|
|
|
|
bnc->flags &= ~BGP_NEXTHOP_VALID;
|
|
|
|
bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
|
|
|
|
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
|
|
|
|
evaluate_paths(bnc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-12 00:26:29 +02:00
|
|
|
void bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
|
|
|
struct bgp_dest *dest;
|
|
|
|
struct bgp_path_info *pi;
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_hash_init(vpn);
|
|
|
|
|
2021-10-26 23:55:54 +02:00
|
|
|
for (dest = bgp_table_top(vpn->ip_table); dest;
|
2021-05-12 00:26:29 +02:00
|
|
|
dest = bgp_route_next(dest))
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
|
|
|
|
bgp_evpn_remote_ip_hash_add(vpn, pi);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
|
|
|
|
|
|
|
bgp_evpn_remote_ip_hash_destroy(vpn);
|
|
|
|
}
|
2021-04-09 01:20:53 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper function for getting the correct label index for l3vni.
|
|
|
|
*
|
|
|
|
* Returns the label with the l3vni of the path's label stack.
|
|
|
|
*
|
|
|
|
* L3vni is always last label. Type5 will only
|
|
|
|
* have one label, Type2 will have two.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels,
|
2024-02-26 18:11:09 +01:00
|
|
|
uint8_t num_labels)
|
2021-04-09 01:20:53 +02:00
|
|
|
{
|
|
|
|
if (!labels)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!num_labels)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return &labels[num_labels - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns the l3vni of the path converted from the label stack.
|
|
|
|
*/
|
|
|
|
vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi)
|
|
|
|
{
|
|
|
|
if (!pi->extra)
|
|
|
|
return 0;
|
|
|
|
|
2024-02-26 18:23:11 +01:00
|
|
|
return label2vni(
|
|
|
|
bgp_evpn_path_info_labels_get_l3vni(pi->extra->labels->label,
|
|
|
|
pi->extra->labels
|
|
|
|
->num_labels));
|
2021-04-09 01:20:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns true if the l3vni of any of this path doesn't match vrf's l3vni.
|
|
|
|
*/
|
|
|
|
static bool bgp_evpn_path_is_dvni(const struct bgp *bgp_vrf,
|
|
|
|
const struct bgp_path_info *pi)
|
|
|
|
{
|
|
|
|
vni_t vni = 0;
|
|
|
|
|
|
|
|
vni = bgp_evpn_path_info_get_l3vni(pi);
|
|
|
|
|
|
|
|
if ((vni > 0) && (vni != bgp_vrf->l3vni))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns true if the l3vni of any of the mpath's doesn't match vrf's l3vni.
|
|
|
|
*/
|
|
|
|
bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
|
|
|
|
struct bgp_path_info *mpinfo)
|
|
|
|
{
|
|
|
|
for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
|
|
|
|
if (bgp_evpn_path_is_dvni(bgp_vrf, mpinfo))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-24 06:52:34 +01:00
|
|
|
|
|
|
|
/* Upon aggregate set trigger unimport suppressed routes
|
|
|
|
* from EVPN
|
|
|
|
*/
|
|
|
|
void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi)
|
|
|
|
{
|
|
|
|
struct bgp_dest *agg_dest, *dest, *top;
|
|
|
|
const struct prefix *aggr_p;
|
|
|
|
struct bgp_aggregate *bgp_aggregate;
|
|
|
|
struct bgp_table *table;
|
|
|
|
struct bgp_path_info *pi;
|
|
|
|
|
|
|
|
if (!bgp_get_evpn() && !advertise_type5_routes(bgp, afi))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Aggregate-address table walk. */
|
|
|
|
table = bgp->rib[afi][safi];
|
|
|
|
for (agg_dest = bgp_table_top(bgp->aggregate[afi][safi]); agg_dest;
|
|
|
|
agg_dest = bgp_route_next(agg_dest)) {
|
|
|
|
bgp_aggregate = bgp_dest_get_bgp_aggregate_info(agg_dest);
|
|
|
|
|
|
|
|
if (bgp_aggregate == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
aggr_p = bgp_dest_get_prefix(agg_dest);
|
|
|
|
|
|
|
|
/* Look all nodes below the aggregate prefix in
|
|
|
|
* global AFI/SAFI table (IPv4/IPv6).
|
|
|
|
* Trigger withdrawal (this will be Type-5 routes only)
|
|
|
|
* from EVPN Global table.
|
|
|
|
*/
|
|
|
|
top = bgp_node_get(table, aggr_p);
|
|
|
|
for (dest = bgp_node_get(table, aggr_p); dest;
|
|
|
|
dest = bgp_route_next_until(dest, top)) {
|
|
|
|
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
|
|
|
|
|
|
|
|
if (dest_p->prefixlen <= aggr_p->prefixlen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
|
|
|
|
pi = pi->next) {
|
|
|
|
if (pi->sub_type == BGP_ROUTE_AGGREGATE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Only Suppressed route remove from EVPN */
|
|
|
|
if (!bgp_path_suppressed(pi))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (BGP_DEBUG(zebra, ZEBRA))
|
|
|
|
zlog_debug("%s aggregated %pFX remove suppressed route %pFX",
|
|
|
|
__func__, aggr_p, dest_p);
|
|
|
|
|
|
|
|
if (!is_route_injectable_into_evpn_non_supp(pi))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bgp_evpn_withdraw_type5_route(bgp, dest_p, afi,
|
|
|
|
safi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|