forked from Mirror/frr
bgpd: Ignore EVPN routes from CLAG peer when VNI comes up
There are two parts to this commit: 1. create a database of self tunnel-ip for used in martian nexthop check In a CLAG setup, the tunnel-ip (VNI UP) notification comes before the clag-anycast-ip comes up in the system. This was causing our self next hop check to fail and we were instaling routes with martian nexthop in zebra. We need to keep this info in a seperate database for all local tunnel-ip. This database will be used in parallel with the self next hop database to martian nexthop checks. 2. When a local VNI comes up, update the tunnel-ip database and filter routes in the RD table if necessary In case of EVPN we might receive routes from clag peer before the clag-anycast ip and VNI is up on the system. We will store the routes in the RD table for later processing. When VNI comes UP, we loop thorugh all the routes and install them in zebra if required. However, we were missing the martian nexthop check in this code path. From now onwards, when a VNI comes UP, we will first update the tunnel-ip database We then loop through all the routes in RD table and apply martian next hop filter if required. Things not covered in this commit but are required: This processing is needed in general when an address becomes a connected address. We need to loop through all the routes in BGP and apply martian nexthop filter if necessary. This will be taken care in a seperate bug Ticket:CM-17271/CM-16911 Reviewed By: ccr-6542 Testing Done: Manual Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
parent
0a97666de7
commit
db0e1937ca
109
bgpd/bgp_evpn.c
109
bgpd/bgp_evpn.c
|
@ -46,6 +46,7 @@
|
|||
#include "bgpd/bgp_debug.h"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_zebra.h"
|
||||
#include "bgpd/bgp_nexthop.h"
|
||||
|
||||
/*
|
||||
* Definitions and external declarations.
|
||||
|
@ -1200,6 +1201,13 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Update the tunnel-ip hash */
|
||||
bgp_tip_del(bgp, &vpn->originator_ip);
|
||||
bgp_tip_add(bgp, &originator_ip);
|
||||
|
||||
/* filter routes as martian nexthop db has changed */
|
||||
bgp_filter_evpn_routes_upon_martian_nh_change(bgp);
|
||||
|
||||
/* Need to withdraw type-3 route as the originator IP is part
|
||||
* of the key.
|
||||
*/
|
||||
|
@ -1392,12 +1400,12 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
|
|||
bgp_evpn_route_type rtype,
|
||||
int install)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct bgp_node *rd_rn, *rn;
|
||||
struct bgp_table *table;
|
||||
struct bgp_info *ri;
|
||||
int ret;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct bgp_node *rd_rn, *rn;
|
||||
struct bgp_table *table;
|
||||
struct bgp_info *ri;
|
||||
int ret;
|
||||
|
||||
afi = AFI_L2VPN;
|
||||
safi = SAFI_EVPN;
|
||||
|
@ -1432,7 +1440,7 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
|
|||
if (is_route_matching_for_vni(bgp, vpn, ri)) {
|
||||
if (install)
|
||||
ret = install_evpn_route_entry(
|
||||
bgp, vpn, evp, ri);
|
||||
bgp, vpn, evp, ri);
|
||||
else
|
||||
ret = uninstall_evpn_route_entry(
|
||||
bgp, vpn, evp, ri);
|
||||
|
@ -2563,6 +2571,79 @@ int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
|||
return install_uninstall_evpn_route(bgp, afi, safi, p, ri, 0);
|
||||
}
|
||||
|
||||
/* filter routes which have martian next hops */
|
||||
int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct bgp_node *rd_rn, *rn;
|
||||
struct bgp_table *table;
|
||||
struct bgp_info *ri;
|
||||
|
||||
afi = AFI_L2VPN;
|
||||
safi = SAFI_EVPN;
|
||||
|
||||
/* 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. */
|
||||
for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn;
|
||||
rd_rn = bgp_route_next(rd_rn)) {
|
||||
table = (struct bgp_table *)(rd_rn->info);
|
||||
if (!table)
|
||||
continue;
|
||||
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
|
||||
for (ri = rn->info; ri; ri = ri->next) {
|
||||
|
||||
/* Consider "valid" remote routes applicable for
|
||||
* this VNI. */
|
||||
if (!(ri->type == ZEBRA_ROUTE_BGP
|
||||
&& ri->sub_type == BGP_ROUTE_NORMAL))
|
||||
continue;
|
||||
|
||||
if (bgp_nexthop_self(bgp,
|
||||
ri->attr->nexthop)) {
|
||||
|
||||
char attr_str[BUFSIZ];
|
||||
char pbuf[PREFIX_STRLEN];
|
||||
|
||||
bgp_dump_attr(ri->attr, attr_str,
|
||||
BUFSIZ);
|
||||
|
||||
if (bgp_debug_update(ri->peer, &rn->p,
|
||||
NULL, 1))
|
||||
zlog_debug(
|
||||
"%u: prefix %s with "
|
||||
"attr %s - DENIED"
|
||||
"due to martian or seld"
|
||||
"nexthop",
|
||||
bgp->vrf_id,
|
||||
prefix2str(
|
||||
&rn->p,
|
||||
pbuf,
|
||||
sizeof(pbuf)),
|
||||
attr_str);
|
||||
|
||||
bgp_evpn_unimport_route(bgp, afi, safi,
|
||||
&rn->p, ri);
|
||||
|
||||
bgp_rib_remove(rn, ri, ri->peer,
|
||||
afi, safi);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle del of a local MACIP.
|
||||
*/
|
||||
|
@ -2658,6 +2739,11 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
|
|||
*/
|
||||
delete_routes_for_vni(bgp, vpn);
|
||||
|
||||
/*
|
||||
* tunnel is no longer active, del tunnel ip address from tip_hash
|
||||
*/
|
||||
bgp_tip_del(bgp, &vpn->originator_ip);
|
||||
|
||||
/* Clear "live" flag and see if hash needs to be freed. */
|
||||
UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE);
|
||||
if (!is_vni_configured(vpn))
|
||||
|
@ -2703,15 +2789,22 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
|
|||
bgp->vrf_id, vni);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* if the VNI is live already, there is nothibng more to do */
|
||||
/* if the VNI is live already, there is nothing more to do */
|
||||
if (is_vni_live(vpn))
|
||||
return 0;
|
||||
|
||||
/* Mark as "live" */
|
||||
SET_FLAG(vpn->flags, VNI_FLAG_LIVE);
|
||||
|
||||
/* tunnel is now active, add tunnel-ip to db */
|
||||
bgp_tip_add(bgp, &originator_ip);
|
||||
|
||||
/* filter routes as nexthop database has changed */
|
||||
bgp_filter_evpn_routes_upon_martian_nh_change(bgp);
|
||||
|
||||
/* Create EVPN type-3 route and schedule for processing. */
|
||||
build_evpn_type3_prefix(&p, vpn->originator_ip);
|
||||
if (update_evpn_route(bgp, vpn, &p, 0)) {
|
||||
|
|
|
@ -38,6 +38,7 @@ extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
|||
struct prefix *p, struct bgp_info *ri);
|
||||
extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
struct prefix *p, struct bgp_info *ri);
|
||||
extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp);
|
||||
extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
|
||||
struct ethaddr *mac, struct ipaddr *ip);
|
||||
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
|
||||
|
|
|
@ -101,6 +101,7 @@ DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array")
|
|||
DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp")
|
||||
DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate")
|
||||
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address")
|
||||
DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address")
|
||||
|
||||
DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution")
|
||||
DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information")
|
||||
|
|
|
@ -97,6 +97,7 @@ DECLARE_MTYPE(BGP_DAMP_ARRAY)
|
|||
DECLARE_MTYPE(BGP_REGEXP)
|
||||
DECLARE_MTYPE(BGP_AGGREGATE)
|
||||
DECLARE_MTYPE(BGP_ADDR)
|
||||
DECLARE_MTYPE(TIP_ADDR)
|
||||
|
||||
DECLARE_MTYPE(BGP_REDIST)
|
||||
DECLARE_MTYPE(BGP_FILTER_NAME)
|
||||
|
|
|
@ -88,11 +88,86 @@ static void bgp_nexthop_cache_reset(struct bgp_table *table)
|
|||
}
|
||||
}
|
||||
|
||||
/* BGP own address structure */
|
||||
struct bgp_addr {
|
||||
struct in_addr addr;
|
||||
int refcnt;
|
||||
};
|
||||
static void *bgp_tip_hash_alloc(void *p)
|
||||
{
|
||||
const struct in_addr *val = (const struct in_addr *)p;
|
||||
struct tip_addr *addr;
|
||||
|
||||
addr = XMALLOC(MTYPE_TIP_ADDR, sizeof(struct tip_addr));
|
||||
addr->refcnt = 0;
|
||||
addr->addr.s_addr = val->s_addr;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void bgp_tip_hash_free(void *addr)
|
||||
{
|
||||
XFREE(MTYPE_TIP_ADDR, addr);
|
||||
}
|
||||
|
||||
static unsigned int bgp_tip_hash_key_make(void *p)
|
||||
{
|
||||
const struct tip_addr *addr = p;
|
||||
|
||||
return jhash_1word(addr->addr.s_addr, 0);
|
||||
}
|
||||
|
||||
static int bgp_tip_hash_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct tip_addr *addr1 = p1;
|
||||
const struct tip_addr *addr2 = p2;
|
||||
|
||||
return addr1->addr.s_addr == addr2->addr.s_addr;
|
||||
}
|
||||
|
||||
void bgp_tip_hash_init(struct bgp *bgp)
|
||||
{
|
||||
bgp->tip_hash = hash_create(bgp_tip_hash_key_make,
|
||||
bgp_tip_hash_cmp, NULL);
|
||||
}
|
||||
|
||||
void bgp_tip_hash_destroy(struct bgp *bgp)
|
||||
{
|
||||
if (bgp->tip_hash == NULL)
|
||||
return;
|
||||
hash_clean(bgp->tip_hash, bgp_tip_hash_free);
|
||||
hash_free(bgp->tip_hash);
|
||||
bgp->tip_hash = NULL;
|
||||
}
|
||||
|
||||
void bgp_tip_add(struct bgp *bgp, struct in_addr *tip)
|
||||
{
|
||||
struct tip_addr tmp;
|
||||
struct tip_addr *addr;
|
||||
|
||||
tmp.addr = *tip;
|
||||
|
||||
addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc);
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
addr->refcnt++;
|
||||
}
|
||||
|
||||
void bgp_tip_del(struct bgp *bgp, struct in_addr *tip)
|
||||
{
|
||||
struct tip_addr tmp;
|
||||
struct tip_addr *addr;
|
||||
|
||||
tmp.addr = *tip;
|
||||
|
||||
addr = hash_lookup(bgp->tip_hash, &tmp);
|
||||
/* may have been deleted earlier by bgp_interface_down() */
|
||||
if (addr == NULL)
|
||||
return;
|
||||
|
||||
addr->refcnt--;
|
||||
|
||||
if (addr->refcnt == 0) {
|
||||
hash_release(bgp->tip_hash, addr);
|
||||
XFREE(MTYPE_TIP_ADDR, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void *bgp_address_hash_alloc(void *p)
|
||||
{
|
||||
|
@ -304,6 +379,7 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
|
|||
int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr)
|
||||
{
|
||||
struct bgp_addr tmp, *addr;
|
||||
struct tip_addr tmp_tip, *tip;
|
||||
|
||||
tmp.addr = nh_addr;
|
||||
|
||||
|
@ -311,6 +387,11 @@ int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr)
|
|||
if (addr)
|
||||
return 1;
|
||||
|
||||
tmp_tip.addr = nh_addr;
|
||||
tip = hash_lookup(bgp->tip_hash, &tmp_tip);
|
||||
if (tip)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,18 @@ struct bgp_nexthop_cache {
|
|||
struct bgp *bgp;
|
||||
};
|
||||
|
||||
/* BGP own address structure */
|
||||
struct bgp_addr {
|
||||
struct in_addr addr;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
/* Own tunnel-ip address structure */
|
||||
struct tip_addr {
|
||||
struct in_addr addr;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
extern int bgp_nexthop_lookup(afi_t, struct peer *peer, struct bgp_info *,
|
||||
int *, int *);
|
||||
extern void bgp_connected_add(struct bgp *bgp, struct connected *c);
|
||||
|
@ -82,5 +94,9 @@ extern void bgp_scan_finish(struct bgp *bgp);
|
|||
extern void bgp_scan_vty_init(void);
|
||||
extern void bgp_address_init(struct bgp *bgp);
|
||||
extern void bgp_address_destroy(struct bgp *bgp);
|
||||
extern void bgp_tip_add(struct bgp *bgp, struct in_addr *tip);
|
||||
extern void bgp_tip_del(struct bgp *bgp, struct in_addr *tip);
|
||||
extern void bgp_tip_hash_init(struct bgp *bgp);
|
||||
extern void bgp_tip_hash_destroy(struct bgp *bgp);
|
||||
|
||||
#endif /* _QUAGGA_BGP_NEXTHOP_H */
|
||||
|
|
|
@ -2384,7 +2384,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
|
|||
/* Unconditionally remove the route from the RIB, without taking
|
||||
* damping into consideration (eg, because the session went down)
|
||||
*/
|
||||
static void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri,
|
||||
void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri,
|
||||
struct peer *peer, afi_t afi, safi_t safi)
|
||||
{
|
||||
bgp_aggregate_decrement(peer->bgp, &rn->p, ri, afi, safi);
|
||||
|
|
|
@ -293,6 +293,8 @@ static inline int bgp_fibupd_safi(safi_t safi)
|
|||
}
|
||||
|
||||
/* Prototypes. */
|
||||
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri,
|
||||
struct peer *peer, afi_t afi, safi_t safi);
|
||||
extern void bgp_process_queue_init(void);
|
||||
extern void bgp_route_init(void);
|
||||
extern void bgp_route_finish(void);
|
||||
|
|
|
@ -2107,10 +2107,10 @@ static void bgp_zebra_connected(struct zclient *zclient)
|
|||
static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
struct stream *s;
|
||||
vni_t vni;
|
||||
struct bgp *bgp;
|
||||
struct in_addr vtep_ip;
|
||||
struct stream *s;
|
||||
vni_t vni;
|
||||
struct bgp *bgp;
|
||||
struct in_addr vtep_ip;
|
||||
|
||||
s = zclient->ibuf;
|
||||
vni = stream_getl(s);
|
||||
|
|
|
@ -2934,6 +2934,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
|
|||
bgp = bgp_create(as, name, inst_type);
|
||||
bgp_router_id_set(bgp, &bgp->router_id_zebra);
|
||||
bgp_address_init(bgp);
|
||||
bgp_tip_hash_init(bgp);
|
||||
bgp_scan_init(bgp);
|
||||
*bgp_val = bgp;
|
||||
|
||||
|
@ -3158,6 +3159,7 @@ static void bgp_free(struct bgp *bgp)
|
|||
|
||||
bgp_scan_finish(bgp);
|
||||
bgp_address_destroy(bgp);
|
||||
bgp_tip_hash_destroy(bgp);
|
||||
|
||||
bgp_evpn_cleanup(bgp);
|
||||
|
||||
|
|
|
@ -318,6 +318,10 @@ struct bgp {
|
|||
|
||||
struct hash *address_hash;
|
||||
|
||||
/* DB for all local tunnel-ips - used mainly for martian checks
|
||||
Currently it only has all VxLan tunnel IPs*/
|
||||
struct hash *tip_hash;
|
||||
|
||||
/* Static route configuration. */
|
||||
struct bgp_table *route[AFI_MAX][SAFI_MAX];
|
||||
|
||||
|
|
Loading…
Reference in a new issue