diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 109c98f81c..d9735e7ffa 100644 --- a/bgpd/bgp_evpn.c +++ b/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)) { diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index e9b7857212..ef63199395 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -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, diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 3df40fa87a..37054ce425 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -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") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 152cfaeaf2..35b83a0401 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -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) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 63a84684bb..b988fbf738 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -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; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 37dad577c2..b482778fdf 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -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 */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 35f793f861..fc22642833 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 1a1817bad3..93d79e5059 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -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); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2fc75ea5a2..ad73f96d55 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -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); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d7733fbacd..f48ba6af24 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bfdddc69b1..344b850fb4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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];