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:
Mitesh Kanjariya 2017-08-16 23:19:58 -07:00
parent 0a97666de7
commit db0e1937ca
11 changed files with 219 additions and 18 deletions

View file

@ -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)) {

View file

@ -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,

View file

@ -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")

View file

@ -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)

View file

@ -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;
}

View file

@ -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 */

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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];