diff options
Diffstat (limited to 'bgpd/rfapi/rfapi_import.c')
| -rw-r--r-- | bgpd/rfapi/rfapi_import.c | 8714 |
1 files changed, 4182 insertions, 4532 deletions
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index dc8dc1ed2e..d0379e1ef8 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -1,22 +1,22 @@ - /* - * - * Copyright 2009-2016, LabN Consulting, L.L.C. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ +/* +* +* Copyright 2009-2016, LabN Consulting, L.L.C. +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; see the file COPYING; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ /* * File: rfapi_import.c @@ -38,7 +38,7 @@ #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" -#include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */ +#include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */ #include "bgpd/bgp_vnc_types.h" #include "bgpd/rfapi/rfapi.h" @@ -75,47 +75,44 @@ * Allocated for each withdraw timer instance; freed when the timer * expires or is canceled */ -struct rfapi_withdraw -{ - struct rfapi_import_table *import_table; - struct route_node *node; - struct bgp_info *info; - safi_t safi; /* used only for bulk operations */ - /* - * For import table node reference count checking (i.e., debugging). - * Normally when a timer expires, lockoffset should be 0. However, if - * the timer expiration function is called directly (e.g., - * rfapiExpireVpnNow), the node could be locked by a preceding - * route_top() or route_next() in a loop, so we need to pass this - * value in. - */ - int lockoffset; +struct rfapi_withdraw { + struct rfapi_import_table *import_table; + struct route_node *node; + struct bgp_info *info; + safi_t safi; /* used only for bulk operations */ + /* + * For import table node reference count checking (i.e., debugging). + * Normally when a timer expires, lockoffset should be 0. However, if + * the timer expiration function is called directly (e.g., + * rfapiExpireVpnNow), the node could be locked by a preceding + * route_top() or route_next() in a loop, so we need to pass this + * value in. + */ + int lockoffset; }; -/* +/* * DEBUG FUNCTION * It's evil and fiendish. It's compiler-dependent. * ? Might need LDFLAGS -rdynamic to produce all function names */ -void -rfapiDebugBacktrace (void) +void rfapiDebugBacktrace(void) { #ifdef HAVE_GLIBC_BACKTRACE #define RFAPI_DEBUG_BACKTRACE_NENTRIES 200 - void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES]; - char **syms; - size_t i; - size_t size; + void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES]; + char **syms; + size_t i; + size_t size; - size = backtrace (buf, RFAPI_DEBUG_BACKTRACE_NENTRIES); - syms = backtrace_symbols (buf, size); + size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES); + syms = backtrace_symbols(buf, size); - for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) - { - vnc_zlog_debug_verbose ("backtrace[%2zu]: %s", i, syms[i]); - } + for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) { + vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i, syms[i]); + } - free (syms); + free(syms); #else #endif } @@ -125,89 +122,80 @@ rfapiDebugBacktrace (void) * Count remote routes and compare with actively-maintained values. * Abort if they disagree. */ -void -rfapiCheckRouteCount () +void rfapiCheckRouteCount() { - struct bgp *bgp = bgp_get_default (); - struct rfapi *h; - struct rfapi_import_table *it; - afi_t afi; - - assert (bgp); - - h = bgp->rfapi; - assert (h); - - for (it = h->imports; it; it = it->next) - { - for (afi = AFI_IP; afi < AFI_MAX; ++afi) - { - - struct route_table *rt; - struct route_node *rn; - - int holddown_count = 0; - int local_count = 0; - int imported_count = 0; - int remote_count = 0; - - rt = it->imported_vpn[afi]; - - for (rn = route_top (rt); rn; rn = route_next (rn)) - { - struct bgp_info *bi; - struct bgp_info *next; - - for (bi = rn->info; bi; bi = next) - { - next = bi->next; - - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - { - ++holddown_count; - - } - else - { - if (RFAPI_LOCAL_BI (bi)) - { - ++local_count; - } - else - { - if (RFAPI_DIRECT_IMPORT_BI (bi)) - { - ++imported_count; - } - else - { - ++remote_count; - } - } - } - } - } - - if (it->holddown_count[afi] != holddown_count) - { - vnc_zlog_debug_verbose ("%s: it->holddown_count %d != holddown_count %d", - __func__, it->holddown_count[afi], holddown_count); - assert (0); - } - if (it->remote_count[afi] != remote_count) - { - vnc_zlog_debug_verbose ("%s: it->remote_count %d != remote_count %d", - __func__, it->remote_count[afi], remote_count); - assert (0); - } - if (it->imported_count[afi] != imported_count) - { - vnc_zlog_debug_verbose ("%s: it->imported_count %d != imported_count %d", - __func__, it->imported_count[afi], imported_count); - assert (0); - } - } - } + struct bgp *bgp = bgp_get_default(); + struct rfapi *h; + struct rfapi_import_table *it; + afi_t afi; + + assert(bgp); + + h = bgp->rfapi; + assert(h); + + for (it = h->imports; it; it = it->next) { + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + struct route_table *rt; + struct route_node *rn; + + int holddown_count = 0; + int local_count = 0; + int imported_count = 0; + int remote_count = 0; + + rt = it->imported_vpn[afi]; + + for (rn = route_top(rt); rn; rn = route_next(rn)) { + struct bgp_info *bi; + struct bgp_info *next; + + for (bi = rn->info; bi; bi = next) { + next = bi->next; + + if (CHECK_FLAG(bi->flags, + BGP_INFO_REMOVED)) { + ++holddown_count; + + } else { + if (RFAPI_LOCAL_BI(bi)) { + ++local_count; + } else { + if (RFAPI_DIRECT_IMPORT_BI( + bi)) { + ++imported_count; + } else { + ++remote_count; + } + } + } + } + } + + if (it->holddown_count[afi] != holddown_count) { + vnc_zlog_debug_verbose( + "%s: it->holddown_count %d != holddown_count %d", + __func__, it->holddown_count[afi], + holddown_count); + assert(0); + } + if (it->remote_count[afi] != remote_count) { + vnc_zlog_debug_verbose( + "%s: it->remote_count %d != remote_count %d", + __func__, it->remote_count[afi], + remote_count); + assert(0); + } + if (it->imported_count[afi] != imported_count) { + vnc_zlog_debug_verbose( + "%s: it->imported_count %d != imported_count %d", + __func__, it->imported_count[afi], + imported_count); + assert(0); + } + } + } } #if DEBUG_ROUTE_COUNTERS @@ -224,825 +212,777 @@ rfapiCheckRouteCount () * node->lock == 1, and we have to validate the refcount before * the node is deleted. In this case, we specify lockoffset 1. */ -void -rfapiCheckRefcount (struct route_node *rn, safi_t safi, int lockoffset) +void rfapiCheckRefcount(struct route_node *rn, safi_t safi, int lockoffset) { - unsigned int count_bi = 0; - unsigned int count_monitor = 0; - struct bgp_info *bi; - struct rfapi_monitor_encap *hme; - struct rfapi_monitor_vpn *hmv; - - for (bi = rn->info; bi; bi = bi->next) - ++count_bi; - - - if (rn->aggregate) - { - ++count_monitor; /* rfapi_it_extra */ - - switch (safi) - { - void *cursor; - int rc; - - case SAFI_ENCAP: - for (hme = RFAPI_MONITOR_ENCAP (rn); hme; hme = hme->next) - ++count_monitor; - break; - - case SAFI_MPLS_VPN: - - for (hmv = RFAPI_MONITOR_VPN (rn); hmv; hmv = hmv->next) - ++count_monitor; - - if (RFAPI_MONITOR_EXTERIOR (rn)->source) - { - ++count_monitor; /* sl */ - cursor = NULL; - for (rc = skiplist_next (RFAPI_MONITOR_EXTERIOR (rn)->source, - NULL, NULL, &cursor); - !rc; - rc = skiplist_next (RFAPI_MONITOR_EXTERIOR (rn)->source, - NULL, NULL, &cursor)) - { - - ++count_monitor; /* sl entry */ - } - } - break; - - default: - assert (0); - } - } - - if (count_bi + count_monitor + lockoffset != rn->lock) - { - vnc_zlog_debug_verbose - ("%s: count_bi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d", - __func__, count_bi, count_monitor, lockoffset, rn->lock); - assert (0); - } + unsigned int count_bi = 0; + unsigned int count_monitor = 0; + struct bgp_info *bi; + struct rfapi_monitor_encap *hme; + struct rfapi_monitor_vpn *hmv; + + for (bi = rn->info; bi; bi = bi->next) + ++count_bi; + + + if (rn->aggregate) { + ++count_monitor; /* rfapi_it_extra */ + + switch (safi) { + void *cursor; + int rc; + + case SAFI_ENCAP: + for (hme = RFAPI_MONITOR_ENCAP(rn); hme; + hme = hme->next) + ++count_monitor; + break; + + case SAFI_MPLS_VPN: + + for (hmv = RFAPI_MONITOR_VPN(rn); hmv; hmv = hmv->next) + ++count_monitor; + + if (RFAPI_MONITOR_EXTERIOR(rn)->source) { + ++count_monitor; /* sl */ + cursor = NULL; + for (rc = skiplist_next( + RFAPI_MONITOR_EXTERIOR(rn)->source, + NULL, NULL, &cursor); + !rc; + rc = skiplist_next( + RFAPI_MONITOR_EXTERIOR(rn)->source, + NULL, NULL, &cursor)) { + + ++count_monitor; /* sl entry */ + } + } + break; + + default: + assert(0); + } + } + + if (count_bi + count_monitor + lockoffset != rn->lock) { + vnc_zlog_debug_verbose( + "%s: count_bi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d", + __func__, count_bi, count_monitor, lockoffset, + rn->lock); + assert(0); + } } /* * Perform deferred rfapi_close operations that were queued * during callbacks. */ -static wq_item_status -rfapi_deferred_close_workfunc (struct work_queue *q, void *data) +static wq_item_status rfapi_deferred_close_workfunc(struct work_queue *q, + void *data) { - struct rfapi_descriptor *rfd = data; - struct rfapi *h = q->spec.data; - - assert (!(h->flags & RFAPI_INCALLBACK)); - rfapi_close (rfd); - vnc_zlog_debug_verbose ("%s: completed deferred close on handle %p", __func__, rfd); - return WQ_SUCCESS; + struct rfapi_descriptor *rfd = data; + struct rfapi *h = q->spec.data; + + assert(!(h->flags & RFAPI_INCALLBACK)); + rfapi_close(rfd); + vnc_zlog_debug_verbose("%s: completed deferred close on handle %p", + __func__, rfd); + return WQ_SUCCESS; } /* * Extract layer 2 option from Encap TLVS in BGP attrs */ -int -rfapiGetL2o (struct attr *attr, struct rfapi_l2address_option *l2o) +int rfapiGetL2o(struct attr *attr, struct rfapi_l2address_option *l2o) { - if (attr) - { - - struct bgp_attr_encap_subtlv *pEncap; - - for (pEncap = attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) - { - - if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) - { - if (pEncap->value[0] == RFAPI_VN_OPTION_TYPE_L2ADDR) - { - - if (pEncap->value[1] == 14) - { - memcpy (l2o->macaddr.octet, pEncap->value + 2, - ETHER_ADDR_LEN); - l2o->label = - ((pEncap->value[10] >> 4) & 0x0f) + - ((pEncap->value[9] << 4) & 0xff0) + - ((pEncap->value[8] << 12) & 0xff000); - - l2o->local_nve_id = pEncap->value[12]; - - l2o->logical_net_id = - (pEncap->value[15] & 0xff) + - ((pEncap->value[14] << 8) & 0xff00) + - ((pEncap->value[13] << 16) & 0xff0000); - } - - return 0; - } - } - } - } - - return ENOENT; + if (attr) { + + struct bgp_attr_encap_subtlv *pEncap; + + for (pEncap = attr->vnc_subtlvs; pEncap; + pEncap = pEncap->next) { + + if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) { + if (pEncap->value[0] + == RFAPI_VN_OPTION_TYPE_L2ADDR) { + + if (pEncap->value[1] == 14) { + memcpy(l2o->macaddr.octet, + pEncap->value + 2, + ETHER_ADDR_LEN); + l2o->label = + ((pEncap->value[10] + >> 4) + & 0x0f) + + ((pEncap->value[9] + << 4) + & 0xff0) + + ((pEncap->value[8] + << 12) + & 0xff000); + + l2o->local_nve_id = + pEncap->value[12]; + + l2o->logical_net_id = + (pEncap->value[15] + & 0xff) + + ((pEncap->value[14] + << 8) + & 0xff00) + + ((pEncap->value[13] + << 16) + & 0xff0000); + } + + return 0; + } + } + } + } + + return ENOENT; } /* * Extract the lifetime from the Tunnel Encap attribute of a route in * an import table */ -int -rfapiGetVncLifetime (struct attr *attr, uint32_t * lifetime) +int rfapiGetVncLifetime(struct attr *attr, uint32_t *lifetime) { - struct bgp_attr_encap_subtlv *pEncap; + struct bgp_attr_encap_subtlv *pEncap; - *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */ + *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */ - if (attr) - { + if (attr) { - for (pEncap = attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) - { + for (pEncap = attr->vnc_subtlvs; pEncap; + pEncap = pEncap->next) { - if (pEncap->type == BGP_VNC_SUBTLV_TYPE_LIFETIME) - { /* lifetime */ - if (pEncap->length == 4) - { - memcpy (lifetime, pEncap->value, 4); - *lifetime = ntohl (*lifetime); - return 0; - } - } - } - } + if (pEncap->type + == BGP_VNC_SUBTLV_TYPE_LIFETIME) { /* lifetime */ + if (pEncap->length == 4) { + memcpy(lifetime, pEncap->value, 4); + *lifetime = ntohl(*lifetime); + return 0; + } + } + } + } - return ENOENT; + return ENOENT; } /* * Extract the tunnel type from the extended community */ -int -rfapiGetTunnelType (struct attr *attr, - bgp_encap_types *type) +int rfapiGetTunnelType(struct attr *attr, bgp_encap_types *type) { - *type = BGP_ENCAP_TYPE_MPLS; /* default to MPLS */ - if (attr && attr->ecommunity) - { - struct ecommunity *ecom = attr->ecommunity; - int i; - - for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) - { - uint8_t *ep; - - ep = ecom->val + i; - if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE && - ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) - { - *type = (ep[6]<<8) + ep[7]; - return 0; - } - } - } - - return ENOENT; + *type = BGP_ENCAP_TYPE_MPLS; /* default to MPLS */ + if (attr && attr->ecommunity) { + struct ecommunity *ecom = attr->ecommunity; + int i; + + for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); + i += ECOMMUNITY_SIZE) { + uint8_t *ep; + + ep = ecom->val + i; + if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE + && ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) { + *type = (ep[6] << 8) + ep[7]; + return 0; + } + } + } + + return ENOENT; } /* * Look for UN address in Encap attribute */ -int -rfapiGetVncTunnelUnAddr (struct attr *attr, struct prefix *p) +int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p) { - struct bgp_attr_encap_subtlv *pEncap; - bgp_encap_types tun_type; - - rfapiGetTunnelType (attr, &tun_type); - if (tun_type == BGP_ENCAP_TYPE_MPLS) - { - if (!p) - return 0; - /* MPLS carries UN address in next hop */ - rfapiNexthop2Prefix (attr, p); - if (p->family != 0) - return 0; - - return ENOENT; - } - if (attr) - { - for (pEncap = attr->encap_subtlvs; pEncap; pEncap = pEncap->next) - { - - if (pEncap->type == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT) - { /* un addr */ - switch (pEncap->length) - { - case 8: - if (p) - { - p->family = AF_INET; - p->prefixlen = 32; - memcpy (p->u.val, pEncap->value, 4); - } - return 0; - - case 20: - if (p) - { - p->family = AF_INET6; - p->prefixlen = 128; - memcpy (p->u.val, pEncap->value, 16); - } - return 0; - } - } - } - } - - return ENOENT; + struct bgp_attr_encap_subtlv *pEncap; + bgp_encap_types tun_type; + + rfapiGetTunnelType(attr, &tun_type); + if (tun_type == BGP_ENCAP_TYPE_MPLS) { + if (!p) + return 0; + /* MPLS carries UN address in next hop */ + rfapiNexthop2Prefix(attr, p); + if (p->family != 0) + return 0; + + return ENOENT; + } + if (attr) { + for (pEncap = attr->encap_subtlvs; pEncap; + pEncap = pEncap->next) { + + if (pEncap->type + == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT) { /* un + addr + */ + switch (pEncap->length) { + case 8: + if (p) { + p->family = AF_INET; + p->prefixlen = 32; + memcpy(p->u.val, pEncap->value, + 4); + } + return 0; + + case 20: + if (p) { + p->family = AF_INET6; + p->prefixlen = 128; + memcpy(p->u.val, pEncap->value, + 16); + } + return 0; + } + } + } + } + + return ENOENT; } /* * Get UN address wherever it might be */ -int -rfapiGetUnAddrOfVpnBi (struct bgp_info *bi, struct prefix *p) +int rfapiGetUnAddrOfVpnBi(struct bgp_info *bi, struct prefix *p) { - /* If it's in this route's VNC attribute, we're done */ - if (!rfapiGetVncTunnelUnAddr (bi->attr, p)) - return 0; - /* - * Otherwise, see if it's cached from a corresponding ENCAP SAFI - * advertisement - */ - if (bi->extra) - { - switch (bi->extra->vnc.import.un_family) - { - case AF_INET: - if (p) - { - p->family = bi->extra->vnc.import.un_family; - p->u.prefix4 = bi->extra->vnc.import.un.addr4; - p->prefixlen = 32; - } - return 0; - case AF_INET6: - if (p) - { - p->family = bi->extra->vnc.import.un_family; - p->u.prefix6 = bi->extra->vnc.import.un.addr6; - p->prefixlen = 128; - } - return 0; - default: - if (p) - p->family = 0; + /* If it's in this route's VNC attribute, we're done */ + if (!rfapiGetVncTunnelUnAddr(bi->attr, p)) + return 0; + /* + * Otherwise, see if it's cached from a corresponding ENCAP SAFI + * advertisement + */ + if (bi->extra) { + switch (bi->extra->vnc.import.un_family) { + case AF_INET: + if (p) { + p->family = bi->extra->vnc.import.un_family; + p->u.prefix4 = bi->extra->vnc.import.un.addr4; + p->prefixlen = 32; + } + return 0; + case AF_INET6: + if (p) { + p->family = bi->extra->vnc.import.un_family; + p->u.prefix6 = bi->extra->vnc.import.un.addr6; + p->prefixlen = 128; + } + return 0; + default: + if (p) + p->family = 0; #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: bi->extra->vnc.import.un_family is 0, no UN addr", - __func__); + vnc_zlog_debug_verbose( + "%s: bi->extra->vnc.import.un_family is 0, no UN addr", + __func__); #endif - break; - } - } + break; + } + } - return ENOENT; + return ENOENT; } /* * Make a new bgp_info from gathered parameters */ -static struct bgp_info * -rfapiBgpInfoCreate ( - struct attr *attr, - struct peer *peer, - void *rfd, - struct prefix_rd *prd, - u_char type, - u_char sub_type, - uint32_t *label) +static struct bgp_info *rfapiBgpInfoCreate(struct attr *attr, struct peer *peer, + void *rfd, struct prefix_rd *prd, + u_char type, u_char sub_type, + uint32_t *label) { - struct bgp_info *new; - - new = bgp_info_new (); - assert (new); - - if (attr) - { - if (!new->attr) - new->attr = bgp_attr_intern (attr); - } - bgp_info_extra_get (new); - if (prd) - { - new->extra->vnc.import.rd = *prd; - rfapi_time (&new->extra->vnc.import.create_time); - } - if (label) - encode_label (*label, &new->extra->label); - new->type = type; - new->sub_type = sub_type; - new->peer = peer; - peer_lock (peer); - - return new; + struct bgp_info *new; + + new = bgp_info_new(); + assert(new); + + if (attr) { + if (!new->attr) + new->attr = bgp_attr_intern(attr); + } + bgp_info_extra_get(new); + if (prd) { + new->extra->vnc.import.rd = *prd; + rfapi_time(&new->extra->vnc.import.create_time); + } + if (label) + encode_label(*label, &new->extra->label); + new->type = type; + new->sub_type = sub_type; + new->peer = peer; + peer_lock(peer); + + return new; } /* * Frees bgp_info as used in import tables (parts are not * allocated exactly the way they are in the main RIBs) */ -static void -rfapiBgpInfoFree (struct bgp_info *goner) +static void rfapiBgpInfoFree(struct bgp_info *goner) { - if (!goner) - return; - - if (goner->peer) - { - vnc_zlog_debug_verbose ("%s: calling peer_unlock(%p), #%d", - __func__, goner->peer, goner->peer->lock); - peer_unlock (goner->peer); - } - - if (goner->attr) - { - bgp_attr_unintern (&goner->attr); - } - if (goner->extra) - { - assert (!goner->extra->damp_info); /* Not used in import tbls */ - XFREE (MTYPE_BGP_ROUTE_EXTRA, goner->extra); - goner->extra = NULL; - } - XFREE (MTYPE_BGP_ROUTE, goner); + if (!goner) + return; + + if (goner->peer) { + vnc_zlog_debug_verbose("%s: calling peer_unlock(%p), #%d", + __func__, goner->peer, + goner->peer->lock); + peer_unlock(goner->peer); + } + + if (goner->attr) { + bgp_attr_unintern(&goner->attr); + } + if (goner->extra) { + assert(!goner->extra->damp_info); /* Not used in import tbls */ + XFREE(MTYPE_BGP_ROUTE_EXTRA, goner->extra); + goner->extra = NULL; + } + XFREE(MTYPE_BGP_ROUTE, goner); } -struct rfapi_import_table * -rfapiMacImportTableGetNoAlloc (struct bgp *bgp, uint32_t lni) +struct rfapi_import_table *rfapiMacImportTableGetNoAlloc(struct bgp *bgp, + uint32_t lni) { - struct rfapi *h; - struct rfapi_import_table *it = NULL; - uintptr_t lni_as_ptr = lni; + struct rfapi *h; + struct rfapi_import_table *it = NULL; + uintptr_t lni_as_ptr = lni; - h = bgp->rfapi; - if (!h) - return NULL; + h = bgp->rfapi; + if (!h) + return NULL; - if (!h->import_mac) - return NULL; + if (!h->import_mac) + return NULL; - if (skiplist_search (h->import_mac, (void *) lni_as_ptr, (void **) &it)) - return NULL; + if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it)) + return NULL; - return it; + return it; } -struct rfapi_import_table * -rfapiMacImportTableGet (struct bgp *bgp, uint32_t lni) +struct rfapi_import_table *rfapiMacImportTableGet(struct bgp *bgp, uint32_t lni) { - struct rfapi *h; - struct rfapi_import_table *it = NULL; - uintptr_t lni_as_ptr = lni; - - h = bgp->rfapi; - assert (h); - - if (!h->import_mac) - { - /* default cmp is good enough for LNI */ - h->import_mac = skiplist_new (0, NULL, NULL); - } - - if (skiplist_search (h->import_mac, (void *) lni_as_ptr, (void **) &it)) - { - - struct ecommunity *enew; - struct ecommunity_val eval; - afi_t afi; - - it = - XCALLOC (MTYPE_RFAPI_IMPORTTABLE, sizeof (struct rfapi_import_table)); - /* set RT list of new import table based on LNI */ - memset ((char *) &eval, 0, sizeof (eval)); - eval.val[0] = 0; /* VNC L2VPN */ - eval.val[1] = 2; /* VNC L2VPN */ - eval.val[5] = (lni >> 16) & 0xff; - eval.val[6] = (lni >> 8) & 0xff; - eval.val[7] = (lni >> 0) & 0xff; - - enew = ecommunity_new (); - ecommunity_add_val (enew, &eval); - it->rt_import_list = enew; - - for (afi = AFI_IP; afi < AFI_MAX; ++afi) - { - it->imported_vpn[afi] = route_table_init (); - it->imported_encap[afi] = route_table_init (); - } - - it->l2_logical_net_id = lni; - - skiplist_insert (h->import_mac, (void *) lni_as_ptr, it); - } - - assert (it); - return it; + struct rfapi *h; + struct rfapi_import_table *it = NULL; + uintptr_t lni_as_ptr = lni; + + h = bgp->rfapi; + assert(h); + + if (!h->import_mac) { + /* default cmp is good enough for LNI */ + h->import_mac = skiplist_new(0, NULL, NULL); + } + + if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it)) { + + struct ecommunity *enew; + struct ecommunity_val eval; + afi_t afi; + + it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE, + sizeof(struct rfapi_import_table)); + /* set RT list of new import table based on LNI */ + memset((char *)&eval, 0, sizeof(eval)); + eval.val[0] = 0; /* VNC L2VPN */ + eval.val[1] = 2; /* VNC L2VPN */ + eval.val[5] = (lni >> 16) & 0xff; + eval.val[6] = (lni >> 8) & 0xff; + eval.val[7] = (lni >> 0) & 0xff; + + enew = ecommunity_new(); + ecommunity_add_val(enew, &eval); + it->rt_import_list = enew; + + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + it->imported_vpn[afi] = route_table_init(); + it->imported_encap[afi] = route_table_init(); + } + + it->l2_logical_net_id = lni; + + skiplist_insert(h->import_mac, (void *)lni_as_ptr, it); + } + + assert(it); + return it; } /* * Implement MONITOR_MOVE_SHORTER(original_node) from * RFAPI-Import-Event-Handling.txt - * + * * Returns pointer to the list of moved monitors */ static struct rfapi_monitor_vpn * -rfapiMonitorMoveShorter (struct route_node *original_vpn_node, int lockoffset) +rfapiMonitorMoveShorter(struct route_node *original_vpn_node, int lockoffset) { - struct bgp_info *bi; - struct route_node *par; - struct rfapi_monitor_vpn *m; - struct rfapi_monitor_vpn *mlast; - struct rfapi_monitor_vpn *moved; - int movecount = 0; - int parent_already_refcounted = 0; + struct bgp_info *bi; + struct route_node *par; + struct rfapi_monitor_vpn *m; + struct rfapi_monitor_vpn *mlast; + struct rfapi_monitor_vpn *moved; + int movecount = 0; + int parent_already_refcounted = 0; - RFAPI_CHECK_REFCOUNT (original_vpn_node, SAFI_MPLS_VPN, lockoffset); + RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN, lockoffset); #if DEBUG_MONITOR_MOVE_SHORTER - { - char buf[BUFSIZ]; + { + char buf[BUFSIZ]; - prefix2str (&original_vpn_node->p, buf, BUFSIZ); - buf[BUFSIZ - 1] = 0; - vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__, buf); - } + prefix2str(&original_vpn_node->p, buf, BUFSIZ); + buf[BUFSIZ - 1] = 0; + vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__, + buf); + } #endif - /* - * 1. If there is at least one bi (either regular route or - * route marked as withdrawn, with a pending timer) at - * original_node with a valid UN address, we're done. Return. - */ - for (bi = original_vpn_node->info; bi; bi = bi->next) - { - struct prefix pfx; - - if (!rfapiGetUnAddrOfVpnBi (bi, &pfx)) - { + /* + * 1. If there is at least one bi (either regular route or + * route marked as withdrawn, with a pending timer) at + * original_node with a valid UN address, we're done. Return. + */ + for (bi = original_vpn_node->info; bi; bi = bi->next) { + struct prefix pfx; + + if (!rfapiGetUnAddrOfVpnBi(bi, &pfx)) { #if DEBUG_MONITOR_MOVE_SHORTER - vnc_zlog_debug_verbose ("%s: have valid UN at original node, no change", - __func__); + vnc_zlog_debug_verbose( + "%s: have valid UN at original node, no change", + __func__); #endif - return NULL; - } - } - - /* - * 2. Travel up the tree (toward less-specific prefixes) from - * original_node to find the first node that has at least - * one route (even if it is only a withdrawn route) with a - * valid UN address. Call this node "Node P." - */ - for (par = original_vpn_node->parent; par; par = par->parent) - { - for (bi = par->info; bi; bi = bi->next) - { - struct prefix pfx; - if (!rfapiGetUnAddrOfVpnBi (bi, &pfx)) - { - break; - } - } - if (bi) - break; - } - - if (par) - { - RFAPI_CHECK_REFCOUNT (par, SAFI_MPLS_VPN, 0); - } - - /* - * If no less-specific routes, try to use the 0/0 node - */ - if (!par) - { - /* this isn't necessarily 0/0 */ - par = route_top (original_vpn_node->table); - - /* - * If we got the top node but it wasn't 0/0, - * ignore it - */ - if (par && par->p.prefixlen) - { - route_unlock_node (par); /* maybe free */ - par = NULL; - } - - if (par) - { - ++parent_already_refcounted; - } - } - - /* - * Create 0/0 node if it isn't there - */ - if (!par) - { - struct prefix pfx_default; - - memset (&pfx_default, 0, sizeof (pfx_default)); - pfx_default.family = original_vpn_node->p.family; - - /* creates default node if none exists */ - par = route_node_get (original_vpn_node->table, &pfx_default); - ++parent_already_refcounted; - } - - /* - * 3. Move each of the monitors found at original_node to Node P. - * These are "Moved Monitors." - * - */ - - /* - * Attach at end so that the list pointer we return points - * only to the moved routes - */ - for (m = RFAPI_MONITOR_VPN (par), mlast = NULL; m; mlast = m, m = m->next); - - if (mlast) - { - moved = mlast->next = RFAPI_MONITOR_VPN (original_vpn_node); - } - else - { - moved = RFAPI_MONITOR_VPN_W_ALLOC (par) = - RFAPI_MONITOR_VPN (original_vpn_node); - } - if (RFAPI_MONITOR_VPN (original_vpn_node)) /* check agg, so not allocated */ - RFAPI_MONITOR_VPN_W_ALLOC (original_vpn_node) = NULL; - - /* - * update the node pointers on the monitors - */ - for (m = moved; m; m = m->next) - { - ++movecount; - m->node = par; - } - - RFAPI_CHECK_REFCOUNT (par, SAFI_MPLS_VPN, - parent_already_refcounted - movecount); - while (movecount > parent_already_refcounted) - { - route_lock_node (par); - ++parent_already_refcounted; - } - while (movecount < parent_already_refcounted) - { - /* unlikely, but code defensively */ - route_unlock_node (par); - --parent_already_refcounted; - } - RFAPI_CHECK_REFCOUNT (original_vpn_node, SAFI_MPLS_VPN, - movecount + lockoffset); - while (movecount--) - { - route_unlock_node (original_vpn_node); - } + return NULL; + } + } + + /* + * 2. Travel up the tree (toward less-specific prefixes) from + * original_node to find the first node that has at least + * one route (even if it is only a withdrawn route) with a + * valid UN address. Call this node "Node P." + */ + for (par = original_vpn_node->parent; par; par = par->parent) { + for (bi = par->info; bi; bi = bi->next) { + struct prefix pfx; + if (!rfapiGetUnAddrOfVpnBi(bi, &pfx)) { + break; + } + } + if (bi) + break; + } + + if (par) { + RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 0); + } + + /* + * If no less-specific routes, try to use the 0/0 node + */ + if (!par) { + /* this isn't necessarily 0/0 */ + par = route_top(original_vpn_node->table); + + /* + * If we got the top node but it wasn't 0/0, + * ignore it + */ + if (par && par->p.prefixlen) { + route_unlock_node(par); /* maybe free */ + par = NULL; + } + + if (par) { + ++parent_already_refcounted; + } + } + + /* + * Create 0/0 node if it isn't there + */ + if (!par) { + struct prefix pfx_default; + + memset(&pfx_default, 0, sizeof(pfx_default)); + pfx_default.family = original_vpn_node->p.family; + + /* creates default node if none exists */ + par = route_node_get(original_vpn_node->table, &pfx_default); + ++parent_already_refcounted; + } + + /* + * 3. Move each of the monitors found at original_node to Node P. + * These are "Moved Monitors." + * + */ + + /* + * Attach at end so that the list pointer we return points + * only to the moved routes + */ + for (m = RFAPI_MONITOR_VPN(par), mlast = NULL; m; + mlast = m, m = m->next) + ; + + if (mlast) { + moved = mlast->next = RFAPI_MONITOR_VPN(original_vpn_node); + } else { + moved = RFAPI_MONITOR_VPN_W_ALLOC(par) = + RFAPI_MONITOR_VPN(original_vpn_node); + } + if (RFAPI_MONITOR_VPN( + original_vpn_node)) /* check agg, so not allocated */ + RFAPI_MONITOR_VPN_W_ALLOC(original_vpn_node) = NULL; + + /* + * update the node pointers on the monitors + */ + for (m = moved; m; m = m->next) { + ++movecount; + m->node = par; + } + + RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, + parent_already_refcounted - movecount); + while (movecount > parent_already_refcounted) { + route_lock_node(par); + ++parent_already_refcounted; + } + while (movecount < parent_already_refcounted) { + /* unlikely, but code defensively */ + route_unlock_node(par); + --parent_already_refcounted; + } + RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN, + movecount + lockoffset); + while (movecount--) { + route_unlock_node(original_vpn_node); + } #if DEBUG_MONITOR_MOVE_SHORTER - { - char buf[BUFSIZ]; + { + char buf[BUFSIZ]; - prefix2str (&par->p, buf, BUFSIZ); - buf[BUFSIZ - 1] = 0; - vnc_zlog_debug_verbose ("%s: moved to node pfx=%s", __func__, buf); - } + prefix2str(&par->p, buf, BUFSIZ); + buf[BUFSIZ - 1] = 0; + vnc_zlog_debug_verbose("%s: moved to node pfx=%s", __func__, + buf); + } #endif - return moved; + return moved; } /* * Implement MONITOR_MOVE_LONGER(new_node) from * RFAPI-Import-Event-Handling.txt */ -static void -rfapiMonitorMoveLonger (struct route_node *new_vpn_node) +static void rfapiMonitorMoveLonger(struct route_node *new_vpn_node) { - struct rfapi_monitor_vpn *monitor; - struct rfapi_monitor_vpn *mlast; - struct bgp_info *bi; - struct route_node *par; - - RFAPI_CHECK_REFCOUNT (new_vpn_node, SAFI_MPLS_VPN, 0); - - /* - * Make sure we have at least one valid route at the new node - */ - for (bi = new_vpn_node->info; bi; bi = bi->next) - { - struct prefix pfx; - if (!rfapiGetUnAddrOfVpnBi (bi, &pfx)) - break; - } - - if (!bi) - { - vnc_zlog_debug_verbose ("%s: no valid routes at node %p, so not attempting moves", - __func__, new_vpn_node); - return; - } - - /* - * Find first parent node that has monitors - */ - for (par = new_vpn_node->parent; par; par = par->parent) - { - if (RFAPI_MONITOR_VPN (par)) - break; - } - - if (!par) - { - vnc_zlog_debug_verbose ("%s: no parent nodes with monitors, done", __func__); - return; - } - - /* - * Check each of these monitors to see of their longest-match - * is now the updated node. Move any such monitors to the more- - * specific updated node - */ - for (mlast = NULL, monitor = RFAPI_MONITOR_VPN (par); monitor;) - { - - /* - * If new longest match for monitor prefix is the new - * route's prefix, move monitor to new route's prefix - */ - if (prefix_match (&new_vpn_node->p, &monitor->p)) - { - /* detach */ - if (mlast) - { - mlast->next = monitor->next; - } - else - { - RFAPI_MONITOR_VPN_W_ALLOC (par) = monitor->next; - } - - - /* attach */ - monitor->next = RFAPI_MONITOR_VPN (new_vpn_node); - RFAPI_MONITOR_VPN_W_ALLOC (new_vpn_node) = monitor; - monitor->node = new_vpn_node; - - route_lock_node (new_vpn_node); /* incr refcount */ - - monitor = mlast ? mlast->next : RFAPI_MONITOR_VPN (par); - - RFAPI_CHECK_REFCOUNT (par, SAFI_MPLS_VPN, 1); - /* decr refcount after we're done with par as this might free it */ - route_unlock_node (par); - - continue; - } - mlast = monitor; - monitor = monitor->next; - } - - RFAPI_CHECK_REFCOUNT (new_vpn_node, SAFI_MPLS_VPN, 0); + struct rfapi_monitor_vpn *monitor; + struct rfapi_monitor_vpn *mlast; + struct bgp_info *bi; + struct route_node *par; + + RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0); + + /* + * Make sure we have at least one valid route at the new node + */ + for (bi = new_vpn_node->info; bi; bi = bi->next) { + struct prefix pfx; + if (!rfapiGetUnAddrOfVpnBi(bi, &pfx)) + break; + } + + if (!bi) { + vnc_zlog_debug_verbose( + "%s: no valid routes at node %p, so not attempting moves", + __func__, new_vpn_node); + return; + } + + /* + * Find first parent node that has monitors + */ + for (par = new_vpn_node->parent; par; par = par->parent) { + if (RFAPI_MONITOR_VPN(par)) + break; + } + + if (!par) { + vnc_zlog_debug_verbose( + "%s: no parent nodes with monitors, done", __func__); + return; + } + + /* + * Check each of these monitors to see of their longest-match + * is now the updated node. Move any such monitors to the more- + * specific updated node + */ + for (mlast = NULL, monitor = RFAPI_MONITOR_VPN(par); monitor;) { + + /* + * If new longest match for monitor prefix is the new + * route's prefix, move monitor to new route's prefix + */ + if (prefix_match(&new_vpn_node->p, &monitor->p)) { + /* detach */ + if (mlast) { + mlast->next = monitor->next; + } else { + RFAPI_MONITOR_VPN_W_ALLOC(par) = monitor->next; + } + + + /* attach */ + monitor->next = RFAPI_MONITOR_VPN(new_vpn_node); + RFAPI_MONITOR_VPN_W_ALLOC(new_vpn_node) = monitor; + monitor->node = new_vpn_node; + + route_lock_node(new_vpn_node); /* incr refcount */ + + monitor = mlast ? mlast->next : RFAPI_MONITOR_VPN(par); + + RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 1); + /* decr refcount after we're done with par as this might + * free it */ + route_unlock_node(par); + + continue; + } + mlast = monitor; + monitor = monitor->next; + } + + RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0); } -static void -rfapiBgpInfoChainFree (struct bgp_info *bi) +static void rfapiBgpInfoChainFree(struct bgp_info *bi) { - struct bgp_info *next; - - while (bi) - { - - /* - * If there is a timer waiting to delete this bi, cancel - * the timer and delete immediately - */ - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) && - bi->extra->vnc.import.timer) - { - - struct thread *t = (struct thread *) bi->extra->vnc.import.timer; - struct rfapi_withdraw *wcb = t->arg; - - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - thread_cancel (t); - } - - next = bi->next; - bi->next = NULL; - rfapiBgpInfoFree (bi); - bi = next; - } + struct bgp_info *next; + + while (bi) { + + /* + * If there is a timer waiting to delete this bi, cancel + * the timer and delete immediately + */ + if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED) + && bi->extra->vnc.import.timer) { + + struct thread *t = + (struct thread *)bi->extra->vnc.import.timer; + struct rfapi_withdraw *wcb = t->arg; + + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + thread_cancel(t); + } + + next = bi->next; + bi->next = NULL; + rfapiBgpInfoFree(bi); + bi = next; + } } -static void -rfapiImportTableFlush (struct rfapi_import_table *it) +static void rfapiImportTableFlush(struct rfapi_import_table *it) { - afi_t afi; - - /* - * Free ecommunity - */ - ecommunity_free (&it->rt_import_list); - it->rt_import_list = NULL; - - for (afi = AFI_IP; afi < AFI_MAX; ++afi) - { - - struct route_node *rn; - - for (rn = route_top (it->imported_vpn[afi]); rn; rn = route_next (rn)) - { - /* - * Each route_node has: - * aggregate: points to rfapi_it_extra with monitor chain(s) - * info: points to chain of bgp_info - */ - /* free bgp_info and its children */ - rfapiBgpInfoChainFree (rn->info); - rn->info = NULL; - - rfapiMonitorExtraFlush (SAFI_MPLS_VPN, rn); - } - - for (rn = route_top (it->imported_encap[afi]); rn; rn = route_next (rn)) - { - /* free bgp_info and its children */ - rfapiBgpInfoChainFree (rn->info); - rn->info = NULL; - - rfapiMonitorExtraFlush (SAFI_ENCAP, rn); - } - - route_table_finish (it->imported_vpn[afi]); - route_table_finish (it->imported_encap[afi]); - } - if (it->monitor_exterior_orphans) - { - skiplist_free (it->monitor_exterior_orphans); - } + afi_t afi; + + /* + * Free ecommunity + */ + ecommunity_free(&it->rt_import_list); + it->rt_import_list = NULL; + + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + struct route_node *rn; + + for (rn = route_top(it->imported_vpn[afi]); rn; + rn = route_next(rn)) { + /* + * Each route_node has: + * aggregate: points to rfapi_it_extra with monitor + * chain(s) + * info: points to chain of bgp_info + */ + /* free bgp_info and its children */ + rfapiBgpInfoChainFree(rn->info); + rn->info = NULL; + + rfapiMonitorExtraFlush(SAFI_MPLS_VPN, rn); + } + + for (rn = route_top(it->imported_encap[afi]); rn; + rn = route_next(rn)) { + /* free bgp_info and its children */ + rfapiBgpInfoChainFree(rn->info); + rn->info = NULL; + + rfapiMonitorExtraFlush(SAFI_ENCAP, rn); + } + + route_table_finish(it->imported_vpn[afi]); + route_table_finish(it->imported_encap[afi]); + } + if (it->monitor_exterior_orphans) { + skiplist_free(it->monitor_exterior_orphans); + } } -void -rfapiImportTableRefDelByIt ( - struct bgp *bgp, - struct rfapi_import_table *it_target) +void rfapiImportTableRefDelByIt(struct bgp *bgp, + struct rfapi_import_table *it_target) { - struct rfapi *h; - struct rfapi_import_table *it; - struct rfapi_import_table *prev = NULL; - - assert (it_target); - - h = bgp->rfapi; - assert (h); - - for (it = h->imports; it; prev = it, it = it->next) - { - if (it == it_target) - break; - } - - assert (it); - assert (it->refcount); - - it->refcount -= 1; - - if (!it->refcount) - { - if (prev) - { - prev->next = it->next; - } - else - { - h->imports = it->next; - } - rfapiImportTableFlush (it); - XFREE (MTYPE_RFAPI_IMPORTTABLE, it); - } + struct rfapi *h; + struct rfapi_import_table *it; + struct rfapi_import_table *prev = NULL; + + assert(it_target); + + h = bgp->rfapi; + assert(h); + + for (it = h->imports; it; prev = it, it = it->next) { + if (it == it_target) + break; + } + + assert(it); + assert(it->refcount); + + it->refcount -= 1; + + if (!it->refcount) { + if (prev) { + prev->next = it->next; + } else { + h->imports = it->next; + } + rfapiImportTableFlush(it); + XFREE(MTYPE_RFAPI_IMPORTTABLE, it); + } } #if RFAPI_REQUIRE_ENCAP_BEEC @@ -1050,298 +990,272 @@ rfapiImportTableRefDelByIt ( * Look for magic BGP Encapsulation Extended Community value * Format in RFC 5512 Sect. 4.5 */ -static int -rfapiEcommunitiesMatchBeec (struct ecommunity *ecom, - bgp_encap_types type) +static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom, + bgp_encap_types type) { - int i; - - if (!ecom) - return 0; + int i; - for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) - { + if (!ecom) + return 0; - uint8_t *ep; + for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) { - ep = ecom->val + i; + uint8_t *ep; - if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE && - ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP && - ep[6] == ((type && 0xff00)>>8) && - ep[7] == (type&0xff)) - { + ep = ecom->val + i; - return 1; - } - } - return 0; + if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE + && ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP + && ep[6] == ((type && 0xff00) >> 8) + && ep[7] == (type & 0xff)) { + return 1; + } + } + return 0; } #endif -int -rfapiEcommunitiesIntersect (struct ecommunity *e1, struct ecommunity *e2) +int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2) { - int i, j; - - if (!e1 || !e2) - return 0; - - { - char *s1, *s2; - s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, 0); - s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, 0); - vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__, s1, s2); - XFREE (MTYPE_ECOMMUNITY_STR, s1); - XFREE (MTYPE_ECOMMUNITY_STR, s2); - } - - for (i = 0; i < e1->size; ++i) - { - for (j = 0; j < e2->size; ++j) - { - if (!memcmp (e1->val + (i * ECOMMUNITY_SIZE), - e2->val + (j * ECOMMUNITY_SIZE), ECOMMUNITY_SIZE)) - { - - return 1; - } - } - } - return 0; + int i, j; + + if (!e1 || !e2) + return 0; + + { + char *s1, *s2; + s1 = ecommunity_ecom2str(e1, ECOMMUNITY_FORMAT_DISPLAY, 0); + s2 = ecommunity_ecom2str(e2, ECOMMUNITY_FORMAT_DISPLAY, 0); + vnc_zlog_debug_verbose("%s: e1[%s], e2[%s]", __func__, s1, s2); + XFREE(MTYPE_ECOMMUNITY_STR, s1); + XFREE(MTYPE_ECOMMUNITY_STR, s2); + } + + for (i = 0; i < e1->size; ++i) { + for (j = 0; j < e2->size; ++j) { + if (!memcmp(e1->val + (i * ECOMMUNITY_SIZE), + e2->val + (j * ECOMMUNITY_SIZE), + ECOMMUNITY_SIZE)) { + + return 1; + } + } + } + return 0; } -int -rfapiEcommunityGetLNI (struct ecommunity *ecom, uint32_t * lni) +int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni) { - if (ecom) - { - int i; - for (i = 0; i < ecom->size; ++i) - { - uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); - - if ((*(p + 0) == 0x00) && (*(p + 1) == 0x02)) - { - - *lni = (*(p + 5) << 16) | (*(p + 6) << 8) | (*(p + 7)); - return 0; - } - } - } - return ENOENT; + if (ecom) { + int i; + for (i = 0; i < ecom->size; ++i) { + uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); + + if ((*(p + 0) == 0x00) && (*(p + 1) == 0x02)) { + + *lni = (*(p + 5) << 16) | (*(p + 6) << 8) + | (*(p + 7)); + return 0; + } + } + } + return ENOENT; } -int -rfapiEcommunityGetEthernetTag (struct ecommunity *ecom, uint16_t * tag_id) +int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id) { - struct bgp *bgp = bgp_get_default (); - *tag_id = 0; /* default to untagged */ - if (ecom) - { - int i; - for (i = 0; i < ecom->size; ++i) - { - as_t as = 0; - int encode = 0; - uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); - - /* High-order octet of type. */ - encode = *p++; - - if (*p++ == ECOMMUNITY_ROUTE_TARGET) { - if (encode == ECOMMUNITY_ENCODE_AS4) - { - as = (*p++ << 24); - as |= (*p++ << 16); - as |= (*p++ << 8); - as |= (*p++); - } - else if (encode == ECOMMUNITY_ENCODE_AS) - { - as = (*p++ << 8); - as |= (*p++); - p += 2; /* skip next two, tag/vid always in lowest bytes */ - } - if (as == bgp->as) - { - *tag_id = *p++ << 8; - *tag_id |= (*p++); - return 0; - } - } - } - } - return ENOENT; + struct bgp *bgp = bgp_get_default(); + *tag_id = 0; /* default to untagged */ + if (ecom) { + int i; + for (i = 0; i < ecom->size; ++i) { + as_t as = 0; + int encode = 0; + uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); + + /* High-order octet of type. */ + encode = *p++; + + if (*p++ == ECOMMUNITY_ROUTE_TARGET) { + if (encode == ECOMMUNITY_ENCODE_AS4) { + as = (*p++ << 24); + as |= (*p++ << 16); + as |= (*p++ << 8); + as |= (*p++); + } else if (encode == ECOMMUNITY_ENCODE_AS) { + as = (*p++ << 8); + as |= (*p++); + p += + 2; /* skip next two, tag/vid + always in lowest bytes */ + } + if (as == bgp->as) { + *tag_id = *p++ << 8; + *tag_id |= (*p++); + return 0; + } + } + } + } + return ENOENT; } -static int -rfapiVpnBiNhEqualsPt (struct bgp_info *bi, struct rfapi_ip_addr *hpt) +static int rfapiVpnBiNhEqualsPt(struct bgp_info *bi, struct rfapi_ip_addr *hpt) { - uint8_t family; + uint8_t family; - if (!hpt || !bi) - return 0; + if (!hpt || !bi) + return 0; - family = BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len); + family = BGP_MP_NEXTHOP_FAMILY(bi->attr->mp_nexthop_len); - if (hpt->addr_family != family) - return 0; + if (hpt->addr_family != family) + return 0; - switch (family) - { - case AF_INET: - if (bi->attr->mp_nexthop_global_in.s_addr != hpt->addr.v4.s_addr) - return 0; - break; + switch (family) { + case AF_INET: + if (bi->attr->mp_nexthop_global_in.s_addr + != hpt->addr.v4.s_addr) + return 0; + break; - case AF_INET6: - if (IPV6_ADDR_CMP (&bi->attr->mp_nexthop_global, &hpt->addr.v6)) - return 0; - break; + case AF_INET6: + if (IPV6_ADDR_CMP(&bi->attr->mp_nexthop_global, &hpt->addr.v6)) + return 0; + break; - default: - return 0; - break; - } + default: + return 0; + break; + } - return 1; + return 1; } /* * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses */ -static int -rfapiVpnBiSamePtUn (struct bgp_info *bi1, struct bgp_info *bi2) +static int rfapiVpnBiSamePtUn(struct bgp_info *bi1, struct bgp_info *bi2) { - struct prefix pfx_un1; - struct prefix pfx_un2; - - if (!bi1 || !bi2) - return 0; - - if (!bi1->attr || !bi2->attr) - return 0; - - /* - * VN address comparisons - */ - - if (BGP_MP_NEXTHOP_FAMILY (bi1->attr->mp_nexthop_len) != - BGP_MP_NEXTHOP_FAMILY (bi2->attr->mp_nexthop_len)) - { - return 0; - } - - switch (BGP_MP_NEXTHOP_FAMILY (bi1->attr->mp_nexthop_len)) - { - case AF_INET: - if (bi1->attr->mp_nexthop_global_in.s_addr != - bi2->attr->mp_nexthop_global_in.s_addr) - return 0; - break; - - case AF_INET6: - if (IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global, - &bi2->attr->mp_nexthop_global)) - return 0; - break; - - default: - return 0; - break; - } - - /* - * UN address comparisons - */ - if (rfapiGetVncTunnelUnAddr (bi1->attr, &pfx_un1)) - { - if (bi1->extra) - { - pfx_un1.family = bi1->extra->vnc.import.un_family; - switch (bi1->extra->vnc.import.un_family) - { - case AF_INET: - pfx_un1.u.prefix4 = bi1->extra->vnc.import.un.addr4; - break; - case AF_INET6: - pfx_un1.u.prefix6 = bi1->extra->vnc.import.un.addr6; - break; - default: - pfx_un1.family = 0; - break; - } - } - } - - if (rfapiGetVncTunnelUnAddr (bi2->attr, &pfx_un2)) - { - if (bi2->extra) - { - pfx_un2.family = bi2->extra->vnc.import.un_family; - switch (bi2->extra->vnc.import.un_family) - { - case AF_INET: - pfx_un2.u.prefix4 = bi2->extra->vnc.import.un.addr4; - break; - case AF_INET6: - pfx_un2.u.prefix6 = bi2->extra->vnc.import.un.addr6; - break; - default: - pfx_un2.family = 0; - break; - } - } - } - - if (!pfx_un1.family || !pfx_un2.family) - return 0; - - if (pfx_un1.family != pfx_un2.family) - return 0; - - switch (pfx_un1.family) - { - case AF_INET: - if (!IPV4_ADDR_SAME - (&pfx_un1.u.prefix4.s_addr, &pfx_un2.u.prefix4.s_addr)) - return 0; - break; - case AF_INET6: - if (!IPV6_ADDR_SAME (&pfx_un1.u.prefix6, &pfx_un2.u.prefix6)) - return 0; - break; - } - - - - return 1; + struct prefix pfx_un1; + struct prefix pfx_un2; + + if (!bi1 || !bi2) + return 0; + + if (!bi1->attr || !bi2->attr) + return 0; + + /* + * VN address comparisons + */ + + if (BGP_MP_NEXTHOP_FAMILY(bi1->attr->mp_nexthop_len) + != BGP_MP_NEXTHOP_FAMILY(bi2->attr->mp_nexthop_len)) { + return 0; + } + + switch (BGP_MP_NEXTHOP_FAMILY(bi1->attr->mp_nexthop_len)) { + case AF_INET: + if (bi1->attr->mp_nexthop_global_in.s_addr + != bi2->attr->mp_nexthop_global_in.s_addr) + return 0; + break; + + case AF_INET6: + if (IPV6_ADDR_CMP(&bi1->attr->mp_nexthop_global, + &bi2->attr->mp_nexthop_global)) + return 0; + break; + + default: + return 0; + break; + } + + /* + * UN address comparisons + */ + if (rfapiGetVncTunnelUnAddr(bi1->attr, &pfx_un1)) { + if (bi1->extra) { + pfx_un1.family = bi1->extra->vnc.import.un_family; + switch (bi1->extra->vnc.import.un_family) { + case AF_INET: + pfx_un1.u.prefix4 = + bi1->extra->vnc.import.un.addr4; + break; + case AF_INET6: + pfx_un1.u.prefix6 = + bi1->extra->vnc.import.un.addr6; + break; + default: + pfx_un1.family = 0; + break; + } + } + } + + if (rfapiGetVncTunnelUnAddr(bi2->attr, &pfx_un2)) { + if (bi2->extra) { + pfx_un2.family = bi2->extra->vnc.import.un_family; + switch (bi2->extra->vnc.import.un_family) { + case AF_INET: + pfx_un2.u.prefix4 = + bi2->extra->vnc.import.un.addr4; + break; + case AF_INET6: + pfx_un2.u.prefix6 = + bi2->extra->vnc.import.un.addr6; + break; + default: + pfx_un2.family = 0; + break; + } + } + } + + if (!pfx_un1.family || !pfx_un2.family) + return 0; + + if (pfx_un1.family != pfx_un2.family) + return 0; + + switch (pfx_un1.family) { + case AF_INET: + if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4.s_addr, + &pfx_un2.u.prefix4.s_addr)) + return 0; + break; + case AF_INET6: + if (!IPV6_ADDR_SAME(&pfx_un1.u.prefix6, &pfx_un2.u.prefix6)) + return 0; + break; + } + + + return 1; } -uint8_t -rfapiRfpCost (struct attr * attr) +uint8_t rfapiRfpCost(struct attr *attr) { - if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) - { - if (attr->local_pref > 255) - { - return 0; - } - return 255 - attr->local_pref; - } - - return 255; + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { + if (attr->local_pref > 255) { + return 0; + } + return 255 - attr->local_pref; + } + + return 255; } /*------------------------------------------ * rfapi_extract_l2o * - * Find Layer 2 options in an option chain + * Find Layer 2 options in an option chain * - * input: + * input: * pHop option chain * * output: @@ -1352,404 +1266,384 @@ rfapiRfpCost (struct attr * attr) * 1 no options found * --------------------------------------------*/ -int -rfapi_extract_l2o (struct bgp_tea_options *pHop, /* chain of options */ - struct rfapi_l2address_option *l2o) /* return extracted value */ +int rfapi_extract_l2o( + struct bgp_tea_options *pHop, /* chain of options */ + struct rfapi_l2address_option *l2o) /* return extracted value */ { - struct bgp_tea_options *p; + struct bgp_tea_options *p; - for (p = pHop; p; p = p->next) - { - if ((p->type == RFAPI_VN_OPTION_TYPE_L2ADDR) && (p->length >= 8)) - { + for (p = pHop; p; p = p->next) { + if ((p->type == RFAPI_VN_OPTION_TYPE_L2ADDR) + && (p->length >= 8)) { - char *v = p->value; + char *v = p->value; - memcpy (&l2o->macaddr, v, 6); + memcpy(&l2o->macaddr, v, 6); - l2o->label = - ((v[6] << 12) & 0xff000) + - ((v[7] << 4) & 0xff0) + ((v[8] >> 4) & 0xf); + l2o->label = ((v[6] << 12) & 0xff000) + + ((v[7] << 4) & 0xff0) + + ((v[8] >> 4) & 0xf); - l2o->local_nve_id = (uint8_t) v[10]; + l2o->local_nve_id = (uint8_t)v[10]; - l2o->logical_net_id = (v[11] << 16) + (v[12] << 8) + (v[13] << 0); + l2o->logical_net_id = + (v[11] << 16) + (v[12] << 8) + (v[13] << 0); - return 0; - } - } - return 1; + return 0; + } + } + return 1; } static struct rfapi_next_hop_entry * -rfapiRouteInfo2NextHopEntry ( - struct rfapi_ip_prefix *rprefix, - struct bgp_info *bi, /* route to encode */ - uint32_t lifetime, /* use this in nhe */ - struct route_node *rn) /* req for L2 eth addr */ +rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, + struct bgp_info *bi, /* route to encode */ + uint32_t lifetime, /* use this in nhe */ + struct route_node *rn) /* req for L2 eth addr */ { - struct rfapi_next_hop_entry *new; - int have_vnc_tunnel_un = 0; + struct rfapi_next_hop_entry *new; + int have_vnc_tunnel_un = 0; #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: entry, bi %p, rn %p", __func__, bi, rn); + vnc_zlog_debug_verbose("%s: entry, bi %p, rn %p", __func__, bi, rn); #endif - new = XCALLOC (MTYPE_RFAPI_NEXTHOP, sizeof (struct rfapi_next_hop_entry)); - assert (new); - - new->prefix = *rprefix; - - if (bi->extra && - decode_rd_type(bi->extra->vnc.import.rd.val) == RD_TYPE_VNC_ETH) - { - /* ethernet */ - - struct rfapi_vn_option *vo; - - vo = XCALLOC (MTYPE_RFAPI_VN_OPTION, sizeof (struct rfapi_vn_option)); - assert (vo); - - vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR; - - memcpy (&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet, - ETHER_ADDR_LEN); - /* only low 3 bytes of this are significant */ - if (bi->attr) - { - (void) rfapiEcommunityGetLNI (bi->attr->ecommunity, - &vo->v.l2addr.logical_net_id); - (void) rfapiEcommunityGetEthernetTag (bi->attr->ecommunity, - &vo->v.l2addr.tag_id); - } - - /* local_nve_id comes from lower byte of RD type */ - vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1]; - - /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label (&bi->extra->label); - - new->vn_options = vo; - - /* - * If there is an auxiliary prefix (i.e., host IP address), - * use it as the nexthop prefix instead of the query prefix - */ - if (bi->extra->vnc.import.aux_prefix.family) - { - rfapiQprefix2Rprefix (&bi->extra->vnc.import.aux_prefix, - &new->prefix); - } - } - - if (bi->attr) - { - bgp_encap_types tun_type; - new->prefix.cost = rfapiRfpCost (bi->attr); - - struct bgp_attr_encap_subtlv *pEncap; - - switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len)) - { - case AF_INET: - new->vn_address.addr_family = AF_INET; - new->vn_address.addr.v4 = bi->attr->mp_nexthop_global_in; - break; - - case AF_INET6: - new->vn_address.addr_family = AF_INET6; - new->vn_address.addr.v6 = bi->attr->mp_nexthop_global; - break; - - default: - zlog_warn ("%s: invalid vpn nexthop length: %d", - __func__, bi->attr->mp_nexthop_len); - rfapi_free_next_hop_list (new); - return NULL; - } - - for (pEncap = bi->attr->vnc_subtlvs; pEncap; - pEncap = pEncap->next) - { - switch (pEncap->type) - { - case BGP_VNC_SUBTLV_TYPE_LIFETIME: - /* use configured lifetime, not attr lifetime */ - break; - - default: - zlog_warn ("%s: unknown VNC option type %d", - __func__, pEncap->type); - - - break; - } - } - - rfapiGetTunnelType (bi->attr, &tun_type); - if (tun_type == BGP_ENCAP_TYPE_MPLS) - { - struct prefix p; - /* MPLS carries UN address in next hop */ - rfapiNexthop2Prefix (bi->attr, &p); - if (p.family != 0) - { - rfapiQprefix2Raddr(&p, &new->un_address); - have_vnc_tunnel_un = 1; - } - } - - for (pEncap = bi->attr->encap_subtlvs; pEncap; - pEncap = pEncap->next) - { - switch (pEncap->type) - { - case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: - /* - * Overrides ENCAP UN address, if any - */ - switch (pEncap->length) - { - - case 8: - new->un_address.addr_family = AF_INET; - memcpy (&new->un_address.addr.v4, pEncap->value, 4); - have_vnc_tunnel_un = 1; - break; - - case 20: - new->un_address.addr_family = AF_INET6; - memcpy (&new->un_address.addr.v6, pEncap->value, 16); - have_vnc_tunnel_un = 1; - break; - - default: - zlog_warn - ("%s: invalid tunnel subtlv UN addr length (%d) for bi %p", - __func__, pEncap->length, bi); - } - break; - - default: - zlog_warn ("%s: unknown Encap Attribute option type %d", - __func__, pEncap->type); - - - break; - } - } - - new->un_options = rfapi_encap_tlv_to_un_option (bi->attr); + new = XCALLOC(MTYPE_RFAPI_NEXTHOP, sizeof(struct rfapi_next_hop_entry)); + assert(new); + + new->prefix = *rprefix; + + if (bi->extra + && decode_rd_type(bi->extra->vnc.import.rd.val) + == RD_TYPE_VNC_ETH) { + /* ethernet */ + + struct rfapi_vn_option *vo; + + vo = XCALLOC(MTYPE_RFAPI_VN_OPTION, + sizeof(struct rfapi_vn_option)); + assert(vo); + + vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR; + + memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet, + ETHER_ADDR_LEN); + /* only low 3 bytes of this are significant */ + if (bi->attr) { + (void)rfapiEcommunityGetLNI( + bi->attr->ecommunity, + &vo->v.l2addr.logical_net_id); + (void)rfapiEcommunityGetEthernetTag( + bi->attr->ecommunity, &vo->v.l2addr.tag_id); + } + + /* local_nve_id comes from lower byte of RD type */ + vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1]; + + /* label comes from MP_REACH_NLRI label */ + vo->v.l2addr.label = decode_label(&bi->extra->label); + + new->vn_options = vo; + + /* + * If there is an auxiliary prefix (i.e., host IP address), + * use it as the nexthop prefix instead of the query prefix + */ + if (bi->extra->vnc.import.aux_prefix.family) { + rfapiQprefix2Rprefix(&bi->extra->vnc.import.aux_prefix, + &new->prefix); + } + } + + if (bi->attr) { + bgp_encap_types tun_type; + new->prefix.cost = rfapiRfpCost(bi->attr); + + struct bgp_attr_encap_subtlv *pEncap; + + switch (BGP_MP_NEXTHOP_FAMILY(bi->attr->mp_nexthop_len)) { + case AF_INET: + new->vn_address.addr_family = AF_INET; + new->vn_address.addr.v4 = + bi->attr->mp_nexthop_global_in; + break; + + case AF_INET6: + new->vn_address.addr_family = AF_INET6; + new->vn_address.addr.v6 = bi->attr->mp_nexthop_global; + break; + + default: + zlog_warn("%s: invalid vpn nexthop length: %d", + __func__, bi->attr->mp_nexthop_len); + rfapi_free_next_hop_list(new); + return NULL; + } + + for (pEncap = bi->attr->vnc_subtlvs; pEncap; + pEncap = pEncap->next) { + switch (pEncap->type) { + case BGP_VNC_SUBTLV_TYPE_LIFETIME: + /* use configured lifetime, not attr lifetime */ + break; + + default: + zlog_warn("%s: unknown VNC option type %d", + __func__, pEncap->type); + + + break; + } + } + + rfapiGetTunnelType(bi->attr, &tun_type); + if (tun_type == BGP_ENCAP_TYPE_MPLS) { + struct prefix p; + /* MPLS carries UN address in next hop */ + rfapiNexthop2Prefix(bi->attr, &p); + if (p.family != 0) { + rfapiQprefix2Raddr(&p, &new->un_address); + have_vnc_tunnel_un = 1; + } + } + + for (pEncap = bi->attr->encap_subtlvs; pEncap; + pEncap = pEncap->next) { + switch (pEncap->type) { + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + /* + * Overrides ENCAP UN address, if any + */ + switch (pEncap->length) { + + case 8: + new->un_address.addr_family = AF_INET; + memcpy(&new->un_address.addr.v4, + pEncap->value, 4); + have_vnc_tunnel_un = 1; + break; + + case 20: + new->un_address.addr_family = AF_INET6; + memcpy(&new->un_address.addr.v6, + pEncap->value, 16); + have_vnc_tunnel_un = 1; + break; + + default: + zlog_warn( + "%s: invalid tunnel subtlv UN addr length (%d) for bi %p", + __func__, pEncap->length, bi); + } + break; + + default: + zlog_warn( + "%s: unknown Encap Attribute option type %d", + __func__, pEncap->type); + + + break; + } + } + + new->un_options = rfapi_encap_tlv_to_un_option(bi->attr); #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d", - __func__, __LINE__, have_vnc_tunnel_un); + vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", + __func__, __LINE__, have_vnc_tunnel_un); #endif - if (!have_vnc_tunnel_un && bi && bi->extra) - { - /* - * use cached UN address from ENCAP route - */ - new->un_address.addr_family = bi->extra->vnc.import.un_family; - switch (new->un_address.addr_family) - { - case AF_INET: - new->un_address.addr.v4 = bi->extra->vnc.import.un.addr4; - break; - case AF_INET6: - new->un_address.addr.v6 = bi->extra->vnc.import.un.addr6; - break; - default: - zlog_warn ("%s: invalid UN addr family (%d) for bi %p", - __func__, new->un_address.addr_family, bi); - rfapi_free_next_hop_list (new); - return NULL; - break; - } - } - } - - new->lifetime = lifetime; - return new; + if (!have_vnc_tunnel_un && bi && bi->extra) { + /* + * use cached UN address from ENCAP route + */ + new->un_address.addr_family = + bi->extra->vnc.import.un_family; + switch (new->un_address.addr_family) { + case AF_INET: + new->un_address.addr.v4 = + bi->extra->vnc.import.un.addr4; + break; + case AF_INET6: + new->un_address.addr.v6 = + bi->extra->vnc.import.un.addr6; + break; + default: + zlog_warn( + "%s: invalid UN addr family (%d) for bi %p", + __func__, new->un_address.addr_family, + bi); + rfapi_free_next_hop_list(new); + return NULL; + break; + } + } + } + + new->lifetime = lifetime; + return new; } -int -rfapiHasNonRemovedRoutes (struct route_node *rn) +int rfapiHasNonRemovedRoutes(struct route_node *rn) { - struct bgp_info *bi; + struct bgp_info *bi; - for (bi = rn->info; bi; bi = bi->next) - { - struct prefix pfx; + for (bi = rn->info; bi; bi = bi->next) { + struct prefix pfx; - if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) && - (bi->extra && !rfapiGetUnAddrOfVpnBi (bi, &pfx))) - { + if (!CHECK_FLAG(bi->flags, BGP_INFO_REMOVED) + && (bi->extra && !rfapiGetUnAddrOfVpnBi(bi, &pfx))) { - return 1; - } - } - return 0; + return 1; + } + } + return 0; } #if DEBUG_IT_NODES -/* +/* * DEBUG FUNCTION */ -void -rfapiDumpNode (struct route_node *rn) +void rfapiDumpNode(struct route_node *rn) { - struct bgp_info *bi; - - vnc_zlog_debug_verbose ("%s: rn=%p", __func__, rn); - for (bi = rn->info; bi; bi = bi->next) - { - struct prefix pfx; - int ctrc = rfapiGetUnAddrOfVpnBi (bi, &pfx); - int nr; - - if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) && (bi->extra && !ctrc)) - { - - nr = 1; - } - else - { - nr = 0; - } - - vnc_zlog_debug_verbose (" bi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d", - bi, nr, bi->flags, bi->extra, ctrc); - } + struct bgp_info *bi; + + vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn); + for (bi = rn->info; bi; bi = bi->next) { + struct prefix pfx; + int ctrc = rfapiGetUnAddrOfVpnBi(bi, &pfx); + int nr; + + if (!CHECK_FLAG(bi->flags, BGP_INFO_REMOVED) + && (bi->extra && !ctrc)) { + + nr = 1; + } else { + nr = 0; + } + + vnc_zlog_debug_verbose( + " bi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d", bi, nr, + bi->flags, bi->extra, ctrc); + } } #endif -static int -rfapiNhlAddNodeRoutes ( - struct route_node *rn, /* in */ - struct rfapi_ip_prefix *rprefix, /* in */ - uint32_t lifetime, /* in */ - int removed, /* in */ - struct rfapi_next_hop_entry **head, /* in/out */ - struct rfapi_next_hop_entry **tail, /* in/out */ - struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ - struct route_node *rfd_rib_node,/* preload this NVE rib node */ - struct prefix *pfx_target_original) /* query target */ +static int rfapiNhlAddNodeRoutes( + struct route_node *rn, /* in */ + struct rfapi_ip_prefix *rprefix, /* in */ + uint32_t lifetime, /* in */ + int removed, /* in */ + struct rfapi_next_hop_entry **head, /* in/out */ + struct rfapi_next_hop_entry **tail, /* in/out */ + struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ + struct route_node *rfd_rib_node, /* preload this NVE rib node */ + struct prefix *pfx_target_original) /* query target */ { - struct bgp_info *bi; - struct rfapi_next_hop_entry *new; - struct prefix pfx_un; - struct skiplist *seen_nexthops; - int count = 0; - int is_l2 = (rn->p.family == AF_ETHERNET); - - if (rfapiRibFTDFilterRecentPrefix( - (struct rfapi_descriptor *)(rfd_rib_node->table->info), rn, - pfx_target_original)) - { - return 0; - } - - seen_nexthops = - skiplist_new (0, vnc_prefix_cmp, (void (*)(void *)) prefix_free); - - for (bi = rn->info; bi; bi = bi->next) - { - - struct prefix pfx_vn; - struct prefix *newpfx; - - if (removed && !CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - { + struct bgp_info *bi; + struct rfapi_next_hop_entry *new; + struct prefix pfx_un; + struct skiplist *seen_nexthops; + int count = 0; + int is_l2 = (rn->p.family == AF_ETHERNET); + + if (rfapiRibFTDFilterRecentPrefix( + (struct rfapi_descriptor *)(rfd_rib_node->table->info), rn, + pfx_target_original)) { + return 0; + } + + seen_nexthops = + skiplist_new(0, vnc_prefix_cmp, (void (*)(void *))prefix_free); + + for (bi = rn->info; bi; bi = bi->next) { + + struct prefix pfx_vn; + struct prefix *newpfx; + + if (removed && !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { #if DEBUG_RETURNED_NHL - vnc_zlog_debug_verbose ("%s: want holddown, this route not holddown, skip", - __func__); + vnc_zlog_debug_verbose( + "%s: want holddown, this route not holddown, skip", + __func__); #endif - continue; - } - if (!removed && CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - { - continue; - } - - if (!bi->extra) - { - continue; - } - - /* - * Check for excluded VN address - */ - if (rfapiVpnBiNhEqualsPt (bi, exclude_vnaddr)) - continue; - - /* - * Check for VN address (nexthop) copied already - */ - if (is_l2) - { - /* L2 routes: semantic nexthop in aux_prefix; VN addr ain't it */ - pfx_vn = bi->extra->vnc.import.aux_prefix; - } - else - { - rfapiNexthop2Prefix (bi->attr, &pfx_vn); - } - if (!skiplist_search (seen_nexthops, &pfx_vn, NULL)) - { + continue; + } + if (!removed && CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { + continue; + } + + if (!bi->extra) { + continue; + } + + /* + * Check for excluded VN address + */ + if (rfapiVpnBiNhEqualsPt(bi, exclude_vnaddr)) + continue; + + /* + * Check for VN address (nexthop) copied already + */ + if (is_l2) { + /* L2 routes: semantic nexthop in aux_prefix; VN addr + * ain't it */ + pfx_vn = bi->extra->vnc.import.aux_prefix; + } else { + rfapiNexthop2Prefix(bi->attr, &pfx_vn); + } + if (!skiplist_search(seen_nexthops, &pfx_vn, NULL)) { #if DEBUG_RETURNED_NHL - char buf[BUFSIZ]; + char buf[BUFSIZ]; - prefix2str (&pfx_vn, buf, BUFSIZ); - buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */ - vnc_zlog_debug_verbose ("%s: already put VN/nexthop %s, skip", __func__, buf); + prefix2str(&pfx_vn, buf, BUFSIZ); + buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */ + vnc_zlog_debug_verbose( + "%s: already put VN/nexthop %s, skip", __func__, + buf); #endif - continue; - } + continue; + } - if (rfapiGetUnAddrOfVpnBi (bi, &pfx_un)) - { + if (rfapiGetUnAddrOfVpnBi(bi, &pfx_un)) { #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: failed to get UN address of this VPN bi", - __func__); + vnc_zlog_debug_verbose( + "%s: failed to get UN address of this VPN bi", + __func__); #endif - continue; - } - - newpfx = prefix_new (); - *newpfx = pfx_vn; - skiplist_insert (seen_nexthops, newpfx, newpfx); - - new = rfapiRouteInfo2NextHopEntry(rprefix, bi, lifetime, rn); - if (new) - { - if (rfapiRibPreloadBi(rfd_rib_node, &pfx_vn, &pfx_un, lifetime, bi)) - { - /* duplicate filtered by RIB */ - rfapi_free_next_hop_list (new); - new = NULL; - } - } - - if (new) - { - if (*tail) - { - (*tail)->next = new; - } - else - { - *head = new; - } - *tail = new; - ++count; - } - } - - skiplist_free (seen_nexthops); - - return count; + continue; + } + + newpfx = prefix_new(); + *newpfx = pfx_vn; + skiplist_insert(seen_nexthops, newpfx, newpfx); + + new = rfapiRouteInfo2NextHopEntry(rprefix, bi, lifetime, rn); + if (new) { + if (rfapiRibPreloadBi(rfd_rib_node, &pfx_vn, &pfx_un, + lifetime, bi)) { + /* duplicate filtered by RIB */ + rfapi_free_next_hop_list(new); + new = NULL; + } + } + + if (new) { + if (*tail) { + (*tail)->next = new; + } else { + *head = new; + } + *tail = new; + ++count; + } + } + + skiplist_free(seen_nexthops); + + return count; } @@ -1762,85 +1656,84 @@ rfapiNhlAddNodeRoutes ( * its routes in the list, so we skip it if the right or left node * matches (of course, we still travel down its child subtrees). */ -static int -rfapiNhlAddSubtree ( - struct route_node *rn, /* in */ - uint32_t lifetime, /* in */ - struct rfapi_next_hop_entry **head, /* in/out */ - struct rfapi_next_hop_entry **tail, /* in/out */ - struct route_node *omit_node, /* in */ - struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */ - struct route_table *rfd_rib_table,/* preload here */ - struct prefix *pfx_target_original) /* query target */ +static int rfapiNhlAddSubtree( + struct route_node *rn, /* in */ + uint32_t lifetime, /* in */ + struct rfapi_next_hop_entry **head, /* in/out */ + struct rfapi_next_hop_entry **tail, /* in/out */ + struct route_node *omit_node, /* in */ + struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ + struct route_table *rfd_rib_table, /* preload here */ + struct prefix *pfx_target_original) /* query target */ { - struct rfapi_ip_prefix rprefix; - int rcount = 0; - - /* FIXME: need to find a better way here to work without sticking our - * hands in node->link */ - if (rn->l_left && rn->l_left != omit_node) - { - if (rn->l_left->info) - { - int count = 0; - struct route_node *rib_rn = NULL; - - rfapiQprefix2Rprefix (&rn->l_left->p, &rprefix); - if (rfd_rib_table) - { - rib_rn = route_node_get(rfd_rib_table, &rn->l_left->p); - } - - count = rfapiNhlAddNodeRoutes (rn->l_left, &rprefix, lifetime, 0, - head, tail, exclude_vnaddr, rib_rn, pfx_target_original); - if (!count) - { - count = rfapiNhlAddNodeRoutes (rn->l_left, &rprefix, lifetime, 1, - head, tail, exclude_vnaddr, rib_rn, pfx_target_original); - } - rcount += count; - if (rib_rn) - route_unlock_node(rib_rn); - } - } - - if (rn->l_right && rn->l_right != omit_node) - { - if (rn->l_right->info) - { - int count = 0; - struct route_node *rib_rn = NULL; - - rfapiQprefix2Rprefix (&rn->l_right->p, &rprefix); - if (rfd_rib_table) - { - rib_rn = route_node_get(rfd_rib_table, &rn->l_right->p); - } - count = rfapiNhlAddNodeRoutes (rn->l_right, &rprefix, lifetime, 0, - head, tail, exclude_vnaddr, rib_rn, pfx_target_original); - if (!count) - { - count = rfapiNhlAddNodeRoutes (rn->l_right, &rprefix, lifetime, 1, - head, tail, exclude_vnaddr, rib_rn, pfx_target_original); - } - rcount += count; - if (rib_rn) - route_unlock_node(rib_rn); - } - } - - if (rn->l_left) - { - rcount += rfapiNhlAddSubtree (rn->l_left, lifetime, head, tail, omit_node, - exclude_vnaddr, rfd_rib_table, pfx_target_original); - } - if (rn->l_right) - { - rcount += rfapiNhlAddSubtree (rn->l_right, lifetime, head, tail, - omit_node, exclude_vnaddr, rfd_rib_table, pfx_target_original); - } - - return rcount; + struct rfapi_ip_prefix rprefix; + int rcount = 0; + + /* FIXME: need to find a better way here to work without sticking our + * hands in node->link */ + if (rn->l_left && rn->l_left != omit_node) { + if (rn->l_left->info) { + int count = 0; + struct route_node *rib_rn = NULL; + + rfapiQprefix2Rprefix(&rn->l_left->p, &rprefix); + if (rfd_rib_table) { + rib_rn = route_node_get(rfd_rib_table, + &rn->l_left->p); + } + + count = rfapiNhlAddNodeRoutes( + rn->l_left, &rprefix, lifetime, 0, head, tail, + exclude_vnaddr, rib_rn, pfx_target_original); + if (!count) { + count = rfapiNhlAddNodeRoutes( + rn->l_left, &rprefix, lifetime, 1, head, + tail, exclude_vnaddr, rib_rn, + pfx_target_original); + } + rcount += count; + if (rib_rn) + route_unlock_node(rib_rn); + } + } + + if (rn->l_right && rn->l_right != omit_node) { + if (rn->l_right->info) { + int count = 0; + struct route_node *rib_rn = NULL; + + rfapiQprefix2Rprefix(&rn->l_right->p, &rprefix); + if (rfd_rib_table) { + rib_rn = route_node_get(rfd_rib_table, + &rn->l_right->p); + } + count = rfapiNhlAddNodeRoutes( + rn->l_right, &rprefix, lifetime, 0, head, tail, + exclude_vnaddr, rib_rn, pfx_target_original); + if (!count) { + count = rfapiNhlAddNodeRoutes( + rn->l_right, &rprefix, lifetime, 1, + head, tail, exclude_vnaddr, rib_rn, + pfx_target_original); + } + rcount += count; + if (rib_rn) + route_unlock_node(rib_rn); + } + } + + if (rn->l_left) { + rcount += rfapiNhlAddSubtree( + rn->l_left, lifetime, head, tail, omit_node, + exclude_vnaddr, rfd_rib_table, pfx_target_original); + } + if (rn->l_right) { + rcount += rfapiNhlAddSubtree( + rn->l_right, lifetime, head, tail, omit_node, + exclude_vnaddr, rfd_rib_table, pfx_target_original); + } + + return rcount; } /* @@ -1854,343 +1747,326 @@ rfapiNhlAddSubtree ( * then return those, and also include all the non-removed routes from the * next less-specific node (i.e., this node's parent) at the end. */ -struct rfapi_next_hop_entry * -rfapiRouteNode2NextHopList ( - struct route_node *rn, - uint32_t lifetime, /* put into nexthop entries */ - struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */ - struct route_table *rfd_rib_table,/* preload here */ - struct prefix *pfx_target_original) /* query target */ +struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList( + struct route_node *rn, uint32_t lifetime, /* put into nexthop entries */ + struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ + struct route_table *rfd_rib_table, /* preload here */ + struct prefix *pfx_target_original) /* query target */ { - struct rfapi_ip_prefix rprefix; - struct rfapi_next_hop_entry *answer = NULL; - struct rfapi_next_hop_entry *last = NULL; - struct route_node *parent; - int count = 0; - struct route_node *rib_rn; + struct rfapi_ip_prefix rprefix; + struct rfapi_next_hop_entry *answer = NULL; + struct rfapi_next_hop_entry *last = NULL; + struct route_node *parent; + int count = 0; + struct route_node *rib_rn; #if DEBUG_RETURNED_NHL - { - char buf[BUFSIZ]; - - prefix2str (&rn->p, buf, BUFSIZ); - buf[BUFSIZ - 1] = 0; - vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__, buf); - } - rfapiDebugBacktrace (); + { + char buf[BUFSIZ]; + + prefix2str(&rn->p, buf, BUFSIZ); + buf[BUFSIZ - 1] = 0; + vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__, + buf); + } + rfapiDebugBacktrace(); #endif - rfapiQprefix2Rprefix (&rn->p, &rprefix); - - rib_rn = rfd_rib_table? route_node_get(rfd_rib_table, &rn->p): NULL; - - /* - * Add non-withdrawn routes at this node - */ - count = rfapiNhlAddNodeRoutes (rn, &rprefix, lifetime, 0, &answer, &last, - exclude_vnaddr, rib_rn, pfx_target_original); - - /* - * If the list has at least one entry, it's finished - */ - if (count) - { - count += rfapiNhlAddSubtree (rn, lifetime, &answer, &last, NULL, - exclude_vnaddr, rfd_rib_table, pfx_target_original); - vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__, count, answer); + rfapiQprefix2Rprefix(&rn->p, &rprefix); + + rib_rn = rfd_rib_table ? route_node_get(rfd_rib_table, &rn->p) : NULL; + + /* + * Add non-withdrawn routes at this node + */ + count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 0, &answer, &last, + exclude_vnaddr, rib_rn, + pfx_target_original); + + /* + * If the list has at least one entry, it's finished + */ + if (count) { + count += rfapiNhlAddSubtree(rn, lifetime, &answer, &last, NULL, + exclude_vnaddr, rfd_rib_table, + pfx_target_original); + vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__, + count, answer); #if DEBUG_RETURNED_NHL - rfapiPrintNhl (NULL, answer); + rfapiPrintNhl(NULL, answer); #endif - if (rib_rn) - route_unlock_node(rib_rn); - return answer; - } - - /* - * Add withdrawn routes at this node - */ - count = rfapiNhlAddNodeRoutes (rn, &rprefix, lifetime, 1, &answer, &last, - exclude_vnaddr, rib_rn, pfx_target_original); - if (rib_rn) - route_unlock_node(rib_rn); - - // rfapiPrintNhl(NULL, answer); - - /* - * walk up the tree until we find a node with non-deleted - * routes, then add them - */ - for (parent = rn->parent; parent; parent = parent->parent) - { - if (rfapiHasNonRemovedRoutes (parent)) - { - break; - } - } - - /* - * Add non-withdrawn routes from less-specific prefix - */ - if (parent) - { - rib_rn = rfd_rib_table? route_node_get(rfd_rib_table, &parent->p): NULL; - rfapiQprefix2Rprefix (&parent->p, &rprefix); - count += rfapiNhlAddNodeRoutes (parent, &rprefix, lifetime, 0, - &answer, &last, exclude_vnaddr, rib_rn, pfx_target_original); - count += rfapiNhlAddSubtree (parent, lifetime, &answer, &last, rn, - exclude_vnaddr, rfd_rib_table, pfx_target_original); - if (rib_rn) - route_unlock_node(rib_rn); - } - else - { - /* - * There is no parent with non-removed routes. Still need to - * add subtree of original node if it contributed routes to the - * answer. - */ - if (count) - count += rfapiNhlAddSubtree (rn, lifetime, &answer, &last, rn, - exclude_vnaddr, rfd_rib_table, pfx_target_original); - } - - vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__, count, answer); + if (rib_rn) + route_unlock_node(rib_rn); + return answer; + } + + /* + * Add withdrawn routes at this node + */ + count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 1, &answer, &last, + exclude_vnaddr, rib_rn, + pfx_target_original); + if (rib_rn) + route_unlock_node(rib_rn); + + // rfapiPrintNhl(NULL, answer); + + /* + * walk up the tree until we find a node with non-deleted + * routes, then add them + */ + for (parent = rn->parent; parent; parent = parent->parent) { + if (rfapiHasNonRemovedRoutes(parent)) { + break; + } + } + + /* + * Add non-withdrawn routes from less-specific prefix + */ + if (parent) { + rib_rn = rfd_rib_table + ? route_node_get(rfd_rib_table, &parent->p) + : NULL; + rfapiQprefix2Rprefix(&parent->p, &rprefix); + count += rfapiNhlAddNodeRoutes(parent, &rprefix, lifetime, 0, + &answer, &last, exclude_vnaddr, + rib_rn, pfx_target_original); + count += rfapiNhlAddSubtree(parent, lifetime, &answer, &last, + rn, exclude_vnaddr, rfd_rib_table, + pfx_target_original); + if (rib_rn) + route_unlock_node(rib_rn); + } else { + /* + * There is no parent with non-removed routes. Still need to + * add subtree of original node if it contributed routes to the + * answer. + */ + if (count) + count += rfapiNhlAddSubtree(rn, lifetime, &answer, + &last, rn, exclude_vnaddr, + rfd_rib_table, + pfx_target_original); + } + + vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__, count, + answer); #if DEBUG_RETURNED_NHL - rfapiPrintNhl (NULL, answer); + rfapiPrintNhl(NULL, answer); #endif - return answer; + return answer; } /* * Construct nexthop list of all routes in table */ -struct rfapi_next_hop_entry * -rfapiRouteTable2NextHopList ( - struct route_table *rt, - uint32_t lifetime, /* put into nexthop entries */ - struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */ - struct route_table *rfd_rib_table, /* preload this NVE rib table */ - struct prefix *pfx_target_original) /* query target */ +struct rfapi_next_hop_entry *rfapiRouteTable2NextHopList( + struct route_table *rt, + uint32_t lifetime, /* put into nexthop entries */ + struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ + struct route_table *rfd_rib_table, /* preload this NVE rib table */ + struct prefix *pfx_target_original) /* query target */ { - struct route_node *rn; - struct rfapi_next_hop_entry *biglist = NULL; - struct rfapi_next_hop_entry *nhl; - struct rfapi_next_hop_entry *tail = NULL; - int count = 0; - - for (rn = route_top (rt); rn; rn = route_next (rn)) - { - - nhl = rfapiRouteNode2NextHopList (rn, lifetime, exclude_vnaddr, - rfd_rib_table, pfx_target_original); - if (!tail) - { - tail = biglist = nhl; - if (tail) - count = 1; - } - else - { - tail->next = nhl; - } - if (tail) - { - while (tail->next) - { - ++count; - tail = tail->next; - } - } - } - - vnc_zlog_debug_verbose ("%s: returning %d routes", __func__, count); - return biglist; + struct route_node *rn; + struct rfapi_next_hop_entry *biglist = NULL; + struct rfapi_next_hop_entry *nhl; + struct rfapi_next_hop_entry *tail = NULL; + int count = 0; + + for (rn = route_top(rt); rn; rn = route_next(rn)) { + + nhl = rfapiRouteNode2NextHopList(rn, lifetime, exclude_vnaddr, + rfd_rib_table, + pfx_target_original); + if (!tail) { + tail = biglist = nhl; + if (tail) + count = 1; + } else { + tail->next = nhl; + } + if (tail) { + while (tail->next) { + ++count; + tail = tail->next; + } + } + } + + vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count); + return biglist; } -struct rfapi_next_hop_entry * -rfapiEthRouteNode2NextHopList ( - struct route_node *rn, - struct rfapi_ip_prefix *rprefix, - uint32_t lifetime, /* put into nexthop entries */ - struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */ - struct route_table *rfd_rib_table,/* preload NVE rib table */ - struct prefix *pfx_target_original) /* query target */ +struct rfapi_next_hop_entry *rfapiEthRouteNode2NextHopList( + struct route_node *rn, struct rfapi_ip_prefix *rprefix, + uint32_t lifetime, /* put into nexthop entries */ + struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ + struct route_table *rfd_rib_table, /* preload NVE rib table */ + struct prefix *pfx_target_original) /* query target */ { - int count = 0; - struct rfapi_next_hop_entry *answer = NULL; - struct rfapi_next_hop_entry *last = NULL; - struct route_node *rib_rn; + int count = 0; + struct rfapi_next_hop_entry *answer = NULL; + struct rfapi_next_hop_entry *last = NULL; + struct route_node *rib_rn; - rib_rn = rfd_rib_table? route_node_get(rfd_rib_table, &rn->p): NULL; + rib_rn = rfd_rib_table ? route_node_get(rfd_rib_table, &rn->p) : NULL; - count = rfapiNhlAddNodeRoutes (rn, rprefix, lifetime, 0, &answer, &last, - NULL, rib_rn, pfx_target_original); + count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 0, &answer, &last, + NULL, rib_rn, pfx_target_original); #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: node %p: %d non-holddown routes", __func__, rn, count); + vnc_zlog_debug_verbose("%s: node %p: %d non-holddown routes", __func__, + rn, count); #endif - if (!count) - { - count = rfapiNhlAddNodeRoutes (rn, rprefix, lifetime, 1, &answer, &last, - exclude_vnaddr, rib_rn, pfx_target_original); - vnc_zlog_debug_verbose ("%s: node %p: %d holddown routes", __func__, rn, count); - } + if (!count) { + count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 1, &answer, + &last, exclude_vnaddr, rib_rn, + pfx_target_original); + vnc_zlog_debug_verbose("%s: node %p: %d holddown routes", + __func__, rn, count); + } - if (rib_rn) - route_unlock_node(rib_rn); + if (rib_rn) + route_unlock_node(rib_rn); #if DEBUG_RETURNED_NHL - rfapiPrintNhl (NULL, answer); + rfapiPrintNhl(NULL, answer); #endif - return answer; + return answer; } /* * Construct nexthop list of all routes in table */ -struct rfapi_next_hop_entry * -rfapiEthRouteTable2NextHopList ( - uint32_t logical_net_id, - struct rfapi_ip_prefix *rprefix, - uint32_t lifetime, /* put into nexthop entries */ - struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */ - struct route_table *rfd_rib_table, /* preload NVE rib node */ - struct prefix *pfx_target_original) /* query target */ +struct rfapi_next_hop_entry *rfapiEthRouteTable2NextHopList( + uint32_t logical_net_id, struct rfapi_ip_prefix *rprefix, + uint32_t lifetime, /* put into nexthop entries */ + struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */ + struct route_table *rfd_rib_table, /* preload NVE rib node */ + struct prefix *pfx_target_original) /* query target */ { - struct rfapi_import_table *it; - struct bgp *bgp = bgp_get_default (); - struct route_table *rt; - struct route_node *rn; - struct rfapi_next_hop_entry *biglist = NULL; - struct rfapi_next_hop_entry *nhl; - struct rfapi_next_hop_entry *tail = NULL; - int count = 0; - - - it = rfapiMacImportTableGet (bgp, logical_net_id); - rt = it->imported_vpn[AFI_L2VPN]; - - for (rn = route_top (rt); rn; rn = route_next (rn)) - { - - nhl = rfapiEthRouteNode2NextHopList(rn, rprefix, lifetime, - exclude_vnaddr, rfd_rib_table, pfx_target_original); - if (!tail) - { - tail = biglist = nhl; - if (tail) - count = 1; - } - else - { - tail->next = nhl; - } - if (tail) - { - while (tail->next) - { - ++count; - tail = tail->next; - } - } - } - - vnc_zlog_debug_verbose ("%s: returning %d routes", __func__, count); - return biglist; + struct rfapi_import_table *it; + struct bgp *bgp = bgp_get_default(); + struct route_table *rt; + struct route_node *rn; + struct rfapi_next_hop_entry *biglist = NULL; + struct rfapi_next_hop_entry *nhl; + struct rfapi_next_hop_entry *tail = NULL; + int count = 0; + + + it = rfapiMacImportTableGet(bgp, logical_net_id); + rt = it->imported_vpn[AFI_L2VPN]; + + for (rn = route_top(rt); rn; rn = route_next(rn)) { + + nhl = rfapiEthRouteNode2NextHopList( + rn, rprefix, lifetime, exclude_vnaddr, rfd_rib_table, + pfx_target_original); + if (!tail) { + tail = biglist = nhl; + if (tail) + count = 1; + } else { + tail->next = nhl; + } + if (tail) { + while (tail->next) { + ++count; + tail = tail->next; + } + } + } + + vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count); + return biglist; } /* * Insert a new bi to the imported route table node, * keeping the list of BIs sorted best route first */ -static void -rfapiBgpInfoAttachSorted ( - struct route_node *rn, - struct bgp_info *info_new, - afi_t afi, - safi_t safi) +static void rfapiBgpInfoAttachSorted(struct route_node *rn, + struct bgp_info *info_new, afi_t afi, + safi_t safi) { - struct bgp *bgp; - struct bgp_info *prev; - struct bgp_info *next; - char pfx_buf[PREFIX2STR_BUFFER]; - - - bgp = bgp_get_default (); /* assume 1 instance for now */ - - if (VNC_DEBUG(IMPORT_BI_ATTACH)) - { - vnc_zlog_debug_verbose ("%s: info_new->peer=%p", __func__, info_new->peer); - vnc_zlog_debug_verbose ("%s: info_new->peer->su_remote=%p", __func__, - info_new->peer->su_remote); - } - - for (prev = NULL, next = rn->info; next; prev = next, next = next->next) - { - if (!bgp || - (!CHECK_FLAG (info_new->flags, BGP_INFO_REMOVED) && - CHECK_FLAG (next->flags, BGP_INFO_REMOVED)) || - bgp_info_cmp_compatible (bgp, info_new, next, pfx_buf, afi, safi) == -1) - { /* -1 if 1st is better */ - break; - } - } - vnc_zlog_debug_verbose ("%s: prev=%p, next=%p", __func__, prev, next); - if (prev) - { - prev->next = info_new; - } - else - { - rn->info = info_new; - } - info_new->prev = prev; - info_new->next = next; - if (next) - next->prev = info_new; - bgp_attr_intern (info_new->attr); + struct bgp *bgp; + struct bgp_info *prev; + struct bgp_info *next; + char pfx_buf[PREFIX2STR_BUFFER]; + + + bgp = bgp_get_default(); /* assume 1 instance for now */ + + if (VNC_DEBUG(IMPORT_BI_ATTACH)) { + vnc_zlog_debug_verbose("%s: info_new->peer=%p", __func__, + info_new->peer); + vnc_zlog_debug_verbose("%s: info_new->peer->su_remote=%p", + __func__, info_new->peer->su_remote); + } + + for (prev = NULL, next = rn->info; next; + prev = next, next = next->next) { + if (!bgp || (!CHECK_FLAG(info_new->flags, BGP_INFO_REMOVED) + && CHECK_FLAG(next->flags, BGP_INFO_REMOVED)) + || bgp_info_cmp_compatible(bgp, info_new, next, pfx_buf, + afi, safi) + == -1) { /* -1 if 1st is better */ + break; + } + } + vnc_zlog_debug_verbose("%s: prev=%p, next=%p", __func__, prev, next); + if (prev) { + prev->next = info_new; + } else { + rn->info = info_new; + } + info_new->prev = prev; + info_new->next = next; + if (next) + next->prev = info_new; + bgp_attr_intern(info_new->attr); } -static void -rfapiBgpInfoDetach (struct route_node *rn, struct bgp_info *bi) +static void rfapiBgpInfoDetach(struct route_node *rn, struct bgp_info *bi) { - /* - * Remove the route (doubly-linked) - */ - // bgp_attr_unintern (&bi->attr); - if (bi->next) - bi->next->prev = bi->prev; - if (bi->prev) - bi->prev->next = bi->next; - else - rn->info = bi->next; + /* + * Remove the route (doubly-linked) + */ + // bgp_attr_unintern (&bi->attr); + if (bi->next) + bi->next->prev = bi->prev; + if (bi->prev) + bi->prev->next = bi->next; + else + rn->info = bi->next; } /* * For L3-indexed import tables */ -static int -rfapi_bi_peer_rd_cmp (void *b1, void *b2) +static int rfapi_bi_peer_rd_cmp(void *b1, void *b2) { - struct bgp_info *bi1 = b1; - struct bgp_info *bi2 = b2; - - /* - * Compare peers - */ - if (bi1->peer < bi2->peer) - return -1; - if (bi1->peer > bi2->peer) - return 1; - - /* - * compare RDs - */ - return vnc_prefix_cmp ((struct prefix *) &bi1->extra->vnc.import.rd, - (struct prefix *) &bi2->extra->vnc.import.rd); + struct bgp_info *bi1 = b1; + struct bgp_info *bi2 = b2; + + /* + * Compare peers + */ + if (bi1->peer < bi2->peer) + return -1; + if (bi1->peer > bi2->peer) + return 1; + + /* + * compare RDs + */ + return vnc_prefix_cmp((struct prefix *)&bi1->extra->vnc.import.rd, + (struct prefix *)&bi2->extra->vnc.import.rd); } /* @@ -2198,765 +2074,717 @@ rfapi_bi_peer_rd_cmp (void *b1, void *b2) * The BIs in these tables should ALWAYS have an aux_prefix set because * they arrive via IPv4 or IPv6 advertisements. */ -static int -rfapi_bi_peer_rd_aux_cmp (void *b1, void *b2) +static int rfapi_bi_peer_rd_aux_cmp(void *b1, void *b2) { - struct bgp_info *bi1 = b1; - struct bgp_info *bi2 = b2; - int rc; - - /* - * Compare peers - */ - if (bi1->peer < bi2->peer) - return -1; - if (bi1->peer > bi2->peer) - return 1; - - /* - * compare RDs - */ - rc = vnc_prefix_cmp ((struct prefix *) &bi1->extra->vnc.import.rd, - (struct prefix *) &bi2->extra->vnc.import.rd); - if (rc) - { - return rc; - } - - /* - * L2 import tables can have multiple entries with the - * same MAC address, same RD, but different L3 addresses. - * - * Use presence of aux_prefix with AF=ethernet and prefixlen=1 - * as magic value to signify explicit wildcarding of the aux_prefix. - * This magic value will not appear in bona fide bi entries in - * the import table, but is allowed in the "fake" bi used to - * probe the table when searching. (We have to test both b1 and b2 - * because there is no guarantee of the order the test key and - * the real key will be passed) - */ - if ((bi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET && - (bi1->extra->vnc.import.aux_prefix.prefixlen == 1)) || - (bi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET && - (bi2->extra->vnc.import.aux_prefix.prefixlen == 1))) - { - - /* - * wildcard aux address specified - */ - return 0; - } - - return vnc_prefix_cmp (&bi1->extra->vnc.import.aux_prefix, - &bi2->extra->vnc.import.aux_prefix); + struct bgp_info *bi1 = b1; + struct bgp_info *bi2 = b2; + int rc; + + /* + * Compare peers + */ + if (bi1->peer < bi2->peer) + return -1; + if (bi1->peer > bi2->peer) + return 1; + + /* + * compare RDs + */ + rc = vnc_prefix_cmp((struct prefix *)&bi1->extra->vnc.import.rd, + (struct prefix *)&bi2->extra->vnc.import.rd); + if (rc) { + return rc; + } + + /* + * L2 import tables can have multiple entries with the + * same MAC address, same RD, but different L3 addresses. + * + * Use presence of aux_prefix with AF=ethernet and prefixlen=1 + * as magic value to signify explicit wildcarding of the aux_prefix. + * This magic value will not appear in bona fide bi entries in + * the import table, but is allowed in the "fake" bi used to + * probe the table when searching. (We have to test both b1 and b2 + * because there is no guarantee of the order the test key and + * the real key will be passed) + */ + if ((bi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET + && (bi1->extra->vnc.import.aux_prefix.prefixlen == 1)) + || (bi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET + && (bi2->extra->vnc.import.aux_prefix.prefixlen == 1))) { + + /* + * wildcard aux address specified + */ + return 0; + } + + return vnc_prefix_cmp(&bi1->extra->vnc.import.aux_prefix, + &bi2->extra->vnc.import.aux_prefix); } /* * Index on RD and Peer */ -static void -rfapiItBiIndexAdd ( - struct route_node *rn, /* Import table VPN node */ - struct bgp_info *bi) /* new BI */ +static void rfapiItBiIndexAdd(struct route_node *rn, /* Import table VPN node */ + struct bgp_info *bi) /* new BI */ { - struct skiplist *sl; - - assert (rn); - assert (bi); - assert (bi->extra); - - { - char buf[BUFSIZ]; - prefix_rd2str (&bi->extra->vnc.import.rd, buf, BUFSIZ); - vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__, bi, bi->peer, buf); - } - - sl = RFAPI_RDINDEX_W_ALLOC (rn); - if (!sl) - { - if (AF_ETHERNET == rn->p.family) - { - sl = skiplist_new (0, rfapi_bi_peer_rd_aux_cmp, NULL); - } - else - { - sl = skiplist_new (0, rfapi_bi_peer_rd_cmp, NULL); - } - RFAPI_IT_EXTRA_GET (rn)->u.vpn.idx_rd = sl; - route_lock_node (rn); /* for skiplist */ - } - assert (!skiplist_insert (sl, (void *) bi, (void *) bi)); - route_lock_node (rn); /* for skiplist entry */ - - /* NB: BIs in import tables are not refcounted */ + struct skiplist *sl; + + assert(rn); + assert(bi); + assert(bi->extra); + + { + char buf[BUFSIZ]; + prefix_rd2str(&bi->extra->vnc.import.rd, buf, BUFSIZ); + vnc_zlog_debug_verbose("%s: bi %p, peer %p, rd %s", __func__, + bi, bi->peer, buf); + } + + sl = RFAPI_RDINDEX_W_ALLOC(rn); + if (!sl) { + if (AF_ETHERNET == rn->p.family) { + sl = skiplist_new(0, rfapi_bi_peer_rd_aux_cmp, NULL); + } else { + sl = skiplist_new(0, rfapi_bi_peer_rd_cmp, NULL); + } + RFAPI_IT_EXTRA_GET(rn)->u.vpn.idx_rd = sl; + route_lock_node(rn); /* for skiplist */ + } + assert(!skiplist_insert(sl, (void *)bi, (void *)bi)); + route_lock_node(rn); /* for skiplist entry */ + + /* NB: BIs in import tables are not refcounted */ } -static void -rfapiItBiIndexDump (struct route_node *rn) +static void rfapiItBiIndexDump(struct route_node *rn) { - struct skiplist *sl; - void *cursor = NULL; - struct bgp_info *k; - struct bgp_info *v; - int rc; - - sl = RFAPI_RDINDEX (rn); - if (!sl) - return; - - for (rc = skiplist_next (sl, (void **) &k, (void **) &v, &cursor); - !rc; rc = skiplist_next (sl, (void **) &k, (void **) &v, &cursor)) - { - - char buf[BUFSIZ]; - char buf_aux_pfx[BUFSIZ]; - - prefix_rd2str (&k->extra->vnc.import.rd, buf, BUFSIZ); - buf_aux_pfx[0] = 0; - if (k->extra->vnc.import.aux_prefix.family) - { - prefix2str (&k->extra->vnc.import.aux_prefix, buf_aux_pfx, BUFSIZ); - } - else - { - strncpy (buf_aux_pfx, "(none)", BUFSIZ); - buf_aux_pfx[BUFSIZ - 1] = 0; - } - - vnc_zlog_debug_verbose ("bi %p, peer %p, rd %s, aux_prefix %s", k, k->peer, buf, - buf_aux_pfx); - } + struct skiplist *sl; + void *cursor = NULL; + struct bgp_info *k; + struct bgp_info *v; + int rc; + + sl = RFAPI_RDINDEX(rn); + if (!sl) + return; + + for (rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor); !rc; + rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor)) { + + char buf[BUFSIZ]; + char buf_aux_pfx[BUFSIZ]; + + prefix_rd2str(&k->extra->vnc.import.rd, buf, BUFSIZ); + buf_aux_pfx[0] = 0; + if (k->extra->vnc.import.aux_prefix.family) { + prefix2str(&k->extra->vnc.import.aux_prefix, + buf_aux_pfx, BUFSIZ); + } else { + strncpy(buf_aux_pfx, "(none)", BUFSIZ); + buf_aux_pfx[BUFSIZ - 1] = 0; + } + + vnc_zlog_debug_verbose("bi %p, peer %p, rd %s, aux_prefix %s", + k, k->peer, buf, buf_aux_pfx); + } } -static struct bgp_info * -rfapiItBiIndexSearch ( - struct route_node *rn, /* Import table VPN node */ - struct prefix_rd *prd, - struct peer *peer, - struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */ +static struct bgp_info *rfapiItBiIndexSearch( + struct route_node *rn, /* Import table VPN node */ + struct prefix_rd *prd, struct peer *peer, + struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */ { - struct skiplist *sl; - int rc; - struct bgp_info bi_fake; - struct bgp_info_extra bi_extra; - struct bgp_info *bi_result; + struct skiplist *sl; + int rc; + struct bgp_info bi_fake; + struct bgp_info_extra bi_extra; + struct bgp_info *bi_result; - sl = RFAPI_RDINDEX (rn); - if (!sl) - return NULL; + sl = RFAPI_RDINDEX(rn); + if (!sl) + return NULL; #if DEBUG_BI_SEARCH - { - char buf[BUFSIZ]; - char buf_aux_pfx[BUFSIZ]; - - prefix_rd2str (prd, buf, BUFSIZ); - if (aux_prefix) - { - prefix2str (aux_prefix, buf_aux_pfx, BUFSIZ); - } - else - { - strncpy (buf_aux_pfx, "(nil)", BUFSIZ - 1); - buf_aux_pfx[BUFSIZ - 1] = 0; - } - - vnc_zlog_debug_verbose ("%s want prd=%s, peer=%p, aux_prefix=%s", - __func__, buf, peer, buf_aux_pfx); - rfapiItBiIndexDump (rn); - } + { + char buf[BUFSIZ]; + char buf_aux_pfx[BUFSIZ]; + + prefix_rd2str(prd, buf, BUFSIZ); + if (aux_prefix) { + prefix2str(aux_prefix, buf_aux_pfx, BUFSIZ); + } else { + strncpy(buf_aux_pfx, "(nil)", BUFSIZ - 1); + buf_aux_pfx[BUFSIZ - 1] = 0; + } + + vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s", + __func__, buf, peer, buf_aux_pfx); + rfapiItBiIndexDump(rn); + } #endif - /* threshold is a WAG */ - if (sl->count < 3) - { + /* threshold is a WAG */ + if (sl->count < 3) { #if DEBUG_BI_SEARCH - vnc_zlog_debug_verbose ("%s: short list algorithm", __func__); + vnc_zlog_debug_verbose("%s: short list algorithm", __func__); #endif - /* if short list, linear search might be faster */ - for (bi_result = rn->info; bi_result; bi_result = bi_result->next) - { + /* if short list, linear search might be faster */ + for (bi_result = rn->info; bi_result; + bi_result = bi_result->next) { #if DEBUG_BI_SEARCH - { - char buf[BUFSIZ]; - prefix_rd2str (&bi_result->extra->vnc.import.rd, buf, BUFSIZ); - vnc_zlog_debug_verbose ("%s: bi has prd=%s, peer=%p", __func__, - buf, bi_result->peer); - } + { + char buf[BUFSIZ]; + prefix_rd2str(&bi_result->extra->vnc.import.rd, + buf, BUFSIZ); + vnc_zlog_debug_verbose( + "%s: bi has prd=%s, peer=%p", __func__, + buf, bi_result->peer); + } #endif - if (peer == bi_result->peer && - !prefix_cmp ((struct prefix *) &bi_result->extra->vnc.import.rd, - (struct prefix *) prd)) - { + if (peer == bi_result->peer + && !prefix_cmp((struct prefix *)&bi_result->extra + ->vnc.import.rd, + (struct prefix *)prd)) { #if DEBUG_BI_SEARCH - vnc_zlog_debug_verbose ("%s: peer and RD same, doing aux_prefix check", - __func__); + vnc_zlog_debug_verbose( + "%s: peer and RD same, doing aux_prefix check", + __func__); #endif - if (!aux_prefix || - !prefix_cmp (aux_prefix, - &bi_result->extra->vnc.import.aux_prefix)) - { + if (!aux_prefix + || !prefix_cmp(aux_prefix, + &bi_result->extra->vnc.import + .aux_prefix)) { #if DEBUG_BI_SEARCH - vnc_zlog_debug_verbose ("%s: match", __func__); + vnc_zlog_debug_verbose("%s: match", + __func__); #endif - break; - } - - } - } - return bi_result; - } - - bi_fake.peer = peer; - bi_fake.extra = &bi_extra; - bi_fake.extra->vnc.import.rd = *(struct prefix_rd *) prd; - if (aux_prefix) - { - bi_fake.extra->vnc.import.aux_prefix = *aux_prefix; - } - else - { - /* wildcard */ - bi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET; - bi_fake.extra->vnc.import.aux_prefix.prefixlen = 1; - } - - rc = skiplist_search (sl, (void *) &bi_fake, (void *) &bi_result); - - if (rc) - { + break; + } + } + } + return bi_result; + } + + bi_fake.peer = peer; + bi_fake.extra = &bi_extra; + bi_fake.extra->vnc.import.rd = *(struct prefix_rd *)prd; + if (aux_prefix) { + bi_fake.extra->vnc.import.aux_prefix = *aux_prefix; + } else { + /* wildcard */ + bi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET; + bi_fake.extra->vnc.import.aux_prefix.prefixlen = 1; + } + + rc = skiplist_search(sl, (void *)&bi_fake, (void *)&bi_result); + + if (rc) { #if DEBUG_BI_SEARCH - vnc_zlog_debug_verbose ("%s: no match", __func__); + vnc_zlog_debug_verbose("%s: no match", __func__); #endif - return NULL; - } + return NULL; + } #if DEBUG_BI_SEARCH - vnc_zlog_debug_verbose ("%s: matched bi=%p", __func__, bi_result); + vnc_zlog_debug_verbose("%s: matched bi=%p", __func__, bi_result); #endif - return bi_result; + return bi_result; } -static void -rfapiItBiIndexDel ( - struct route_node *rn, /* Import table VPN node */ - struct bgp_info *bi) /* old BI */ +static void rfapiItBiIndexDel(struct route_node *rn, /* Import table VPN node */ + struct bgp_info *bi) /* old BI */ { - struct skiplist *sl; - int rc; + struct skiplist *sl; + int rc; - { - char buf[BUFSIZ]; - prefix_rd2str (&bi->extra->vnc.import.rd, buf, BUFSIZ); - vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__, bi, bi->peer, buf); - } + { + char buf[BUFSIZ]; + prefix_rd2str(&bi->extra->vnc.import.rd, buf, BUFSIZ); + vnc_zlog_debug_verbose("%s: bi %p, peer %p, rd %s", __func__, + bi, bi->peer, buf); + } - sl = RFAPI_RDINDEX (rn); - assert (sl); + sl = RFAPI_RDINDEX(rn); + assert(sl); - rc = skiplist_delete (sl, (void *) (bi), (void *) bi); - if (rc) - { - rfapiItBiIndexDump (rn); - } - assert (!rc); + rc = skiplist_delete(sl, (void *)(bi), (void *)bi); + if (rc) { + rfapiItBiIndexDump(rn); + } + assert(!rc); - route_unlock_node (rn); /* for skiplist entry */ + route_unlock_node(rn); /* for skiplist entry */ - /* NB: BIs in import tables are not refcounted */ + /* NB: BIs in import tables are not refcounted */ } /* * Add a backreference at the ENCAP node to the VPN route that * refers to it */ -static void -rfapiMonitorEncapAdd ( - struct rfapi_import_table *import_table, - struct prefix *p, /* VN address */ - struct route_node *vpn_rn, /* VPN node */ - struct bgp_info *vpn_bi) /* VPN bi/route */ +static void rfapiMonitorEncapAdd(struct rfapi_import_table *import_table, + struct prefix *p, /* VN address */ + struct route_node *vpn_rn, /* VPN node */ + struct bgp_info *vpn_bi) /* VPN bi/route */ { - afi_t afi = family2afi (p->family); - struct route_node *rn; - struct rfapi_monitor_encap *m; - - assert (afi); - rn = route_node_get (import_table->imported_encap[afi], p); /* locks rn */ - assert (rn); - - m = - XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP, sizeof (struct rfapi_monitor_encap)); - assert (m); - - m->node = vpn_rn; - m->bi = vpn_bi; - m->rn = rn; - - /* insert to encap node's list */ - m->next = RFAPI_MONITOR_ENCAP (rn); - if (m->next) - m->next->prev = m; - RFAPI_MONITOR_ENCAP_W_ALLOC (rn) = m; - - /* for easy lookup when deleting vpn route */ - vpn_bi->extra->vnc.import.hme = m; - - vnc_zlog_debug_verbose - ("%s: it=%p, vpn_bi=%p, afi=%d, encap rn=%p, setting vpn_bi->extra->vnc.import.hme=%p", - __func__, import_table, vpn_bi, afi, rn, m); - - RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, 0); - bgp_attr_intern (vpn_bi->attr); + afi_t afi = family2afi(p->family); + struct route_node *rn; + struct rfapi_monitor_encap *m; + + assert(afi); + rn = route_node_get(import_table->imported_encap[afi], + p); /* locks rn */ + assert(rn); + + m = XCALLOC(MTYPE_RFAPI_MONITOR_ENCAP, + sizeof(struct rfapi_monitor_encap)); + assert(m); + + m->node = vpn_rn; + m->bi = vpn_bi; + m->rn = rn; + + /* insert to encap node's list */ + m->next = RFAPI_MONITOR_ENCAP(rn); + if (m->next) + m->next->prev = m; + RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m; + + /* for easy lookup when deleting vpn route */ + vpn_bi->extra->vnc.import.hme = m; + + vnc_zlog_debug_verbose( + "%s: it=%p, vpn_bi=%p, afi=%d, encap rn=%p, setting vpn_bi->extra->vnc.import.hme=%p", + __func__, import_table, vpn_bi, afi, rn, m); + + RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0); + bgp_attr_intern(vpn_bi->attr); } -static void -rfapiMonitorEncapDelete (struct bgp_info *vpn_bi) +static void rfapiMonitorEncapDelete(struct bgp_info *vpn_bi) { - /* - * Remove encap monitor - */ - vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__, vpn_bi); - if (vpn_bi->extra) - { - struct rfapi_monitor_encap *hme = vpn_bi->extra->vnc.import.hme; - - if (hme) - { - - vnc_zlog_debug_verbose ("%s: hme=%p", __func__, hme); - - /* Refcount checking takes too long here */ - //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0); - if (hme->next) - hme->next->prev = hme->prev; - if (hme->prev) - hme->prev->next = hme->next; - else - RFAPI_MONITOR_ENCAP_W_ALLOC (hme->rn) = hme->next; - /* Refcount checking takes too long here */ - //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1); - - /* see if the struct rfapi_it_extra is empty and can be freed */ - rfapiMonitorExtraPrune (SAFI_ENCAP, hme->rn); - - route_unlock_node (hme->rn); /* decr ref count */ - XFREE (MTYPE_RFAPI_MONITOR_ENCAP, hme); - vpn_bi->extra->vnc.import.hme = NULL; - } - } + /* + * Remove encap monitor + */ + vnc_zlog_debug_verbose("%s: vpn_bi=%p", __func__, vpn_bi); + if (vpn_bi->extra) { + struct rfapi_monitor_encap *hme = vpn_bi->extra->vnc.import.hme; + + if (hme) { + + vnc_zlog_debug_verbose("%s: hme=%p", __func__, hme); + + /* Refcount checking takes too long here */ + // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0); + if (hme->next) + hme->next->prev = hme->prev; + if (hme->prev) + hme->prev->next = hme->next; + else + RFAPI_MONITOR_ENCAP_W_ALLOC(hme->rn) = + hme->next; + /* Refcount checking takes too long here */ + // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1); + + /* see if the struct rfapi_it_extra is empty and can be + * freed */ + rfapiMonitorExtraPrune(SAFI_ENCAP, hme->rn); + + route_unlock_node(hme->rn); /* decr ref count */ + XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme); + vpn_bi->extra->vnc.import.hme = NULL; + } + } } /* * quagga lib/thread.h says this must return int even though * it doesn't do anything with the return value */ -static int -rfapiWithdrawTimerVPN (struct thread *t) +static int rfapiWithdrawTimerVPN(struct thread *t) { - struct rfapi_withdraw *wcb = t->arg; - struct bgp_info *bi = wcb->info; - struct bgp *bgp = bgp_get_default (); - - struct rfapi_monitor_vpn *moved; - afi_t afi; - - assert (wcb->node); - assert (bi); - assert (wcb->import_table); - assert (bi->extra); - - RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_MPLS_VPN, wcb->lockoffset); - - { - char buf[BUFSIZ]; - - vnc_zlog_debug_verbose ("%s: removing bi %p at prefix %s/%d", - __func__, - bi, - rfapi_ntop (wcb->node->p.family, &wcb->node->p.u.prefix, buf, - BUFSIZ), wcb->node->p.prefixlen); - } - - /* - * Remove the route (doubly-linked) - */ - if (CHECK_FLAG (bi->flags, BGP_INFO_VALID) - && VALID_INTERIOR_TYPE (bi->type)) - RFAPI_MONITOR_EXTERIOR (wcb->node)->valid_interior_count--; - - afi = family2afi (wcb->node->p.family); - wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */ - rfapiItBiIndexDel (wcb->node, bi); - rfapiBgpInfoDetach (wcb->node, bi); /* with removed bi */ - - vnc_import_bgp_exterior_del_route_interior (bgp, wcb->import_table, - wcb->node, bi); - - - /* - * If VNC is configured to send response remove messages, AND - * if the removed route had a UN address, do response removal - * processing. - */ - if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) - { - - int has_valid_duplicate = 0; - struct bgp_info *bii; - - /* - * First check if there are any OTHER routes at this node - * that have the same nexthop and a valid UN address. If - * there are (e.g., from other peers), then the route isn't - * really gone, so skip sending a response removal message. - */ - for (bii = wcb->node->info; bii; bii = bii->next) - { - if (rfapiVpnBiSamePtUn (bi, bii)) - { - has_valid_duplicate = 1; - break; - } - } - - vnc_zlog_debug_verbose ("%s: has_valid_duplicate=%d", __func__, - has_valid_duplicate); - - if (!has_valid_duplicate) - { - rfapiRibPendingDeleteRoute (bgp, wcb->import_table, afi, wcb->node); - } - } - - rfapiMonitorEncapDelete (bi); - - /* - * If there are no VPN monitors at this VPN Node A, - * we are done - */ - if (!RFAPI_MONITOR_VPN (wcb->node)) - { - vnc_zlog_debug_verbose ("%s: no VPN monitors at this node", __func__); - goto done; - } - - /* - * rfapiMonitorMoveShorter only moves monitors if there are - * no remaining valid routes at the current node - */ - moved = rfapiMonitorMoveShorter (wcb->node, 1); - - if (moved) - { - rfapiMonitorMovedUp (wcb->import_table, wcb->node, moved->node, moved); - } + struct rfapi_withdraw *wcb = t->arg; + struct bgp_info *bi = wcb->info; + struct bgp *bgp = bgp_get_default(); + + struct rfapi_monitor_vpn *moved; + afi_t afi; + + assert(wcb->node); + assert(bi); + assert(wcb->import_table); + assert(bi->extra); + + RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, wcb->lockoffset); + + { + char buf[BUFSIZ]; + + vnc_zlog_debug_verbose( + "%s: removing bi %p at prefix %s/%d", __func__, bi, + rfapi_ntop(wcb->node->p.family, &wcb->node->p.u.prefix, + buf, BUFSIZ), + wcb->node->p.prefixlen); + } + + /* + * Remove the route (doubly-linked) + */ + if (CHECK_FLAG(bi->flags, BGP_INFO_VALID) + && VALID_INTERIOR_TYPE(bi->type)) + RFAPI_MONITOR_EXTERIOR(wcb->node)->valid_interior_count--; + + afi = family2afi(wcb->node->p.family); + wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */ + rfapiItBiIndexDel(wcb->node, bi); + rfapiBgpInfoDetach(wcb->node, bi); /* with removed bi */ + + vnc_import_bgp_exterior_del_route_interior(bgp, wcb->import_table, + wcb->node, bi); + + + /* + * If VNC is configured to send response remove messages, AND + * if the removed route had a UN address, do response removal + * processing. + */ + if (!(bgp->rfapi_cfg->flags + & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) { + + int has_valid_duplicate = 0; + struct bgp_info *bii; + + /* + * First check if there are any OTHER routes at this node + * that have the same nexthop and a valid UN address. If + * there are (e.g., from other peers), then the route isn't + * really gone, so skip sending a response removal message. + */ + for (bii = wcb->node->info; bii; bii = bii->next) { + if (rfapiVpnBiSamePtUn(bi, bii)) { + has_valid_duplicate = 1; + break; + } + } + + vnc_zlog_debug_verbose("%s: has_valid_duplicate=%d", __func__, + has_valid_duplicate); + + if (!has_valid_duplicate) { + rfapiRibPendingDeleteRoute(bgp, wcb->import_table, afi, + wcb->node); + } + } + + rfapiMonitorEncapDelete(bi); + + /* + * If there are no VPN monitors at this VPN Node A, + * we are done + */ + if (!RFAPI_MONITOR_VPN(wcb->node)) { + vnc_zlog_debug_verbose("%s: no VPN monitors at this node", + __func__); + goto done; + } + + /* + * rfapiMonitorMoveShorter only moves monitors if there are + * no remaining valid routes at the current node + */ + moved = rfapiMonitorMoveShorter(wcb->node, 1); + + if (moved) { + rfapiMonitorMovedUp(wcb->import_table, wcb->node, moved->node, + moved); + } done: - /* - * Free VPN bi - */ - rfapiBgpInfoFree (bi); - wcb->info = NULL; - - /* - * If route count at this node has gone to 0, withdraw exported prefix - */ - if (!wcb->node->info) - { - /* see if the struct rfapi_it_extra is empty and can be freed */ - rfapiMonitorExtraPrune (SAFI_MPLS_VPN, wcb->node); - vnc_direct_bgp_del_prefix (bgp, wcb->import_table, wcb->node); - vnc_zebra_del_prefix (bgp, wcb->import_table, wcb->node); - } - else - { - /* - * nexthop change event - * vnc_direct_bgp_add_prefix() will recompute the VN addr ecommunity - */ - vnc_direct_bgp_add_prefix (bgp, wcb->import_table, wcb->node); - } - - RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset); - route_unlock_node (wcb->node); /* decr ref count */ - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - return 0; + /* + * Free VPN bi + */ + rfapiBgpInfoFree(bi); + wcb->info = NULL; + + /* + * If route count at this node has gone to 0, withdraw exported prefix + */ + if (!wcb->node->info) { + /* see if the struct rfapi_it_extra is empty and can be freed */ + rfapiMonitorExtraPrune(SAFI_MPLS_VPN, wcb->node); + vnc_direct_bgp_del_prefix(bgp, wcb->import_table, wcb->node); + vnc_zebra_del_prefix(bgp, wcb->import_table, wcb->node); + } else { + /* + * nexthop change event + * vnc_direct_bgp_add_prefix() will recompute the VN addr + * ecommunity + */ + vnc_direct_bgp_add_prefix(bgp, wcb->import_table, wcb->node); + } + + RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset); + route_unlock_node(wcb->node); /* decr ref count */ + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + return 0; } /* * This works for multiprotocol extension, but not for plain ol' * unicast IPv4 because that nexthop is stored in attr->nexthop */ -void -rfapiNexthop2Prefix (struct attr *attr, struct prefix *p) +void rfapiNexthop2Prefix(struct attr *attr, struct prefix *p) { - assert (p); - assert (attr); - - memset (p, 0, sizeof (struct prefix)); - - switch (p->family = BGP_MP_NEXTHOP_FAMILY (attr->mp_nexthop_len)) - { - case AF_INET: - p->u.prefix4 = attr->mp_nexthop_global_in; - p->prefixlen = 32; - break; - - case AF_INET6: - p->u.prefix6 = attr->mp_nexthop_global; - p->prefixlen = 128; - break; - - default: - vnc_zlog_debug_verbose ("%s: Family is unknown = %d", - __func__, p->family); - } + assert(p); + assert(attr); + + memset(p, 0, sizeof(struct prefix)); + + switch (p->family = BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) { + case AF_INET: + p->u.prefix4 = attr->mp_nexthop_global_in; + p->prefixlen = 32; + break; + + case AF_INET6: + p->u.prefix6 = attr->mp_nexthop_global; + p->prefixlen = 128; + break; + + default: + vnc_zlog_debug_verbose("%s: Family is unknown = %d", __func__, + p->family); + } } -void -rfapiUnicastNexthop2Prefix (afi_t afi, struct attr *attr, struct prefix *p) +void rfapiUnicastNexthop2Prefix(afi_t afi, struct attr *attr, struct prefix *p) { - if (afi == AFI_IP) - { - p->family = AF_INET; - p->prefixlen = 32; - p->u.prefix4 = attr->nexthop; - } - else - { - rfapiNexthop2Prefix (attr, p); - } + if (afi == AFI_IP) { + p->family = AF_INET; + p->prefixlen = 32; + p->u.prefix4 = attr->nexthop; + } else { + rfapiNexthop2Prefix(attr, p); + } } -static int -rfapiAttrNexthopAddrDifferent (struct prefix *p1, struct prefix *p2) +static int rfapiAttrNexthopAddrDifferent(struct prefix *p1, struct prefix *p2) { - if (!p1 || !p2) - { - vnc_zlog_debug_verbose ("%s: p1 or p2 is NULL", __func__); - return 1; - } - - /* - * Are address families the same? - */ - if (p1->family != p2->family) - { - return 1; - } - - switch (p1->family) - { - case AF_INET: - if (IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4)) - return 0; - break; - - case AF_INET6: - if (IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6)) - return 0; - break; - - default: - assert (1); - - } - - return 1; + if (!p1 || !p2) { + vnc_zlog_debug_verbose("%s: p1 or p2 is NULL", __func__); + return 1; + } + + /* + * Are address families the same? + */ + if (p1->family != p2->family) { + return 1; + } + + switch (p1->family) { + case AF_INET: + if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4)) + return 0; + break; + + case AF_INET6: + if (IPV6_ADDR_SAME(&p1->u.prefix6, &p2->u.prefix6)) + return 0; + break; + + default: + assert(1); + } + + return 1; } -static void -rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi) +static void rfapiCopyUnEncap2VPN(struct bgp_info *encap_bi, + struct bgp_info *vpn_bi) { - if (!encap_bi->attr) - { - zlog_warn ("%s: no encap bi attr/extra, can't copy UN address", - __func__); - return; - } - - if (!vpn_bi || !vpn_bi->extra) - { - zlog_warn ("%s: no vpn bi attr/extra, can't copy UN address", - __func__); - return; - } - - switch (BGP_MP_NEXTHOP_FAMILY (encap_bi->attr->mp_nexthop_len)) - { - case AF_INET: - - /* - * instrumentation to debug segfault of 091127 - */ - vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__, vpn_bi); - if (vpn_bi) - { - vnc_zlog_debug_verbose ("%s: vpn_bi->extra=%p", __func__, vpn_bi->extra); - } - - vpn_bi->extra->vnc.import.un_family = AF_INET; - vpn_bi->extra->vnc.import.un.addr4 = encap_bi->attr->mp_nexthop_global_in; - break; - - case AF_INET6: - vpn_bi->extra->vnc.import.un_family = AF_INET6; - vpn_bi->extra->vnc.import.un.addr6 = encap_bi->attr->mp_nexthop_global; - break; - - default: - zlog_warn ("%s: invalid encap nexthop length: %d", - __func__, encap_bi->attr->mp_nexthop_len); - vpn_bi->extra->vnc.import.un_family = 0; - break; - } + if (!encap_bi->attr) { + zlog_warn("%s: no encap bi attr/extra, can't copy UN address", + __func__); + return; + } + + if (!vpn_bi || !vpn_bi->extra) { + zlog_warn("%s: no vpn bi attr/extra, can't copy UN address", + __func__); + return; + } + + switch (BGP_MP_NEXTHOP_FAMILY(encap_bi->attr->mp_nexthop_len)) { + case AF_INET: + + /* + * instrumentation to debug segfault of 091127 + */ + vnc_zlog_debug_verbose("%s: vpn_bi=%p", __func__, vpn_bi); + if (vpn_bi) { + vnc_zlog_debug_verbose("%s: vpn_bi->extra=%p", __func__, + vpn_bi->extra); + } + + vpn_bi->extra->vnc.import.un_family = AF_INET; + vpn_bi->extra->vnc.import.un.addr4 = + encap_bi->attr->mp_nexthop_global_in; + break; + + case AF_INET6: + vpn_bi->extra->vnc.import.un_family = AF_INET6; + vpn_bi->extra->vnc.import.un.addr6 = + encap_bi->attr->mp_nexthop_global; + break; + + default: + zlog_warn("%s: invalid encap nexthop length: %d", __func__, + encap_bi->attr->mp_nexthop_len); + vpn_bi->extra->vnc.import.un_family = 0; + break; + } } /* * returns 0 on success, nonzero on error */ -static int -rfapiWithdrawEncapUpdateCachedUn ( - struct rfapi_import_table *import_table, - struct bgp_info *encap_bi, - struct route_node *vpn_rn, - struct bgp_info *vpn_bi) +static int rfapiWithdrawEncapUpdateCachedUn( + struct rfapi_import_table *import_table, struct bgp_info *encap_bi, + struct route_node *vpn_rn, struct bgp_info *vpn_bi) { - if (!encap_bi) - { - - /* - * clear cached UN address - */ - if (!vpn_bi || !vpn_bi->extra) - { - zlog_warn ("%s: missing VPN bi/extra, can't clear UN addr", - __func__); - return 1; - } - vpn_bi->extra->vnc.import.un_family = 0; - memset (&vpn_bi->extra->vnc.import.un, 0, - sizeof (vpn_bi->extra->vnc.import.un)); - if (CHECK_FLAG (vpn_bi->flags, BGP_INFO_VALID)) - { - if (rfapiGetVncTunnelUnAddr (vpn_bi->attr, NULL)) - { - UNSET_FLAG (vpn_bi->flags, BGP_INFO_VALID); - if (VALID_INTERIOR_TYPE (vpn_bi->type)) - RFAPI_MONITOR_EXTERIOR (vpn_rn)->valid_interior_count--; - /* signal interior route withdrawal to import-exterior */ - vnc_import_bgp_exterior_del_route_interior (bgp_get_default (), - import_table, - vpn_rn, vpn_bi); - } - } - - } - else - { - if (!vpn_bi) - { - zlog_warn ("%s: missing VPN bi, can't clear UN addr", __func__); - return 1; - } - rfapiCopyUnEncap2VPN (encap_bi, vpn_bi); - if (!CHECK_FLAG (vpn_bi->flags, BGP_INFO_VALID)) - { - SET_FLAG (vpn_bi->flags, BGP_INFO_VALID); - if (VALID_INTERIOR_TYPE (vpn_bi->type)) - RFAPI_MONITOR_EXTERIOR (vpn_rn)->valid_interior_count++; - /* signal interior route withdrawal to import-exterior */ - vnc_import_bgp_exterior_add_route_interior (bgp_get_default (), - import_table, - vpn_rn, vpn_bi); - } - } - return 0; + if (!encap_bi) { + + /* + * clear cached UN address + */ + if (!vpn_bi || !vpn_bi->extra) { + zlog_warn( + "%s: missing VPN bi/extra, can't clear UN addr", + __func__); + return 1; + } + vpn_bi->extra->vnc.import.un_family = 0; + memset(&vpn_bi->extra->vnc.import.un, 0, + sizeof(vpn_bi->extra->vnc.import.un)); + if (CHECK_FLAG(vpn_bi->flags, BGP_INFO_VALID)) { + if (rfapiGetVncTunnelUnAddr(vpn_bi->attr, NULL)) { + UNSET_FLAG(vpn_bi->flags, BGP_INFO_VALID); + if (VALID_INTERIOR_TYPE(vpn_bi->type)) + RFAPI_MONITOR_EXTERIOR(vpn_rn) + ->valid_interior_count--; + /* signal interior route withdrawal to + * import-exterior */ + vnc_import_bgp_exterior_del_route_interior( + bgp_get_default(), import_table, vpn_rn, + vpn_bi); + } + } + + } else { + if (!vpn_bi) { + zlog_warn("%s: missing VPN bi, can't clear UN addr", + __func__); + return 1; + } + rfapiCopyUnEncap2VPN(encap_bi, vpn_bi); + if (!CHECK_FLAG(vpn_bi->flags, BGP_INFO_VALID)) { + SET_FLAG(vpn_bi->flags, BGP_INFO_VALID); + if (VALID_INTERIOR_TYPE(vpn_bi->type)) + RFAPI_MONITOR_EXTERIOR(vpn_rn) + ->valid_interior_count++; + /* signal interior route withdrawal to import-exterior + */ + vnc_import_bgp_exterior_add_route_interior( + bgp_get_default(), import_table, vpn_rn, + vpn_bi); + } + } + return 0; } -static int -rfapiWithdrawTimerEncap (struct thread *t) +static int rfapiWithdrawTimerEncap(struct thread *t) { - struct rfapi_withdraw *wcb = t->arg; - struct bgp_info *bi = wcb->info; - int was_first_route = 0; - struct rfapi_monitor_encap *em; - struct skiplist *vpn_node_sl = skiplist_new (0, NULL, NULL); - - assert (wcb->node); - assert (bi); - assert (wcb->import_table); - - RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_ENCAP, 0); - - if (wcb->node->info == bi) - was_first_route = 1; - - /* - * Remove the route/bi and free it - */ - rfapiBgpInfoDetach (wcb->node, bi); - rfapiBgpInfoFree (bi); - - if (!was_first_route) - goto done; - - for (em = RFAPI_MONITOR_ENCAP (wcb->node); em; em = em->next) - { - - /* - * Update monitoring VPN BIs with new encap info at the - * head of the encap bi chain (which could be NULL after - * removing the expiring bi above) - */ - if (rfapiWithdrawEncapUpdateCachedUn - (wcb->import_table, wcb->node->info, em->node, em->bi)) - continue; - - /* - * Build a list of unique VPN nodes referenced by these monitors. - * Use a skiplist for speed. - */ - skiplist_insert (vpn_node_sl, em->node, em->node); - } - - - /* - * for each VPN node referenced in the ENCAP monitors: - */ - struct route_node *rn; - while (!skiplist_first (vpn_node_sl, (void **) &rn, NULL)) - { - if (!wcb->node->info) - { - struct rfapi_monitor_vpn *moved; - - moved = rfapiMonitorMoveShorter (rn, 0); - if (moved) - { - //rfapiDoRouteCallback(wcb->import_table, moved->node, moved); - rfapiMonitorMovedUp (wcb->import_table, rn, moved->node, moved); - } - } - else - { - //rfapiDoRouteCallback(wcb->import_table, rn, NULL); - rfapiMonitorItNodeChanged (wcb->import_table, rn, NULL); - } - skiplist_delete_first (vpn_node_sl); - } + struct rfapi_withdraw *wcb = t->arg; + struct bgp_info *bi = wcb->info; + int was_first_route = 0; + struct rfapi_monitor_encap *em; + struct skiplist *vpn_node_sl = skiplist_new(0, NULL, NULL); + + assert(wcb->node); + assert(bi); + assert(wcb->import_table); + + RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 0); + + if (wcb->node->info == bi) + was_first_route = 1; + + /* + * Remove the route/bi and free it + */ + rfapiBgpInfoDetach(wcb->node, bi); + rfapiBgpInfoFree(bi); + + if (!was_first_route) + goto done; + + for (em = RFAPI_MONITOR_ENCAP(wcb->node); em; em = em->next) { + + /* + * Update monitoring VPN BIs with new encap info at the + * head of the encap bi chain (which could be NULL after + * removing the expiring bi above) + */ + if (rfapiWithdrawEncapUpdateCachedUn(wcb->import_table, + wcb->node->info, em->node, + em->bi)) + continue; + + /* + * Build a list of unique VPN nodes referenced by these + * monitors. + * Use a skiplist for speed. + */ + skiplist_insert(vpn_node_sl, em->node, em->node); + } + + + /* + * for each VPN node referenced in the ENCAP monitors: + */ + struct route_node *rn; + while (!skiplist_first(vpn_node_sl, (void **)&rn, NULL)) { + if (!wcb->node->info) { + struct rfapi_monitor_vpn *moved; + + moved = rfapiMonitorMoveShorter(rn, 0); + if (moved) { + // rfapiDoRouteCallback(wcb->import_table, + // moved->node, moved); + rfapiMonitorMovedUp(wcb->import_table, rn, + moved->node, moved); + } + } else { + // rfapiDoRouteCallback(wcb->import_table, rn, NULL); + rfapiMonitorItNodeChanged(wcb->import_table, rn, NULL); + } + skiplist_delete_first(vpn_node_sl); + } done: - RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_ENCAP, 1); - route_unlock_node (wcb->node); /* decr ref count */ - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - skiplist_free (vpn_node_sl); - return 0; + RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 1); + route_unlock_node(wcb->node); /* decr ref count */ + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + skiplist_free(vpn_node_sl); + return 0; } @@ -2965,1391 +2793,1272 @@ done: * in each case */ static void -rfapiBiStartWithdrawTimer ( - struct rfapi_import_table *import_table, - struct route_node *rn, - struct bgp_info *bi, - afi_t afi, - safi_t safi, - int (*timer_service_func) (struct thread *)) +rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, + struct route_node *rn, struct bgp_info *bi, afi_t afi, + safi_t safi, + int (*timer_service_func)(struct thread *)) { - uint32_t lifetime; - struct rfapi_withdraw *wcb; - - if CHECK_FLAG - (bi->flags, BGP_INFO_REMOVED) - { - /* - * Already on the path to being withdrawn, - * should already have a timer set up to - * delete it. - */ - vnc_zlog_debug_verbose ("%s: already being withdrawn, do nothing", __func__); - return; - } - - rfapiGetVncLifetime (bi->attr, &lifetime); - vnc_zlog_debug_verbose ("%s: VNC lifetime is %u", __func__, lifetime); - - /* - * withdrawn routes get to hang around for a while - */ - SET_FLAG (bi->flags, BGP_INFO_REMOVED); - - /* set timer to remove the route later */ - lifetime = rfapiGetHolddownFromLifetime (lifetime); - vnc_zlog_debug_verbose ("%s: using timeout %u", __func__, lifetime); - - /* - * Stash import_table, node, and info for use by timer - * service routine, which is supposed to free the wcb. - */ - wcb = XCALLOC (MTYPE_RFAPI_WITHDRAW, sizeof (struct rfapi_withdraw)); - assert (wcb); - wcb->node = rn; - wcb->info = bi; - wcb->import_table = import_table; - bgp_attr_intern (bi->attr); - - if (VNC_DEBUG(VERBOSE)) - { - vnc_zlog_debug_verbose - ("%s: wcb values: node=%p, info=%p, import_table=%p (bi follows)", - __func__, wcb->node, wcb->info, wcb->import_table); - rfapiPrintBi (NULL, bi); - } - - - assert (bi->extra); - if (lifetime > UINT32_MAX / 1001) - { - /* sub-optimal case, but will probably never happen */ - bi->extra->vnc.import.timer = NULL; - thread_add_timer(bm->master, timer_service_func, wcb, lifetime, - &bi->extra->vnc.import.timer); - } - else - { - static uint32_t jitter; - uint32_t lifetime_msec; - - /* - * the goal here is to spread out the timers so they are - * sortable in the skip list - */ - if (++jitter >= 1000) - jitter = 0; - - lifetime_msec = (lifetime * 1000) + jitter; - - bi->extra->vnc.import.timer = NULL; - thread_add_timer_msec(bm->master, timer_service_func, wcb, lifetime_msec, - &bi->extra->vnc.import.timer); - } - - /* re-sort route list (BGP_INFO_REMOVED routes are last) */ - if (((struct bgp_info *) rn->info)->next) - { - rfapiBgpInfoDetach (rn, bi); - rfapiBgpInfoAttachSorted (rn, bi, afi, safi); - } + uint32_t lifetime; + struct rfapi_withdraw *wcb; + + if + CHECK_FLAG(bi->flags, BGP_INFO_REMOVED) + { + /* + * Already on the path to being withdrawn, + * should already have a timer set up to + * delete it. + */ + vnc_zlog_debug_verbose( + "%s: already being withdrawn, do nothing", + __func__); + return; + } + + rfapiGetVncLifetime(bi->attr, &lifetime); + vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__, lifetime); + + /* + * withdrawn routes get to hang around for a while + */ + SET_FLAG(bi->flags, BGP_INFO_REMOVED); + + /* set timer to remove the route later */ + lifetime = rfapiGetHolddownFromLifetime(lifetime); + vnc_zlog_debug_verbose("%s: using timeout %u", __func__, lifetime); + + /* + * Stash import_table, node, and info for use by timer + * service routine, which is supposed to free the wcb. + */ + wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw)); + assert(wcb); + wcb->node = rn; + wcb->info = bi; + wcb->import_table = import_table; + bgp_attr_intern(bi->attr); + + if (VNC_DEBUG(VERBOSE)) { + vnc_zlog_debug_verbose( + "%s: wcb values: node=%p, info=%p, import_table=%p (bi follows)", + __func__, wcb->node, wcb->info, wcb->import_table); + rfapiPrintBi(NULL, bi); + } + + + assert(bi->extra); + if (lifetime > UINT32_MAX / 1001) { + /* sub-optimal case, but will probably never happen */ + bi->extra->vnc.import.timer = NULL; + thread_add_timer(bm->master, timer_service_func, wcb, lifetime, + &bi->extra->vnc.import.timer); + } else { + static uint32_t jitter; + uint32_t lifetime_msec; + + /* + * the goal here is to spread out the timers so they are + * sortable in the skip list + */ + if (++jitter >= 1000) + jitter = 0; + + lifetime_msec = (lifetime * 1000) + jitter; + + bi->extra->vnc.import.timer = NULL; + thread_add_timer_msec(bm->master, timer_service_func, wcb, + lifetime_msec, + &bi->extra->vnc.import.timer); + } + + /* re-sort route list (BGP_INFO_REMOVED routes are last) */ + if (((struct bgp_info *)rn->info)->next) { + rfapiBgpInfoDetach(rn, bi); + rfapiBgpInfoAttachSorted(rn, bi, afi, safi); + } } -typedef void (rfapi_bi_filtered_import_f) (struct rfapi_import_table *, - int, - struct peer *, - void *, - struct prefix *, - struct prefix *, - afi_t, - struct prefix_rd *, - struct attr *, - u_char, u_char, uint32_t *); +typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *, int, + struct peer *, void *, struct prefix *, + struct prefix *, afi_t, + struct prefix_rd *, struct attr *, + u_char, u_char, uint32_t *); -static void -rfapiExpireEncapNow ( - struct rfapi_import_table *it, - struct route_node *rn, - struct bgp_info *bi) +static void rfapiExpireEncapNow(struct rfapi_import_table *it, + struct route_node *rn, struct bgp_info *bi) { - struct rfapi_withdraw *wcb; - struct thread t; - - /* - * pretend we're an expiring timer - */ - wcb = XCALLOC (MTYPE_RFAPI_WITHDRAW, sizeof (struct rfapi_withdraw)); - wcb->info = bi; - wcb->node = rn; - wcb->import_table = it; - memset (&t, 0, sizeof (t)); - t.arg = wcb; - rfapiWithdrawTimerEncap (&t); /* frees wcb */ + struct rfapi_withdraw *wcb; + struct thread t; + + /* + * pretend we're an expiring timer + */ + wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw)); + wcb->info = bi; + wcb->node = rn; + wcb->import_table = it; + memset(&t, 0, sizeof(t)); + t.arg = wcb; + rfapiWithdrawTimerEncap(&t); /* frees wcb */ } -static int -rfapiGetNexthop (struct attr *attr, struct prefix *prefix) +static int rfapiGetNexthop(struct attr *attr, struct prefix *prefix) { - switch (BGP_MP_NEXTHOP_FAMILY (attr->mp_nexthop_len)) - { - case AF_INET: - prefix->family = AF_INET; - prefix->prefixlen = 32; - prefix->u.prefix4 = attr->mp_nexthop_global_in; - break; - case AF_INET6: - prefix->family = AF_INET6; - prefix->prefixlen = 128; - prefix->u.prefix6 = attr->mp_nexthop_global; - break; - default: - vnc_zlog_debug_verbose ("%s: unknown attr->mp_nexthop_len %d", __func__, - attr->mp_nexthop_len); - return EINVAL; - } - return 0; + switch (BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) { + case AF_INET: + prefix->family = AF_INET; + prefix->prefixlen = 32; + prefix->u.prefix4 = attr->mp_nexthop_global_in; + break; + case AF_INET6: + prefix->family = AF_INET6; + prefix->prefixlen = 128; + prefix->u.prefix6 = attr->mp_nexthop_global; + break; + default: + vnc_zlog_debug_verbose("%s: unknown attr->mp_nexthop_len %d", + __func__, attr->mp_nexthop_len); + return EINVAL; + } + return 0; } -/* +/* * import a bgp_info if its route target list intersects with the * import table's route target list */ -static void -rfapiBgpInfoFilteredImportEncap ( - struct rfapi_import_table *import_table, - int action, - struct peer *peer, - void *rfd, /* set for looped back routes */ - struct prefix *p, - struct prefix *aux_prefix, /* Unused for encap routes */ - afi_t afi, - struct prefix_rd *prd, - struct attr *attr, /* part of bgp_info */ - u_char type, /* part of bgp_info */ - u_char sub_type, /* part of bgp_info */ - uint32_t *label) /* part of bgp_info */ +static void rfapiBgpInfoFilteredImportEncap( + struct rfapi_import_table *import_table, int action, struct peer *peer, + void *rfd, /* set for looped back routes */ + struct prefix *p, + struct prefix *aux_prefix, /* Unused for encap routes */ + afi_t afi, struct prefix_rd *prd, + struct attr *attr, /* part of bgp_info */ + u_char type, /* part of bgp_info */ + u_char sub_type, /* part of bgp_info */ + uint32_t *label) /* part of bgp_info */ { - struct route_table *rt = NULL; - struct route_node *rn; - struct bgp_info *info_new; - struct bgp_info *bi; - struct bgp_info *next; - char buf[BUFSIZ]; - - struct prefix p_firstbi_old; - struct prefix p_firstbi_new; - int replacing = 0; - const char *action_str = NULL; - struct prefix un_prefix; - - struct bgp *bgp; - bgp = bgp_get_default (); /* assume 1 instance for now */ - - switch (action) - { - case FIF_ACTION_UPDATE: - action_str = "update"; - break; - case FIF_ACTION_WITHDRAW: - action_str = "withdraw"; - break; - case FIF_ACTION_KILL: - action_str = "kill"; - break; - default: - assert (0); - break; - } - - vnc_zlog_debug_verbose ("%s: entry: %s: prefix %s/%d", __func__, - action_str, - inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); - - memset (&p_firstbi_old, 0, sizeof (p_firstbi_old)); - memset (&p_firstbi_new, 0, sizeof (p_firstbi_new)); - - if (action == FIF_ACTION_UPDATE) - { - /* - * Compare rt lists. If no intersection, don't import this route - * On a withdraw, peer and RD are sufficient to determine if - * we should act. - */ - if (!attr || !attr->ecommunity) - { - - vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing", - __func__); - return; - } + struct route_table *rt = NULL; + struct route_node *rn; + struct bgp_info *info_new; + struct bgp_info *bi; + struct bgp_info *next; + char buf[BUFSIZ]; + + struct prefix p_firstbi_old; + struct prefix p_firstbi_new; + int replacing = 0; + const char *action_str = NULL; + struct prefix un_prefix; + + struct bgp *bgp; + bgp = bgp_get_default(); /* assume 1 instance for now */ + + switch (action) { + case FIF_ACTION_UPDATE: + action_str = "update"; + break; + case FIF_ACTION_WITHDRAW: + action_str = "withdraw"; + break; + case FIF_ACTION_KILL: + action_str = "kill"; + break; + default: + assert(0); + break; + } + + vnc_zlog_debug_verbose( + "%s: entry: %s: prefix %s/%d", __func__, action_str, + inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); + + memset(&p_firstbi_old, 0, sizeof(p_firstbi_old)); + memset(&p_firstbi_new, 0, sizeof(p_firstbi_new)); + + if (action == FIF_ACTION_UPDATE) { + /* + * Compare rt lists. If no intersection, don't import this route + * On a withdraw, peer and RD are sufficient to determine if + * we should act. + */ + if (!attr || !attr->ecommunity) { + + vnc_zlog_debug_verbose( + "%s: attr, extra, or ecommunity missing, not importing", + __func__); + return; + } #if RFAPI_REQUIRE_ENCAP_BEEC - if (!rfapiEcommunitiesMatchBeec (attr->ecommunity)) - { - vnc_zlog_debug_verbose ("%s: it=%p: no match for BGP Encapsulation ecommunity", - __func__, import_table); - return; - } + if (!rfapiEcommunitiesMatchBeec(attr->ecommunity)) { + vnc_zlog_debug_verbose( + "%s: it=%p: no match for BGP Encapsulation ecommunity", + __func__, import_table); + return; + } #endif - if (!rfapiEcommunitiesIntersect (import_table->rt_import_list, - attr->ecommunity)) - { - - vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection", - __func__, import_table); - return; - } - - /* - * Updates must also have a nexthop address - */ - memset (&un_prefix, 0, sizeof (un_prefix)); /* keep valgrind happy */ - if (rfapiGetNexthop (attr, &un_prefix)) - { - vnc_zlog_debug_verbose ("%s: missing nexthop address", __func__); - return; - } - } - - /* - * Figure out which radix tree the route would go into - */ - switch (afi) - { - case AFI_IP: - case AFI_IP6: - rt = import_table->imported_encap[afi]; - break; - - default: - zlog_err ("%s: bad afi %d", __func__, afi); - return; - } - - /* - * route_node_lookup returns a node only if there is at least - * one route attached. - */ - rn = route_node_lookup (rt, p); + if (!rfapiEcommunitiesIntersect(import_table->rt_import_list, + attr->ecommunity)) { + + vnc_zlog_debug_verbose( + "%s: it=%p: no ecommunity intersection", + __func__, import_table); + return; + } + + /* + * Updates must also have a nexthop address + */ + memset(&un_prefix, 0, + sizeof(un_prefix)); /* keep valgrind happy */ + if (rfapiGetNexthop(attr, &un_prefix)) { + vnc_zlog_debug_verbose("%s: missing nexthop address", + __func__); + return; + } + } + + /* + * Figure out which radix tree the route would go into + */ + switch (afi) { + case AFI_IP: + case AFI_IP6: + rt = import_table->imported_encap[afi]; + break; + + default: + zlog_err("%s: bad afi %d", __func__, afi); + return; + } + + /* + * route_node_lookup returns a node only if there is at least + * one route attached. + */ + rn = route_node_lookup(rt, p); #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: initial encap lookup(it=%p) rn=%p", - __func__, import_table, rn); + vnc_zlog_debug_verbose("%s: initial encap lookup(it=%p) rn=%p", + __func__, import_table, rn); #endif - if (rn) - { - - RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, 1); - route_unlock_node (rn); /* undo lock in route_node_lookup */ - - - /* - * capture nexthop of first bi - */ - if (rn->info) - { - rfapiNexthop2Prefix (((struct bgp_info *) (rn->info))->attr, - &p_firstbi_old); - } - - for (bi = rn->info; bi; bi = bi->next) - { - - /* - * Does this bgp_info refer to the same route - * as we are trying to add? - */ - vnc_zlog_debug_verbose ("%s: comparing BI %p", __func__, bi); - - - /* - * Compare RDs - * - * RD of import table bi is in bi->extra->vnc.import.rd - * RD of info_orig is in prd - */ - if (!bi->extra) - { - vnc_zlog_debug_verbose ("%s: no bi->extra", __func__); - continue; - } - if (prefix_cmp ((struct prefix *) &bi->extra->vnc.import.rd, - (struct prefix *) prd)) - { - - vnc_zlog_debug_verbose ("%s: prd does not match", __func__); - continue; - } - - /* - * Compare peers - */ - if (bi->peer != peer) - { - vnc_zlog_debug_verbose ("%s: peer does not match", __func__); - continue; - } - - vnc_zlog_debug_verbose ("%s: found matching bi", __func__); - - /* Same route. Delete this bi, replace with new one */ - - if (action == FIF_ACTION_WITHDRAW) - { - - vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d", - __func__, - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, - BUFSIZ), rn->p.prefixlen); - - rfapiBiStartWithdrawTimer (import_table, rn, bi, - afi, SAFI_ENCAP, - rfapiWithdrawTimerEncap); - - } - else - { - vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d", - __func__, - ((action == - FIF_ACTION_KILL) ? "killing" : "replacing"), - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, - BUFSIZ), rn->p.prefixlen); - - /* - * If this route is waiting to be deleted because of - * a previous withdraw, we must cancel its timer. - */ - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) - && bi->extra->vnc.import.timer) - { - - struct thread *t = - (struct thread *) bi->extra->vnc.import.timer; - struct rfapi_withdraw *wcb = t->arg; - - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - thread_cancel (t); - } - - if (action == FIF_ACTION_UPDATE) - { - rfapiBgpInfoDetach (rn, bi); - rfapiBgpInfoFree (bi); - replacing = 1; - } - else - { - /* - * Kill: do export stuff when removing bi - */ - struct rfapi_withdraw *wcb; - struct thread t; - - /* - * pretend we're an expiring timer - */ - wcb = - XCALLOC (MTYPE_RFAPI_WITHDRAW, - sizeof (struct rfapi_withdraw)); - wcb->info = bi; - wcb->node = rn; - wcb->import_table = import_table; - memset (&t, 0, sizeof (t)); - t.arg = wcb; - rfapiWithdrawTimerEncap (&t); /* frees wcb */ - } - } - - break; - } - } - - if (rn) - RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, replacing ? 1 : 0); - - if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) - return; - - info_new = rfapiBgpInfoCreate (attr, peer, rfd, prd, type, sub_type, NULL); - - if (rn) - { - if (!replacing) - route_lock_node (rn); /* incr ref count for new BI */ - } - else - { - rn = route_node_get (rt, p); - } - - vnc_zlog_debug_verbose ("%s: (afi=%d, rn=%p) inserting at prefix %s/%d", - __func__, - afi, - rn, - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), - rn->p.prefixlen); - - rfapiBgpInfoAttachSorted (rn, info_new, afi, SAFI_ENCAP); - - /* - * Delete holddown routes from same NVE. See details in - * rfapiBgpInfoFilteredImportVPN() - */ - for (bi = info_new->next; bi; bi = next) - { - - struct prefix pfx_un; - int un_match = 0; - - next = bi->next; - if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - continue; - - /* - * We already match the VN address (it is the prefix - * of the route node) - */ - - if (!rfapiGetNexthop (bi->attr, &pfx_un) && - prefix_same (&pfx_un, &un_prefix)) - { - - un_match = 1; - } - - if (!un_match) - continue; - - vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route", - __func__); - if (bi->extra->vnc.import.timer) - { - struct thread *t = (struct thread *) bi->extra->vnc.import.timer; - struct rfapi_withdraw *wcb = t->arg; - - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - thread_cancel (t); - } - rfapiExpireEncapNow (import_table, rn, bi); - } - - rfapiNexthop2Prefix (((struct bgp_info *) (rn->info))->attr, - &p_firstbi_new); - - /* - * If the nexthop address of the selected Encap route (i.e., - * the UN address) has changed, then we must update the VPN - * routes that refer to this Encap route and possibly force - * rfapi callbacks. - */ - if (rfapiAttrNexthopAddrDifferent (&p_firstbi_old, &p_firstbi_new)) - { - - struct rfapi_monitor_encap *m; - struct rfapi_monitor_encap *mnext; - - struct route_node *referenced_vpn_prefix; - - /* - * Optimized approach: build radix tree on the fly to - * hold list of VPN nodes referenced by the ENCAP monitors - * - * The nodes in this table correspond to prefixes of VPN routes. - * The "info" pointer of the node points to a chain of - * struct rfapi_monitor_encap, each of which refers to a - * specific VPN node. - */ - struct route_table *referenced_vpn_table; - - referenced_vpn_table = route_table_init (); - assert (referenced_vpn_table); - - /* - * iterate over the set of monitors at this ENCAP node. - */ + if (rn) { + + RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 1); + route_unlock_node(rn); /* undo lock in route_node_lookup */ + + + /* + * capture nexthop of first bi + */ + if (rn->info) { + rfapiNexthop2Prefix( + ((struct bgp_info *)(rn->info))->attr, + &p_firstbi_old); + } + + for (bi = rn->info; bi; bi = bi->next) { + + /* + * Does this bgp_info refer to the same route + * as we are trying to add? + */ + vnc_zlog_debug_verbose("%s: comparing BI %p", __func__, + bi); + + + /* + * Compare RDs + * + * RD of import table bi is in bi->extra->vnc.import.rd + * RD of info_orig is in prd + */ + if (!bi->extra) { + vnc_zlog_debug_verbose("%s: no bi->extra", + __func__); + continue; + } + if (prefix_cmp( + (struct prefix *)&bi->extra->vnc.import.rd, + (struct prefix *)prd)) { + + vnc_zlog_debug_verbose("%s: prd does not match", + __func__); + continue; + } + + /* + * Compare peers + */ + if (bi->peer != peer) { + vnc_zlog_debug_verbose( + "%s: peer does not match", __func__); + continue; + } + + vnc_zlog_debug_verbose("%s: found matching bi", + __func__); + + /* Same route. Delete this bi, replace with new one */ + + if (action == FIF_ACTION_WITHDRAW) { + + vnc_zlog_debug_verbose( + "%s: withdrawing at prefix %s/%d", + __func__, + inet_ntop(rn->p.family, &rn->p.u.prefix, + buf, BUFSIZ), + rn->p.prefixlen); + + rfapiBiStartWithdrawTimer( + import_table, rn, bi, afi, SAFI_ENCAP, + rfapiWithdrawTimerEncap); + + } else { + vnc_zlog_debug_verbose( + "%s: %s at prefix %s/%d", __func__, + ((action == FIF_ACTION_KILL) + ? "killing" + : "replacing"), + inet_ntop(rn->p.family, &rn->p.u.prefix, + buf, BUFSIZ), + rn->p.prefixlen); + + /* + * If this route is waiting to be deleted + * because of + * a previous withdraw, we must cancel its + * timer. + */ + if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED) + && bi->extra->vnc.import.timer) { + + struct thread *t = + (struct thread *)bi->extra->vnc + .import.timer; + struct rfapi_withdraw *wcb = t->arg; + + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + thread_cancel(t); + } + + if (action == FIF_ACTION_UPDATE) { + rfapiBgpInfoDetach(rn, bi); + rfapiBgpInfoFree(bi); + replacing = 1; + } else { + /* + * Kill: do export stuff when removing + * bi + */ + struct rfapi_withdraw *wcb; + struct thread t; + + /* + * pretend we're an expiring timer + */ + wcb = XCALLOC( + MTYPE_RFAPI_WITHDRAW, + sizeof(struct rfapi_withdraw)); + wcb->info = bi; + wcb->node = rn; + wcb->import_table = import_table; + memset(&t, 0, sizeof(t)); + t.arg = wcb; + rfapiWithdrawTimerEncap( + &t); /* frees wcb */ + } + } + + break; + } + } + + if (rn) + RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, replacing ? 1 : 0); + + if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) + return; + + info_new = + rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, NULL); + + if (rn) { + if (!replacing) + route_lock_node(rn); /* incr ref count for new BI */ + } else { + rn = route_node_get(rt, p); + } + + vnc_zlog_debug_verbose( + "%s: (afi=%d, rn=%p) inserting at prefix %s/%d", __func__, afi, + rn, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), + rn->p.prefixlen); + + rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_ENCAP); + + /* + * Delete holddown routes from same NVE. See details in + * rfapiBgpInfoFilteredImportVPN() + */ + for (bi = info_new->next; bi; bi = next) { + + struct prefix pfx_un; + int un_match = 0; + + next = bi->next; + if (!CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) + continue; + + /* + * We already match the VN address (it is the prefix + * of the route node) + */ + + if (!rfapiGetNexthop(bi->attr, &pfx_un) + && prefix_same(&pfx_un, &un_prefix)) { + + un_match = 1; + } + + if (!un_match) + continue; + + vnc_zlog_debug_verbose( + "%s: removing holddown bi matching NVE of new route", + __func__); + if (bi->extra->vnc.import.timer) { + struct thread *t = + (struct thread *)bi->extra->vnc.import.timer; + struct rfapi_withdraw *wcb = t->arg; + + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + thread_cancel(t); + } + rfapiExpireEncapNow(import_table, rn, bi); + } + + rfapiNexthop2Prefix(((struct bgp_info *)(rn->info))->attr, + &p_firstbi_new); + + /* + * If the nexthop address of the selected Encap route (i.e., + * the UN address) has changed, then we must update the VPN + * routes that refer to this Encap route and possibly force + * rfapi callbacks. + */ + if (rfapiAttrNexthopAddrDifferent(&p_firstbi_old, &p_firstbi_new)) { + + struct rfapi_monitor_encap *m; + struct rfapi_monitor_encap *mnext; + + struct route_node *referenced_vpn_prefix; + + /* + * Optimized approach: build radix tree on the fly to + * hold list of VPN nodes referenced by the ENCAP monitors + * + * The nodes in this table correspond to prefixes of VPN routes. + * The "info" pointer of the node points to a chain of + * struct rfapi_monitor_encap, each of which refers to a + * specific VPN node. + */ + struct route_table *referenced_vpn_table; + + referenced_vpn_table = route_table_init(); + assert(referenced_vpn_table); + +/* + * iterate over the set of monitors at this ENCAP node. + */ #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: examining monitors at rn=%p", __func__, rn); + vnc_zlog_debug_verbose("%s: examining monitors at rn=%p", + __func__, rn); #endif - for (m = RFAPI_MONITOR_ENCAP (rn); m; m = m->next) - { - - /* - * For each referenced bi/route, copy the ENCAP route's - * nexthop to the VPN route's cached UN address field and set - * the address family of the cached UN address field. - */ - rfapiCopyUnEncap2VPN (info_new, m->bi); - if (!CHECK_FLAG (m->bi->flags, BGP_INFO_VALID)) - { - SET_FLAG (m->bi->flags, BGP_INFO_VALID); - if (VALID_INTERIOR_TYPE (m->bi->type)) - RFAPI_MONITOR_EXTERIOR (m->node)->valid_interior_count++; - vnc_import_bgp_exterior_add_route_interior (bgp, - import_table, - m->node, m->bi); - } - - /* - * Build a list of unique VPN nodes referenced by these monitors - * - * There could be more than one VPN node here with a given - * prefix. Those are currently in an unsorted linear list - * per prefix. - */ - - referenced_vpn_prefix = - route_node_get (referenced_vpn_table, &m->node->p); - assert (referenced_vpn_prefix); - for (mnext = referenced_vpn_prefix->info; mnext; - mnext = mnext->next) - { - - if (mnext->node == m->node) - break; - } - - if (mnext) - { - /* - * already have an entry for this VPN node - */ - route_unlock_node (referenced_vpn_prefix); - } - else - { - mnext = XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP, - sizeof (struct rfapi_monitor_encap)); - assert (mnext); - mnext->node = m->node; - mnext->next = referenced_vpn_prefix->info; - referenced_vpn_prefix->info = mnext; - } - - } - - /* - * for each VPN node referenced in the ENCAP monitors: - */ - for (referenced_vpn_prefix = route_top (referenced_vpn_table); - referenced_vpn_prefix; - referenced_vpn_prefix = route_next (referenced_vpn_prefix)) - { - - while ((m = referenced_vpn_prefix->info)) - { - - struct route_node *n; - - rfapiMonitorMoveLonger (m->node); - for (n = m->node; n; n = n->parent) - { - //rfapiDoRouteCallback(import_table, n, NULL); - } - rfapiMonitorItNodeChanged (import_table, m->node, NULL); - - referenced_vpn_prefix->info = m->next; - route_unlock_node (referenced_vpn_prefix); - XFREE (MTYPE_RFAPI_MONITOR_ENCAP, m); - } - - } - route_table_finish (referenced_vpn_table); - } - - RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, 0); + for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) { + + /* + * For each referenced bi/route, copy the ENCAP route's + * nexthop to the VPN route's cached UN address field + * and set + * the address family of the cached UN address field. + */ + rfapiCopyUnEncap2VPN(info_new, m->bi); + if (!CHECK_FLAG(m->bi->flags, BGP_INFO_VALID)) { + SET_FLAG(m->bi->flags, BGP_INFO_VALID); + if (VALID_INTERIOR_TYPE(m->bi->type)) + RFAPI_MONITOR_EXTERIOR(m->node) + ->valid_interior_count++; + vnc_import_bgp_exterior_add_route_interior( + bgp, import_table, m->node, m->bi); + } + + /* + * Build a list of unique VPN nodes referenced by these + * monitors + * + * There could be more than one VPN node here with a + * given + * prefix. Those are currently in an unsorted linear + * list + * per prefix. + */ + + referenced_vpn_prefix = route_node_get( + referenced_vpn_table, &m->node->p); + assert(referenced_vpn_prefix); + for (mnext = referenced_vpn_prefix->info; mnext; + mnext = mnext->next) { + + if (mnext->node == m->node) + break; + } + + if (mnext) { + /* + * already have an entry for this VPN node + */ + route_unlock_node(referenced_vpn_prefix); + } else { + mnext = XCALLOC( + MTYPE_RFAPI_MONITOR_ENCAP, + sizeof(struct rfapi_monitor_encap)); + assert(mnext); + mnext->node = m->node; + mnext->next = referenced_vpn_prefix->info; + referenced_vpn_prefix->info = mnext; + } + } + + /* + * for each VPN node referenced in the ENCAP monitors: + */ + for (referenced_vpn_prefix = route_top(referenced_vpn_table); + referenced_vpn_prefix; referenced_vpn_prefix = route_next( + referenced_vpn_prefix)) { + + while ((m = referenced_vpn_prefix->info)) { + + struct route_node *n; + + rfapiMonitorMoveLonger(m->node); + for (n = m->node; n; n = n->parent) { + // rfapiDoRouteCallback(import_table, n, + // NULL); + } + rfapiMonitorItNodeChanged(import_table, m->node, + NULL); + + referenced_vpn_prefix->info = m->next; + route_unlock_node(referenced_vpn_prefix); + XFREE(MTYPE_RFAPI_MONITOR_ENCAP, m); + } + } + route_table_finish(referenced_vpn_table); + } + + RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0); } -static void -rfapiExpireVpnNow ( - struct rfapi_import_table *it, - struct route_node *rn, - struct bgp_info *bi, - int lockoffset) +static void rfapiExpireVpnNow(struct rfapi_import_table *it, + struct route_node *rn, struct bgp_info *bi, + int lockoffset) { - struct rfapi_withdraw *wcb; - struct thread t; - - /* - * pretend we're an expiring timer - */ - wcb = XCALLOC (MTYPE_RFAPI_WITHDRAW, sizeof (struct rfapi_withdraw)); - wcb->info = bi; - wcb->node = rn; - wcb->import_table = it; - wcb->lockoffset = lockoffset; - memset (&t, 0, sizeof (t)); - t.arg = wcb; - rfapiWithdrawTimerVPN (&t); /* frees wcb */ + struct rfapi_withdraw *wcb; + struct thread t; + + /* + * pretend we're an expiring timer + */ + wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw)); + wcb->info = bi; + wcb->node = rn; + wcb->import_table = it; + wcb->lockoffset = lockoffset; + memset(&t, 0, sizeof(t)); + t.arg = wcb; + rfapiWithdrawTimerVPN(&t); /* frees wcb */ } -/* +/* * import a bgp_info if its route target list intersects with the * import table's route target list */ -void -rfapiBgpInfoFilteredImportVPN ( - struct rfapi_import_table *import_table, - int action, - struct peer *peer, - void *rfd, /* set for looped back routes */ - struct prefix *p, - struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ - afi_t afi, - struct prefix_rd *prd, - struct attr *attr, /* part of bgp_info */ - u_char type, /* part of bgp_info */ - u_char sub_type, /* part of bgp_info */ - uint32_t *label) /* part of bgp_info */ +void rfapiBgpInfoFilteredImportVPN( + struct rfapi_import_table *import_table, int action, struct peer *peer, + void *rfd, /* set for looped back routes */ + struct prefix *p, + struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ + afi_t afi, struct prefix_rd *prd, + struct attr *attr, /* part of bgp_info */ + u_char type, /* part of bgp_info */ + u_char sub_type, /* part of bgp_info */ + uint32_t *label) /* part of bgp_info */ { - struct route_table *rt = NULL; - struct route_node *rn; - struct route_node *n; - struct bgp_info *info_new; - struct bgp_info *bi; - struct bgp_info *next; - char buf[BUFSIZ]; - struct prefix vn_prefix; - struct prefix un_prefix; - int un_prefix_valid = 0; - struct route_node *ern; - int replacing = 0; - int original_had_routes = 0; - struct prefix original_nexthop; - const char *action_str = NULL; - int is_it_ce = 0; - - struct bgp *bgp; - bgp = bgp_get_default (); /* assume 1 instance for now */ - - switch (action) - { - case FIF_ACTION_UPDATE: - action_str = "update"; - break; - case FIF_ACTION_WITHDRAW: - action_str = "withdraw"; - break; - case FIF_ACTION_KILL: - action_str = "kill"; - break; - default: - assert (0); - break; - } - - if (import_table == bgp->rfapi->it_ce) - is_it_ce = 1; - - vnc_zlog_debug_verbose ("%s: entry: %s%s: prefix %s/%d: it %p, afi %s", __func__, - (is_it_ce ? "CE-IT " : ""), - action_str, - rfapi_ntop (p->family, &p->u.prefix, buf, BUFSIZ), - p->prefixlen, import_table, afi2str (afi)); - - VNC_ITRCCK; - - /* - * Compare rt lists. If no intersection, don't import this route - * On a withdraw, peer and RD are sufficient to determine if - * we should act. - */ - if (action == FIF_ACTION_UPDATE) - { - if (!attr || !attr->ecommunity) - { - - vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing", - __func__); - return; - } - if ((import_table != bgp->rfapi->it_ce) && - !rfapiEcommunitiesIntersect (import_table->rt_import_list, - attr->ecommunity)) - { - - vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection", - __func__, import_table); - return; - } - - memset (&vn_prefix, 0, sizeof (vn_prefix)); /* keep valgrind happy */ - if (rfapiGetNexthop (attr, &vn_prefix)) - { - /* missing nexthop address would be a bad, bad thing */ - vnc_zlog_debug_verbose ("%s: missing nexthop", __func__); - return; - } - } - - /* - * Figure out which radix tree the route would go into - */ - switch (afi) - { - case AFI_IP: - case AFI_IP6: - case AFI_L2VPN: - rt = import_table->imported_vpn[afi]; - break; - - default: - zlog_err ("%s: bad afi %d", __func__, afi); - return; - } - - /* clear it */ - memset (&original_nexthop, 0, sizeof (original_nexthop)); - - /* - * route_node_lookup returns a node only if there is at least - * one route attached. - */ - rn = route_node_lookup (rt, p); - - vnc_zlog_debug_verbose ("%s: rn=%p", __func__, rn); - - if (rn) - { - - RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1); - route_unlock_node (rn); /* undo lock in route_node_lookup */ - - if (rn->info) - original_had_routes = 1; - - if (VNC_DEBUG(VERBOSE)) - { - vnc_zlog_debug_verbose ("%s: showing IT node on entry", __func__); - rfapiShowItNode (NULL, rn); /* debug */ - } - - /* - * Look for same route (will have same RD and peer) - */ - bi = rfapiItBiIndexSearch (rn, prd, peer, aux_prefix); - - if (bi) - { - - /* - * This was an old test when we iterated over the - * BIs linearly. Since we're now looking up with - * RD and peer, comparing types should not be - * needed. Changed to assertion. - * - * Compare types. Doing so prevents a RFP-originated - * route from matching an imported route, for example. - */ - assert (bi->type == type); - - vnc_zlog_debug_verbose ("%s: found matching bi", __func__); - - /* - * In the special CE table, withdrawals occur without holddown - */ - if (import_table == bgp->rfapi->it_ce) - { - vnc_direct_bgp_del_route_ce (bgp, rn, bi); - if (action == FIF_ACTION_WITHDRAW) - action = FIF_ACTION_KILL; - } - - if (action == FIF_ACTION_WITHDRAW) - { - - int washolddown = CHECK_FLAG (bi->flags, BGP_INFO_REMOVED); - - vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d%s", - __func__, - rfapi_ntop (rn->p.family, &rn->p.u.prefix, buf, - BUFSIZ), rn->p.prefixlen, - (washolddown ? " (already being withdrawn)" : "")); - - VNC_ITRCCK; - if (!washolddown) - { - rfapiBiStartWithdrawTimer (import_table, rn, bi, - afi, SAFI_MPLS_VPN, - rfapiWithdrawTimerVPN); - - RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, -1); - import_table->holddown_count[afi] += 1; - } - VNC_ITRCCK; - } - else - { - vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d", - __func__, - ((action == - FIF_ACTION_KILL) ? "killing" : "replacing"), - rfapi_ntop (rn->p.family, &rn->p.u.prefix, buf, - BUFSIZ), rn->p.prefixlen); - - /* - * If this route is waiting to be deleted because of - * a previous withdraw, we must cancel its timer. - */ - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) && - bi->extra->vnc.import.timer) - { - - struct thread *t = - (struct thread *) bi->extra->vnc.import.timer; - struct rfapi_withdraw *wcb = t->arg; - - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - thread_cancel (t); - - import_table->holddown_count[afi] -= 1; - RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, 1); - } - /* - * decrement remote count (if route is remote) because - * we are going to remove it below - */ - RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, -1); - if (action == FIF_ACTION_UPDATE) - { - replacing = 1; - - /* - * make copy of original nexthop so we can see if it changed - */ - rfapiGetNexthop (bi->attr, &original_nexthop); - - /* - * remove bi without doing any export processing - */ - if (CHECK_FLAG (bi->flags, BGP_INFO_VALID) - && VALID_INTERIOR_TYPE (bi->type)) - RFAPI_MONITOR_EXTERIOR (rn)->valid_interior_count--; - rfapiItBiIndexDel (rn, bi); - rfapiBgpInfoDetach (rn, bi); - rfapiMonitorEncapDelete (bi); - vnc_import_bgp_exterior_del_route_interior (bgp, - import_table, - rn, bi); - rfapiBgpInfoFree (bi); - } - else - { - /* Kill */ - /* - * remove bi and do export processing - */ - import_table->holddown_count[afi] += 1; - rfapiExpireVpnNow (import_table, rn, bi, 0); - } - - } - } - - } - - if (rn) - RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, replacing ? 1 : 0); - - if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) - { - VNC_ITRCCK; - return; - } - - info_new = rfapiBgpInfoCreate (attr, peer, rfd, prd, type, sub_type, label); - - /* - * lookup un address in encap table - */ - ern = route_node_match (import_table->imported_encap[afi], &vn_prefix); - if (ern) - { - rfapiCopyUnEncap2VPN (ern->info, info_new); - route_unlock_node (ern); /* undo lock in route_note_match */ - } - else - { - char buf[BUFSIZ]; - prefix2str (&vn_prefix, buf, sizeof (buf)); - buf[BUFSIZ - 1] = 0; - /* Not a big deal, just means VPN route got here first */ - vnc_zlog_debug_verbose ("%s: no encap route for vn addr %s", __func__, buf); - info_new->extra->vnc.import.un_family = 0; - } - - if (rn) - { - if (!replacing) - route_lock_node (rn); - } - else - { - /* - * No need to increment reference count, so only "get" - * if the node is not there already - */ - rn = route_node_get (rt, p); - } - - /* - * For ethernet routes, if there is an accompanying IP address, - * save it in the bi - */ - if ((AFI_L2VPN == afi) && aux_prefix) - { - - vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__); - info_new->extra->vnc.import.aux_prefix = *aux_prefix; - } - - vnc_zlog_debug_verbose ("%s: inserting bi %p at prefix %s/%d #%d", - __func__, - info_new, - rfapi_ntop (rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), - rn->p.prefixlen, rn->lock); - - rfapiBgpInfoAttachSorted (rn, info_new, afi, SAFI_MPLS_VPN); - rfapiItBiIndexAdd (rn, info_new); - if (!rfapiGetUnAddrOfVpnBi (info_new, NULL)) - { - if (VALID_INTERIOR_TYPE (info_new->type)) - RFAPI_MONITOR_EXTERIOR (rn)->valid_interior_count++; - SET_FLAG (info_new->flags, BGP_INFO_VALID); - } - RFAPI_UPDATE_ITABLE_COUNT (info_new, import_table, afi, 1); - vnc_import_bgp_exterior_add_route_interior (bgp, import_table, rn, - info_new); - - if (import_table == bgp->rfapi->it_ce) - vnc_direct_bgp_add_route_ce (bgp, rn, info_new); - - if (VNC_DEBUG(VERBOSE)) - { - vnc_zlog_debug_verbose ("%s: showing IT node", __func__); - rfapiShowItNode (NULL, rn); /* debug */ - } - - rfapiMonitorEncapAdd (import_table, &vn_prefix, rn, info_new); - - if (!rfapiGetUnAddrOfVpnBi (info_new, &un_prefix)) - { - - /* - * if we have a valid UN address (either via Encap route - * or via tunnel attribute), then we should attempt - * to move any monitors at less-specific nodes to this node - */ - rfapiMonitorMoveLonger (rn); - - un_prefix_valid = 1; - - } - - /* - * 101129 Enhancement: if we add a route (implication: it is not - * in holddown), delete all other routes from this nve at this - * node that are in holddown, regardless of peer. - * - * Reasons it's OK to do that: - * - * - if the holddown route being deleted originally came from BGP VPN, - * it is already gone from BGP (implication of holddown), so there - * won't be any added inconsistency with the BGP RIB. - * - * - once a fresh route is added at a prefix, any routes in holddown - * at that prefix will not show up in RFP responses, so deleting - * the holddown routes won't affect the contents of responses. - * - * - lifetimes are supposed to be consistent, so there should not - * be a case where the fresh route has a shorter lifetime than - * the holddown route, so we don't expect the fresh route to - * disappear and complete its holddown time before the existing - * holddown routes time out. Therefore, we won't have a situation - * where we expect the existing holddown routes to be hidden and - * then to reappear sometime later (as holddown routes) in a - * RFP response. - * - * Among other things, this would enable us to skirt the problem - * of local holddown routes that refer to NVE descriptors that - * have already been closed (if the same NVE triggers a subsequent - * rfapi_open(), the new peer is different and doesn't match the - * peer of the holddown route, so the stale holddown route still - * hangs around until it times out instead of just being replaced - * by the fresh route). - */ - /* - * We know that the new bi will have been inserted before any routes - * in holddown, so we can skip any that came before it - */ - for (bi = info_new->next; bi; bi = next) - { - - struct prefix pfx_vn; - struct prefix pfx_un; - int un_match = 0; - int remote_peer_match = 0; - - next = bi->next; - - /* - * Must be holddown - */ - if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - continue; - - /* - * Must match VN address (nexthop of VPN route) - */ - if (rfapiGetNexthop (bi->attr, &pfx_vn)) - continue; - if (!prefix_same (&pfx_vn, &vn_prefix)) - continue; - - if (un_prefix_valid && /* new route UN addr */ - !rfapiGetUnAddrOfVpnBi (bi, &pfx_un) && /* old route UN addr */ - prefix_same (&pfx_un, &un_prefix)) - { /* compare */ - un_match = 1; - } - if (!RFAPI_LOCAL_BI (bi) && !RFAPI_LOCAL_BI (info_new) && - sockunion_same (&bi->peer->su, &info_new->peer->su)) - { - /* old & new are both remote, same peer */ - remote_peer_match = 1; - } - - if (!un_match & !remote_peer_match) - continue; - - vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route", - __func__); - if (bi->extra->vnc.import.timer) - { - struct thread *t = (struct thread *) bi->extra->vnc.import.timer; - struct rfapi_withdraw *wcb = t->arg; - - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - thread_cancel (t); - } - rfapiExpireVpnNow (import_table, rn, bi, 0); - } - - if (!original_had_routes) - { - /* - * We went from 0 usable routes to 1 usable route. Perform the - * "Adding a Route" export process. - */ - vnc_direct_bgp_add_prefix (bgp, import_table, rn); - vnc_zebra_add_prefix (bgp, import_table, rn); - } - else - { - /* - * Check for nexthop change event - * Note: the prefix_same() test below detects two situations: - * 1. route is replaced, new route has different nexthop - * 2. new route is added (original_nexthop is 0) - */ - struct prefix new_nexthop; - - rfapiGetNexthop (attr, &new_nexthop); - if (!prefix_same (&original_nexthop, &new_nexthop)) - { - /* - * nexthop change event - * vnc_direct_bgp_add_prefix() will recompute VN addr ecommunity - */ - vnc_direct_bgp_add_prefix (bgp, import_table, rn); - } - } - - if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) - { - for (n = rn; n; n = n->parent) - { - //rfapiDoRouteCallback(import_table, n, NULL); - } - rfapiMonitorItNodeChanged (import_table, rn, NULL); - } - RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 0); - VNC_ITRCCK; + struct route_table *rt = NULL; + struct route_node *rn; + struct route_node *n; + struct bgp_info *info_new; + struct bgp_info *bi; + struct bgp_info *next; + char buf[BUFSIZ]; + struct prefix vn_prefix; + struct prefix un_prefix; + int un_prefix_valid = 0; + struct route_node *ern; + int replacing = 0; + int original_had_routes = 0; + struct prefix original_nexthop; + const char *action_str = NULL; + int is_it_ce = 0; + + struct bgp *bgp; + bgp = bgp_get_default(); /* assume 1 instance for now */ + + switch (action) { + case FIF_ACTION_UPDATE: + action_str = "update"; + break; + case FIF_ACTION_WITHDRAW: + action_str = "withdraw"; + break; + case FIF_ACTION_KILL: + action_str = "kill"; + break; + default: + assert(0); + break; + } + + if (import_table == bgp->rfapi->it_ce) + is_it_ce = 1; + + vnc_zlog_debug_verbose("%s: entry: %s%s: prefix %s/%d: it %p, afi %s", + __func__, (is_it_ce ? "CE-IT " : ""), action_str, + rfapi_ntop(p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, import_table, afi2str(afi)); + + VNC_ITRCCK; + + /* + * Compare rt lists. If no intersection, don't import this route + * On a withdraw, peer and RD are sufficient to determine if + * we should act. + */ + if (action == FIF_ACTION_UPDATE) { + if (!attr || !attr->ecommunity) { + + vnc_zlog_debug_verbose( + "%s: attr, extra, or ecommunity missing, not importing", + __func__); + return; + } + if ((import_table != bgp->rfapi->it_ce) + && !rfapiEcommunitiesIntersect(import_table->rt_import_list, + attr->ecommunity)) { + + vnc_zlog_debug_verbose( + "%s: it=%p: no ecommunity intersection", + __func__, import_table); + return; + } + + memset(&vn_prefix, 0, + sizeof(vn_prefix)); /* keep valgrind happy */ + if (rfapiGetNexthop(attr, &vn_prefix)) { + /* missing nexthop address would be a bad, bad thing */ + vnc_zlog_debug_verbose("%s: missing nexthop", __func__); + return; + } + } + + /* + * Figure out which radix tree the route would go into + */ + switch (afi) { + case AFI_IP: + case AFI_IP6: + case AFI_L2VPN: + rt = import_table->imported_vpn[afi]; + break; + + default: + zlog_err("%s: bad afi %d", __func__, afi); + return; + } + + /* clear it */ + memset(&original_nexthop, 0, sizeof(original_nexthop)); + + /* + * route_node_lookup returns a node only if there is at least + * one route attached. + */ + rn = route_node_lookup(rt, p); + + vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn); + + if (rn) { + + RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1); + route_unlock_node(rn); /* undo lock in route_node_lookup */ + + if (rn->info) + original_had_routes = 1; + + if (VNC_DEBUG(VERBOSE)) { + vnc_zlog_debug_verbose("%s: showing IT node on entry", + __func__); + rfapiShowItNode(NULL, rn); /* debug */ + } + + /* + * Look for same route (will have same RD and peer) + */ + bi = rfapiItBiIndexSearch(rn, prd, peer, aux_prefix); + + if (bi) { + + /* + * This was an old test when we iterated over the + * BIs linearly. Since we're now looking up with + * RD and peer, comparing types should not be + * needed. Changed to assertion. + * + * Compare types. Doing so prevents a RFP-originated + * route from matching an imported route, for example. + */ + assert(bi->type == type); + + vnc_zlog_debug_verbose("%s: found matching bi", + __func__); + + /* + * In the special CE table, withdrawals occur without + * holddown + */ + if (import_table == bgp->rfapi->it_ce) { + vnc_direct_bgp_del_route_ce(bgp, rn, bi); + if (action == FIF_ACTION_WITHDRAW) + action = FIF_ACTION_KILL; + } + + if (action == FIF_ACTION_WITHDRAW) { + + int washolddown = + CHECK_FLAG(bi->flags, BGP_INFO_REMOVED); + + vnc_zlog_debug_verbose( + "%s: withdrawing at prefix %s/%d%s", + __func__, rfapi_ntop(rn->p.family, + &rn->p.u.prefix, + buf, BUFSIZ), + rn->p.prefixlen, + (washolddown + ? " (already being withdrawn)" + : "")); + + VNC_ITRCCK; + if (!washolddown) { + rfapiBiStartWithdrawTimer( + import_table, rn, bi, afi, + SAFI_MPLS_VPN, + rfapiWithdrawTimerVPN); + + RFAPI_UPDATE_ITABLE_COUNT( + bi, import_table, afi, -1); + import_table->holddown_count[afi] += 1; + } + VNC_ITRCCK; + } else { + vnc_zlog_debug_verbose( + "%s: %s at prefix %s/%d", __func__, + ((action == FIF_ACTION_KILL) + ? "killing" + : "replacing"), + rfapi_ntop(rn->p.family, + &rn->p.u.prefix, buf, + BUFSIZ), + rn->p.prefixlen); + + /* + * If this route is waiting to be deleted + * because of + * a previous withdraw, we must cancel its + * timer. + */ + if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED) + && bi->extra->vnc.import.timer) { + + struct thread *t = + (struct thread *)bi->extra->vnc + .import.timer; + struct rfapi_withdraw *wcb = t->arg; + + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + thread_cancel(t); + + import_table->holddown_count[afi] -= 1; + RFAPI_UPDATE_ITABLE_COUNT( + bi, import_table, afi, 1); + } + /* + * decrement remote count (if route is remote) + * because + * we are going to remove it below + */ + RFAPI_UPDATE_ITABLE_COUNT(bi, import_table, afi, + -1); + if (action == FIF_ACTION_UPDATE) { + replacing = 1; + + /* + * make copy of original nexthop so we + * can see if it changed + */ + rfapiGetNexthop(bi->attr, + &original_nexthop); + + /* + * remove bi without doing any export + * processing + */ + if (CHECK_FLAG(bi->flags, + BGP_INFO_VALID) + && VALID_INTERIOR_TYPE(bi->type)) + RFAPI_MONITOR_EXTERIOR(rn) + ->valid_interior_count--; + rfapiItBiIndexDel(rn, bi); + rfapiBgpInfoDetach(rn, bi); + rfapiMonitorEncapDelete(bi); + vnc_import_bgp_exterior_del_route_interior( + bgp, import_table, rn, bi); + rfapiBgpInfoFree(bi); + } else { + /* Kill */ + /* + * remove bi and do export processing + */ + import_table->holddown_count[afi] += 1; + rfapiExpireVpnNow(import_table, rn, bi, + 0); + } + } + } + } + + if (rn) + RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, replacing ? 1 : 0); + + if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) { + VNC_ITRCCK; + return; + } + + info_new = + rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, label); + + /* + * lookup un address in encap table + */ + ern = route_node_match(import_table->imported_encap[afi], &vn_prefix); + if (ern) { + rfapiCopyUnEncap2VPN(ern->info, info_new); + route_unlock_node(ern); /* undo lock in route_note_match */ + } else { + char buf[BUFSIZ]; + prefix2str(&vn_prefix, buf, sizeof(buf)); + buf[BUFSIZ - 1] = 0; + /* Not a big deal, just means VPN route got here first */ + vnc_zlog_debug_verbose("%s: no encap route for vn addr %s", + __func__, buf); + info_new->extra->vnc.import.un_family = 0; + } + + if (rn) { + if (!replacing) + route_lock_node(rn); + } else { + /* + * No need to increment reference count, so only "get" + * if the node is not there already + */ + rn = route_node_get(rt, p); + } + + /* + * For ethernet routes, if there is an accompanying IP address, + * save it in the bi + */ + if ((AFI_L2VPN == afi) && aux_prefix) { + + vnc_zlog_debug_verbose("%s: setting BI's aux_prefix", __func__); + info_new->extra->vnc.import.aux_prefix = *aux_prefix; + } + + vnc_zlog_debug_verbose( + "%s: inserting bi %p at prefix %s/%d #%d", __func__, info_new, + rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), + rn->p.prefixlen, rn->lock); + + rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_MPLS_VPN); + rfapiItBiIndexAdd(rn, info_new); + if (!rfapiGetUnAddrOfVpnBi(info_new, NULL)) { + if (VALID_INTERIOR_TYPE(info_new->type)) + RFAPI_MONITOR_EXTERIOR(rn)->valid_interior_count++; + SET_FLAG(info_new->flags, BGP_INFO_VALID); + } + RFAPI_UPDATE_ITABLE_COUNT(info_new, import_table, afi, 1); + vnc_import_bgp_exterior_add_route_interior(bgp, import_table, rn, + info_new); + + if (import_table == bgp->rfapi->it_ce) + vnc_direct_bgp_add_route_ce(bgp, rn, info_new); + + if (VNC_DEBUG(VERBOSE)) { + vnc_zlog_debug_verbose("%s: showing IT node", __func__); + rfapiShowItNode(NULL, rn); /* debug */ + } + + rfapiMonitorEncapAdd(import_table, &vn_prefix, rn, info_new); + + if (!rfapiGetUnAddrOfVpnBi(info_new, &un_prefix)) { + + /* + * if we have a valid UN address (either via Encap route + * or via tunnel attribute), then we should attempt + * to move any monitors at less-specific nodes to this node + */ + rfapiMonitorMoveLonger(rn); + + un_prefix_valid = 1; + } + + /* + * 101129 Enhancement: if we add a route (implication: it is not + * in holddown), delete all other routes from this nve at this + * node that are in holddown, regardless of peer. + * + * Reasons it's OK to do that: + * + * - if the holddown route being deleted originally came from BGP VPN, + * it is already gone from BGP (implication of holddown), so there + * won't be any added inconsistency with the BGP RIB. + * + * - once a fresh route is added at a prefix, any routes in holddown + * at that prefix will not show up in RFP responses, so deleting + * the holddown routes won't affect the contents of responses. + * + * - lifetimes are supposed to be consistent, so there should not + * be a case where the fresh route has a shorter lifetime than + * the holddown route, so we don't expect the fresh route to + * disappear and complete its holddown time before the existing + * holddown routes time out. Therefore, we won't have a situation + * where we expect the existing holddown routes to be hidden and + * then to reappear sometime later (as holddown routes) in a + * RFP response. + * + * Among other things, this would enable us to skirt the problem + * of local holddown routes that refer to NVE descriptors that + * have already been closed (if the same NVE triggers a subsequent + * rfapi_open(), the new peer is different and doesn't match the + * peer of the holddown route, so the stale holddown route still + * hangs around until it times out instead of just being replaced + * by the fresh route). + */ + /* + * We know that the new bi will have been inserted before any routes + * in holddown, so we can skip any that came before it + */ + for (bi = info_new->next; bi; bi = next) { + + struct prefix pfx_vn; + struct prefix pfx_un; + int un_match = 0; + int remote_peer_match = 0; + + next = bi->next; + + /* + * Must be holddown + */ + if (!CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) + continue; + + /* + * Must match VN address (nexthop of VPN route) + */ + if (rfapiGetNexthop(bi->attr, &pfx_vn)) + continue; + if (!prefix_same(&pfx_vn, &vn_prefix)) + continue; + + if (un_prefix_valid && /* new route UN addr */ + !rfapiGetUnAddrOfVpnBi(bi, &pfx_un) + && /* old route UN addr */ + prefix_same(&pfx_un, &un_prefix)) { /* compare */ + un_match = 1; + } + if (!RFAPI_LOCAL_BI(bi) && !RFAPI_LOCAL_BI(info_new) + && sockunion_same(&bi->peer->su, &info_new->peer->su)) { + /* old & new are both remote, same peer */ + remote_peer_match = 1; + } + + if (!un_match & !remote_peer_match) + continue; + + vnc_zlog_debug_verbose( + "%s: removing holddown bi matching NVE of new route", + __func__); + if (bi->extra->vnc.import.timer) { + struct thread *t = + (struct thread *)bi->extra->vnc.import.timer; + struct rfapi_withdraw *wcb = t->arg; + + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); + thread_cancel(t); + } + rfapiExpireVpnNow(import_table, rn, bi, 0); + } + + if (!original_had_routes) { + /* + * We went from 0 usable routes to 1 usable route. Perform the + * "Adding a Route" export process. + */ + vnc_direct_bgp_add_prefix(bgp, import_table, rn); + vnc_zebra_add_prefix(bgp, import_table, rn); + } else { + /* + * Check for nexthop change event + * Note: the prefix_same() test below detects two situations: + * 1. route is replaced, new route has different nexthop + * 2. new route is added (original_nexthop is 0) + */ + struct prefix new_nexthop; + + rfapiGetNexthop(attr, &new_nexthop); + if (!prefix_same(&original_nexthop, &new_nexthop)) { + /* + * nexthop change event + * vnc_direct_bgp_add_prefix() will recompute VN addr + * ecommunity + */ + vnc_direct_bgp_add_prefix(bgp, import_table, rn); + } + } + + if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) { + for (n = rn; n; n = n->parent) { + // rfapiDoRouteCallback(import_table, n, NULL); + } + rfapiMonitorItNodeChanged(import_table, rn, NULL); + } + RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 0); + VNC_ITRCCK; } static rfapi_bi_filtered_import_f * -rfapiBgpInfoFilteredImportFunction (safi_t safi) +rfapiBgpInfoFilteredImportFunction(safi_t safi) { - switch (safi) - { - case SAFI_MPLS_VPN: - return rfapiBgpInfoFilteredImportVPN; - - case SAFI_ENCAP: - return rfapiBgpInfoFilteredImportEncap; - } - zlog_err ("%s: bad safi %d", __func__, safi); - return NULL; + switch (safi) { + case SAFI_MPLS_VPN: + return rfapiBgpInfoFilteredImportVPN; + + case SAFI_ENCAP: + return rfapiBgpInfoFilteredImportEncap; + } + zlog_err("%s: bad safi %d", __func__, safi); + return NULL; } -void -rfapiProcessUpdate ( - struct peer *peer, - void *rfd, /* set when looped from RFP/RFAPI */ - struct prefix *p, - struct prefix_rd *prd, - struct attr *attr, - afi_t afi, - safi_t safi, - u_char type, - u_char sub_type, - uint32_t *label) +void rfapiProcessUpdate(struct peer *peer, + void *rfd, /* set when looped from RFP/RFAPI */ + struct prefix *p, struct prefix_rd *prd, + struct attr *attr, afi_t afi, safi_t safi, u_char type, + u_char sub_type, uint32_t *label) { - struct bgp *bgp; - struct rfapi *h; - struct rfapi_import_table *it; - int has_ip_route = 1; - uint32_t lni = 0; - - bgp = bgp_get_default (); /* assume 1 instance for now */ - assert (bgp); - - h = bgp->rfapi; - assert (h); - - /* - * look at high-order byte of RD. FF means MAC - * address is present (VNC L2VPN) - */ - if ((safi == SAFI_MPLS_VPN) && - (decode_rd_type(prd->val) == RD_TYPE_VNC_ETH)) - { - struct prefix pfx_mac_buf; - struct prefix pfx_nexthop_buf; - int rc; - - /* - * Set flag if prefix and nexthop are the same - don't - * add the route to normal IP-based import tables - */ - if (!rfapiGetNexthop (attr, &pfx_nexthop_buf)) - { - if (!prefix_cmp (&pfx_nexthop_buf, p)) - { - has_ip_route = 0; - } - } - - memset (&pfx_mac_buf, 0, sizeof (pfx_mac_buf)); - pfx_mac_buf.family = AF_ETHERNET; - pfx_mac_buf.prefixlen = 48; - memcpy (&pfx_mac_buf.u.prefix_eth.octet, prd->val + 2, 6); - - /* - * Find rt containing LNI (Logical Network ID), which - * _should_ always be present when mac address is present - */ - rc = rfapiEcommunityGetLNI (attr->ecommunity, &lni); - - vnc_zlog_debug_verbose - ("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p", - __func__, rc, lni, attr); - if (attr && !rc) - { - it = rfapiMacImportTableGet (bgp, lni); - - rfapiBgpInfoFilteredImportVPN ( - it, - FIF_ACTION_UPDATE, - peer, - rfd, - &pfx_mac_buf, /* prefix */ - p, /* aux prefix: IP addr */ - AFI_L2VPN, - prd, - attr, - type, - sub_type, - label); - } - - } - - if (!has_ip_route) - return; - - /* - * Iterate over all import tables; do a filtered import - * for the afi/safi combination - */ - for (it = h->imports; it; it = it->next) - { - (*rfapiBgpInfoFilteredImportFunction (safi)) ( - it, - FIF_ACTION_UPDATE, - peer, - rfd, - p, /* prefix */ - NULL, - afi, - prd, - attr, - type, - sub_type, - label); - } - - if (safi == SAFI_MPLS_VPN) - { - vnc_direct_bgp_rh_add_route (bgp, afi, p, peer, attr); - } - - if (safi == SAFI_MPLS_VPN) - { - rfapiBgpInfoFilteredImportVPN ( - bgp->rfapi->it_ce, - FIF_ACTION_UPDATE, - peer, - rfd, - p, /* prefix */ - NULL, - afi, - prd, - attr, - type, - sub_type, - label); - } + struct bgp *bgp; + struct rfapi *h; + struct rfapi_import_table *it; + int has_ip_route = 1; + uint32_t lni = 0; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + assert(bgp); + + h = bgp->rfapi; + assert(h); + + /* + * look at high-order byte of RD. FF means MAC + * address is present (VNC L2VPN) + */ + if ((safi == SAFI_MPLS_VPN) + && (decode_rd_type(prd->val) == RD_TYPE_VNC_ETH)) { + struct prefix pfx_mac_buf; + struct prefix pfx_nexthop_buf; + int rc; + + /* + * Set flag if prefix and nexthop are the same - don't + * add the route to normal IP-based import tables + */ + if (!rfapiGetNexthop(attr, &pfx_nexthop_buf)) { + if (!prefix_cmp(&pfx_nexthop_buf, p)) { + has_ip_route = 0; + } + } + + memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf)); + pfx_mac_buf.family = AF_ETHERNET; + pfx_mac_buf.prefixlen = 48; + memcpy(&pfx_mac_buf.u.prefix_eth.octet, prd->val + 2, 6); + + /* + * Find rt containing LNI (Logical Network ID), which + * _should_ always be present when mac address is present + */ + rc = rfapiEcommunityGetLNI(attr->ecommunity, &lni); + + vnc_zlog_debug_verbose( + "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p", + __func__, rc, lni, attr); + if (attr && !rc) { + it = rfapiMacImportTableGet(bgp, lni); + + rfapiBgpInfoFilteredImportVPN( + it, FIF_ACTION_UPDATE, peer, rfd, + &pfx_mac_buf, /* prefix */ + p, /* aux prefix: IP addr */ + AFI_L2VPN, prd, attr, type, sub_type, label); + } + } + + if (!has_ip_route) + return; + + /* + * Iterate over all import tables; do a filtered import + * for the afi/safi combination + */ + for (it = h->imports; it; it = it->next) { + (*rfapiBgpInfoFilteredImportFunction(safi))( + it, FIF_ACTION_UPDATE, peer, rfd, p, /* prefix */ + NULL, afi, prd, attr, type, sub_type, label); + } + + if (safi == SAFI_MPLS_VPN) { + vnc_direct_bgp_rh_add_route(bgp, afi, p, peer, attr); + } + + if (safi == SAFI_MPLS_VPN) { + rfapiBgpInfoFilteredImportVPN( + bgp->rfapi->it_ce, FIF_ACTION_UPDATE, peer, rfd, + p, /* prefix */ + NULL, afi, prd, attr, type, sub_type, label); + } } -void -rfapiProcessWithdraw ( - struct peer *peer, - void *rfd, - struct prefix *p, - struct prefix_rd *prd, - struct attr *attr, - afi_t afi, - safi_t safi, - u_char type, - int kill) +void rfapiProcessWithdraw(struct peer *peer, void *rfd, struct prefix *p, + struct prefix_rd *prd, struct attr *attr, afi_t afi, + safi_t safi, u_char type, int kill) { - struct bgp *bgp; - struct rfapi *h; - struct rfapi_import_table *it; - - bgp = bgp_get_default (); /* assume 1 instance for now */ - assert (bgp); - - h = bgp->rfapi; - assert (h); - - /* - * look at high-order byte of RD. FF means MAC - * address is present (VNC L2VPN) - */ - if (h->import_mac != NULL && safi == SAFI_MPLS_VPN && - decode_rd_type(prd->val) == RD_TYPE_VNC_ETH) - { - struct prefix pfx_mac_buf; - void *cursor = NULL; - int rc; - - memset (&pfx_mac_buf, 0, sizeof (pfx_mac_buf)); - pfx_mac_buf.family = AF_ETHERNET; - pfx_mac_buf.prefixlen = 48; - memcpy (&pfx_mac_buf.u.prefix_eth, prd->val + 2, 6); - - /* - * withdraw does not contain attrs, so we don't have - * access to the route's LNI, which would ordinarily - * select the specific mac-based import table. Instead, - * we must iterate over all mac-based tables and rely - * on the RD to match. - * - * If this approach is too slow, add an index where - * key is {RD, peer} and value is the import table - */ - for (rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor); - rc == 0; - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor)) - { + struct bgp *bgp; + struct rfapi *h; + struct rfapi_import_table *it; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + assert(bgp); + + h = bgp->rfapi; + assert(h); + + /* + * look at high-order byte of RD. FF means MAC + * address is present (VNC L2VPN) + */ + if (h->import_mac != NULL && safi == SAFI_MPLS_VPN + && decode_rd_type(prd->val) == RD_TYPE_VNC_ETH) { + struct prefix pfx_mac_buf; + void *cursor = NULL; + int rc; + + memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf)); + pfx_mac_buf.family = AF_ETHERNET; + pfx_mac_buf.prefixlen = 48; + memcpy(&pfx_mac_buf.u.prefix_eth, prd->val + 2, 6); + + /* + * withdraw does not contain attrs, so we don't have + * access to the route's LNI, which would ordinarily + * select the specific mac-based import table. Instead, + * we must iterate over all mac-based tables and rely + * on the RD to match. + * + * If this approach is too slow, add an index where + * key is {RD, peer} and value is the import table + */ + for (rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor); + rc == 0; rc = skiplist_next(h->import_mac, NULL, + (void **)&it, &cursor)) { #if DEBUG_L2_EXTRA - vnc_zlog_debug_verbose - ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)", - __func__, it); + vnc_zlog_debug_verbose( + "%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)", + __func__, it); #endif - rfapiBgpInfoFilteredImportVPN ( - it, - (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), - peer, - rfd, - &pfx_mac_buf, /* prefix */ - p, /* aux_prefix: IP */ - AFI_L2VPN, - prd, - attr, - type, - 0, - NULL); /* sub_type & label unused for withdraw */ - } - } - - /* - * XXX For the case where the withdraw involves an L2 - * route with no IP information, we rely on the lack - * of RT-list intersection to filter out the withdraw - * from the IP-based import tables below - */ - - /* - * Iterate over all import tables; do a filtered import - * for the afi/safi combination - */ - - for (it = h->imports; it; it = it->next) - { - (*rfapiBgpInfoFilteredImportFunction (safi)) ( - it, - (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), - peer, - rfd, - p, /* prefix */ - NULL, - afi, - prd, - attr, - type, - 0, - NULL); /* sub_type & label unused for withdraw */ - } - - /* TBD the deletion should happen after the lifetime expires */ - if (safi == SAFI_MPLS_VPN) - vnc_direct_bgp_rh_del_route (bgp, afi, p, peer); - - if (safi == SAFI_MPLS_VPN) - { - rfapiBgpInfoFilteredImportVPN ( - bgp->rfapi->it_ce, - (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), - peer, - rfd, - p, /* prefix */ - NULL, - afi, - prd, - attr, - type, - 0, - NULL); /* sub_type & label unused for withdraw */ - } + rfapiBgpInfoFilteredImportVPN( + it, + (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), + peer, rfd, &pfx_mac_buf, /* prefix */ + p, /* aux_prefix: IP */ + AFI_L2VPN, prd, attr, type, 0, + NULL); /* sub_type & label unused for withdraw + */ + } + } + + /* + * XXX For the case where the withdraw involves an L2 + * route with no IP information, we rely on the lack + * of RT-list intersection to filter out the withdraw + * from the IP-based import tables below + */ + + /* + * Iterate over all import tables; do a filtered import + * for the afi/safi combination + */ + + for (it = h->imports; it; it = it->next) { + (*rfapiBgpInfoFilteredImportFunction(safi))( + it, (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), + peer, rfd, p, /* prefix */ + NULL, afi, prd, attr, type, 0, + NULL); /* sub_type & label unused for withdraw */ + } + + /* TBD the deletion should happen after the lifetime expires */ + if (safi == SAFI_MPLS_VPN) + vnc_direct_bgp_rh_del_route(bgp, afi, p, peer); + + if (safi == SAFI_MPLS_VPN) { + rfapiBgpInfoFilteredImportVPN( + bgp->rfapi->it_ce, + (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), peer, + rfd, p, /* prefix */ + NULL, afi, prd, attr, type, 0, + NULL); /* sub_type & label unused for withdraw */ + } } /* @@ -4378,65 +4087,57 @@ rfapiProcessWithdraw ( /* surprise, this gets called from peer_delete(), from rfapi_close() */ -static void -rfapiProcessPeerDownRt ( - struct peer *peer, - struct rfapi_import_table *import_table, - afi_t afi, - safi_t safi) +static void rfapiProcessPeerDownRt(struct peer *peer, + struct rfapi_import_table *import_table, + afi_t afi, safi_t safi) { - struct route_node *rn; - struct bgp_info *bi; - struct route_table *rt; - int (*timer_service_func) (struct thread *); - - assert (afi == AFI_IP || afi == AFI_IP6); - - VNC_ITRCCK; - - switch (safi) - { - case SAFI_MPLS_VPN: - rt = import_table->imported_vpn[afi]; - timer_service_func = rfapiWithdrawTimerVPN; - break; - case SAFI_ENCAP: - rt = import_table->imported_encap[afi]; - timer_service_func = rfapiWithdrawTimerEncap; - break; - default: - assert (0); - } - - - for (rn = route_top (rt); rn; rn = route_next (rn)) - { - for (bi = rn->info; bi; bi = bi->next) - { - if (bi->peer == peer) - { - - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - { - /* already in holddown, skip */ - continue; - } - - if (safi == SAFI_MPLS_VPN) - { - RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, -1); - import_table->holddown_count[afi] += 1; - } - rfapiBiStartWithdrawTimer (import_table, rn, bi, - afi, safi, - timer_service_func); - } - } - } - VNC_ITRCCK; + struct route_node *rn; + struct bgp_info *bi; + struct route_table *rt; + int (*timer_service_func)(struct thread *); + + assert(afi == AFI_IP || afi == AFI_IP6); + + VNC_ITRCCK; + + switch (safi) { + case SAFI_MPLS_VPN: + rt = import_table->imported_vpn[afi]; + timer_service_func = rfapiWithdrawTimerVPN; + break; + case SAFI_ENCAP: + rt = import_table->imported_encap[afi]; + timer_service_func = rfapiWithdrawTimerEncap; + break; + default: + assert(0); + } + + + for (rn = route_top(rt); rn; rn = route_next(rn)) { + for (bi = rn->info; bi; bi = bi->next) { + if (bi->peer == peer) { + + if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { + /* already in holddown, skip */ + continue; + } + + if (safi == SAFI_MPLS_VPN) { + RFAPI_UPDATE_ITABLE_COUNT( + bi, import_table, afi, -1); + import_table->holddown_count[afi] += 1; + } + rfapiBiStartWithdrawTimer(import_table, rn, bi, + afi, safi, + timer_service_func); + } + } + } + VNC_ITRCCK; } -/* +/* * This gets called when a peer connection drops. We have to remove * all the routes from this peer. * @@ -4444,49 +4145,46 @@ rfapiProcessPeerDownRt ( * grouping withdrawn routes so we can generate callbacks more * efficiently. */ -void -rfapiProcessPeerDown (struct peer *peer) +void rfapiProcessPeerDown(struct peer *peer) { - struct bgp *bgp; - struct rfapi *h; - struct rfapi_import_table *it; - - /* - * If this peer is a "dummy" peer structure atached to a RFAPI - * nve_descriptor, we don't need to walk the import tables - * because the routes are already withdrawn by rfapi_close() - */ - if (CHECK_FLAG (peer->flags, PEER_FLAG_IS_RFAPI_HD)) - return; - - /* - * 1. Visit all BIs in all ENCAP import tables. - * Start withdraw timer on the BIs that match peer. - * - * 2. Visit All BIs in all VPN import tables. - * Start withdraw timer on the BIs that match peer. - */ - - bgp = bgp_get_default (); /* assume 1 instance for now */ - if (!bgp) - return; - - h = bgp->rfapi; - assert (h); - - for (it = h->imports; it; it = it->next) - { - rfapiProcessPeerDownRt (peer, it, AFI_IP, SAFI_ENCAP); - rfapiProcessPeerDownRt (peer, it, AFI_IP6, SAFI_ENCAP); - rfapiProcessPeerDownRt (peer, it, AFI_IP, SAFI_MPLS_VPN); - rfapiProcessPeerDownRt (peer, it, AFI_IP6, SAFI_MPLS_VPN); - } - - if (h->it_ce) - { - rfapiProcessPeerDownRt (peer, h->it_ce, AFI_IP, SAFI_MPLS_VPN); - rfapiProcessPeerDownRt (peer, h->it_ce, AFI_IP6, SAFI_MPLS_VPN); - } + struct bgp *bgp; + struct rfapi *h; + struct rfapi_import_table *it; + + /* + * If this peer is a "dummy" peer structure atached to a RFAPI + * nve_descriptor, we don't need to walk the import tables + * because the routes are already withdrawn by rfapi_close() + */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) + return; + + /* + * 1. Visit all BIs in all ENCAP import tables. + * Start withdraw timer on the BIs that match peer. + * + * 2. Visit All BIs in all VPN import tables. + * Start withdraw timer on the BIs that match peer. + */ + + bgp = bgp_get_default(); /* assume 1 instance for now */ + if (!bgp) + return; + + h = bgp->rfapi; + assert(h); + + for (it = h->imports; it; it = it->next) { + rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_ENCAP); + rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_ENCAP); + rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_MPLS_VPN); + rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_MPLS_VPN); + } + + if (h->it_ce) { + rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP, SAFI_MPLS_VPN); + rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP6, SAFI_MPLS_VPN); + } } /* @@ -4494,445 +4192,431 @@ rfapiProcessPeerDown (struct peer *peer) * filtered according to the import table's RT list * * TBD: does this function need additions to match rfapiProcessUpdate() - * for, e.g., L2 handling? + * for, e.g., L2 handling? */ -static void -rfapiBgpTableFilteredImport ( - struct bgp *bgp, - struct rfapi_import_table *it, - afi_t afi, - safi_t safi) +static void rfapiBgpTableFilteredImport(struct bgp *bgp, + struct rfapi_import_table *it, + afi_t afi, safi_t safi) { - struct bgp_node *rn1; - struct bgp_node *rn2; - - /* Only these SAFIs have 2-level RIBS */ - assert (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP); - - /* - * Now visit all the rd nodes and the nodes of all the - * route tables attached to them, and import the routes - * if they have matching route targets - */ - for (rn1 = bgp_table_top (bgp->rib[afi][safi]); - rn1; rn1 = bgp_route_next (rn1)) - { - - if (rn1->info) - { - for (rn2 = bgp_table_top (rn1->info); - rn2; rn2 = bgp_route_next (rn2)) - { - - struct bgp_info *bi; - - for (bi = rn2->info; bi; bi = bi->next) - { - u_int32_t label = 0; - - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - continue; - - if (bi->extra) - label = decode_label (&bi->extra->label); - (*rfapiBgpInfoFilteredImportFunction (safi)) ( - it, /* which import table */ - FIF_ACTION_UPDATE, - bi->peer, - NULL, - &rn2->p, /* prefix */ - NULL, - afi, - (struct prefix_rd *) &rn1->p, - bi->attr, - bi->type, - bi->sub_type, - &label); - } - } - } - } + struct bgp_node *rn1; + struct bgp_node *rn2; + + /* Only these SAFIs have 2-level RIBS */ + assert(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP); + + /* + * Now visit all the rd nodes and the nodes of all the + * route tables attached to them, and import the routes + * if they have matching route targets + */ + for (rn1 = bgp_table_top(bgp->rib[afi][safi]); rn1; + rn1 = bgp_route_next(rn1)) { + + if (rn1->info) { + for (rn2 = bgp_table_top(rn1->info); rn2; + rn2 = bgp_route_next(rn2)) { + + struct bgp_info *bi; + + for (bi = rn2->info; bi; bi = bi->next) { + u_int32_t label = 0; + + if (CHECK_FLAG(bi->flags, + BGP_INFO_REMOVED)) + continue; + + if (bi->extra) + label = decode_label( + &bi->extra->label); + (*rfapiBgpInfoFilteredImportFunction( + safi))( + it, /* which import table */ + FIF_ACTION_UPDATE, bi->peer, + NULL, &rn2->p, /* prefix */ + NULL, afi, + (struct prefix_rd *)&rn1->p, + bi->attr, bi->type, + bi->sub_type, &label); + } + } + } + } } /* per-bgp-instance rfapi data */ -struct rfapi * -bgp_rfapi_new (struct bgp *bgp) +struct rfapi *bgp_rfapi_new(struct bgp *bgp) { - struct rfapi *h; - int afi; - struct rfapi_rfp_cfg *cfg = NULL; - struct rfapi_rfp_cb_methods *cbm = NULL; - - assert (bgp->rfapi_cfg == NULL); - - h = (struct rfapi *) XCALLOC (MTYPE_RFAPI, sizeof (struct rfapi)); - - for (afi = AFI_IP; afi < AFI_MAX; afi++) - { - /* ugly, to deal with addition of delegates, part of 0.99.24.1 merge */ - h->un[afi].delegate = route_table_get_default_delegate (); - } - - /* - * initialize the ce import table - */ - h->it_ce = - XCALLOC (MTYPE_RFAPI_IMPORTTABLE, sizeof (struct rfapi_import_table)); - h->it_ce->imported_vpn[AFI_IP] = route_table_init (); - h->it_ce->imported_vpn[AFI_IP6] = route_table_init (); - h->it_ce->imported_encap[AFI_IP] = route_table_init (); - h->it_ce->imported_encap[AFI_IP6] = route_table_init (); - rfapiBgpTableFilteredImport (bgp, h->it_ce, AFI_IP, SAFI_MPLS_VPN); - rfapiBgpTableFilteredImport (bgp, h->it_ce, AFI_IP6, SAFI_MPLS_VPN); - - /* - * Set up work queue for deferred rfapi_close operations - */ - h->deferred_close_q = work_queue_new (bm->master, "rfapi deferred close"); - h->deferred_close_q->spec.workfunc = rfapi_deferred_close_workfunc; - h->deferred_close_q->spec.data = h; - - h->rfp = rfp_start (bm->master, &cfg, &cbm); - bgp->rfapi_cfg = bgp_rfapi_cfg_new (cfg); - if (cbm != NULL) - { - h->rfp_methods = *cbm; - } - return h; + struct rfapi *h; + int afi; + struct rfapi_rfp_cfg *cfg = NULL; + struct rfapi_rfp_cb_methods *cbm = NULL; + + assert(bgp->rfapi_cfg == NULL); + + h = (struct rfapi *)XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi)); + + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + /* ugly, to deal with addition of delegates, part of 0.99.24.1 + * merge */ + h->un[afi].delegate = route_table_get_default_delegate(); + } + + /* + * initialize the ce import table + */ + h->it_ce = XCALLOC(MTYPE_RFAPI_IMPORTTABLE, + sizeof(struct rfapi_import_table)); + h->it_ce->imported_vpn[AFI_IP] = route_table_init(); + h->it_ce->imported_vpn[AFI_IP6] = route_table_init(); + h->it_ce->imported_encap[AFI_IP] = route_table_init(); + h->it_ce->imported_encap[AFI_IP6] = route_table_init(); + rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP, SAFI_MPLS_VPN); + rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP6, SAFI_MPLS_VPN); + + /* + * Set up work queue for deferred rfapi_close operations + */ + h->deferred_close_q = + work_queue_new(bm->master, "rfapi deferred close"); + h->deferred_close_q->spec.workfunc = rfapi_deferred_close_workfunc; + h->deferred_close_q->spec.data = h; + + h->rfp = rfp_start(bm->master, &cfg, &cbm); + bgp->rfapi_cfg = bgp_rfapi_cfg_new(cfg); + if (cbm != NULL) { + h->rfp_methods = *cbm; + } + return h; } -void -bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h) +void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h) { - if (bgp == NULL || h == NULL) - return; - - if (h->resolve_nve_nexthop) - { - skiplist_free (h->resolve_nve_nexthop); - h->resolve_nve_nexthop = NULL; - } - - route_table_finish (h->it_ce->imported_vpn[AFI_IP]); - route_table_finish (h->it_ce->imported_vpn[AFI_IP6]); - route_table_finish (h->it_ce->imported_encap[AFI_IP]); - route_table_finish (h->it_ce->imported_encap[AFI_IP6]); - - if (h->import_mac) - { - struct rfapi_import_table *it; - void *cursor; - int rc; - - for (cursor = NULL, - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor); - !rc; - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor)) - { - - rfapiImportTableFlush (it); - XFREE (MTYPE_RFAPI_IMPORTTABLE, it); - } - skiplist_free (h->import_mac); - h->import_mac = NULL; - } - - work_queue_free (h->deferred_close_q); - - if (h->rfp != NULL) - rfp_stop (h->rfp); - XFREE (MTYPE_RFAPI_IMPORTTABLE, h->it_ce); - XFREE (MTYPE_RFAPI, h); + if (bgp == NULL || h == NULL) + return; + + if (h->resolve_nve_nexthop) { + skiplist_free(h->resolve_nve_nexthop); + h->resolve_nve_nexthop = NULL; + } + + route_table_finish(h->it_ce->imported_vpn[AFI_IP]); + route_table_finish(h->it_ce->imported_vpn[AFI_IP6]); + route_table_finish(h->it_ce->imported_encap[AFI_IP]); + route_table_finish(h->it_ce->imported_encap[AFI_IP6]); + + if (h->import_mac) { + struct rfapi_import_table *it; + void *cursor; + int rc; + + for (cursor = NULL, + rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor); + !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor)) { + + rfapiImportTableFlush(it); + XFREE(MTYPE_RFAPI_IMPORTTABLE, it); + } + skiplist_free(h->import_mac); + h->import_mac = NULL; + } + + work_queue_free(h->deferred_close_q); + + if (h->rfp != NULL) + rfp_stop(h->rfp); + XFREE(MTYPE_RFAPI_IMPORTTABLE, h->it_ce); + XFREE(MTYPE_RFAPI, h); } struct rfapi_import_table * -rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list, - struct rfapi_nve_group_cfg *rfg) +rfapiImportTableRefAdd(struct bgp *bgp, struct ecommunity *rt_import_list, + struct rfapi_nve_group_cfg *rfg) { - struct rfapi *h; - struct rfapi_import_table *it; - afi_t afi; - - h = bgp->rfapi; - assert (h); - - for (it = h->imports; it; it = it->next) - { - if (ecommunity_cmp (it->rt_import_list, rt_import_list)) - break; - } - - vnc_zlog_debug_verbose ("%s: matched it=%p", __func__, it); - - if (!it) - { - it = - XCALLOC (MTYPE_RFAPI_IMPORTTABLE, sizeof (struct rfapi_import_table)); - assert (it); - it->next = h->imports; - h->imports = it; - - it->rt_import_list = ecommunity_dup (rt_import_list); - it->rfg = rfg; - it->monitor_exterior_orphans = - skiplist_new (0, NULL, (void (*)(void *)) prefix_free); - - /* - * fill import route tables from RIBs - * - * Potential area for optimization. If this occurs when - * tables are large (e.g., the operator adds a nve group - * with a new RT list to a running system), it could take - * a while. - * - */ - for (afi = AFI_IP; afi < AFI_MAX; ++afi) - { - - it->imported_vpn[afi] = route_table_init (); - it->imported_encap[afi] = route_table_init (); - - rfapiBgpTableFilteredImport (bgp, it, afi, SAFI_MPLS_VPN); - rfapiBgpTableFilteredImport (bgp, it, afi, SAFI_ENCAP); - - vnc_import_bgp_exterior_redist_enable_it (bgp, afi, it); - } - } - - it->refcount += 1; - - return it; + struct rfapi *h; + struct rfapi_import_table *it; + afi_t afi; + + h = bgp->rfapi; + assert(h); + + for (it = h->imports; it; it = it->next) { + if (ecommunity_cmp(it->rt_import_list, rt_import_list)) + break; + } + + vnc_zlog_debug_verbose("%s: matched it=%p", __func__, it); + + if (!it) { + it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE, + sizeof(struct rfapi_import_table)); + assert(it); + it->next = h->imports; + h->imports = it; + + it->rt_import_list = ecommunity_dup(rt_import_list); + it->rfg = rfg; + it->monitor_exterior_orphans = + skiplist_new(0, NULL, (void (*)(void *))prefix_free); + + /* + * fill import route tables from RIBs + * + * Potential area for optimization. If this occurs when + * tables are large (e.g., the operator adds a nve group + * with a new RT list to a running system), it could take + * a while. + * + */ + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + it->imported_vpn[afi] = route_table_init(); + it->imported_encap[afi] = route_table_init(); + + rfapiBgpTableFilteredImport(bgp, it, afi, + SAFI_MPLS_VPN); + rfapiBgpTableFilteredImport(bgp, it, afi, SAFI_ENCAP); + + vnc_import_bgp_exterior_redist_enable_it(bgp, afi, it); + } + } + + it->refcount += 1; + + return it; } /* * skiplist element free function */ -static void -delete_rem_pfx_na_free (void *na) +static void delete_rem_pfx_na_free(void *na) { - uint32_t *pCounter = ((struct rfapi_nve_addr *) na)->info; + uint32_t *pCounter = ((struct rfapi_nve_addr *)na)->info; - *pCounter += 1; - XFREE (MTYPE_RFAPI_NVE_ADDR, na); + *pCounter += 1; + XFREE(MTYPE_RFAPI_NVE_ADDR, na); } /* * Common deleter for IP and MAC import tables */ -static void -rfapiDeleteRemotePrefixesIt ( - struct bgp *bgp, - struct rfapi_import_table *it, - struct prefix *un, - struct prefix *vn, - struct prefix *p, - int delete_active, - int delete_holddown, - uint32_t *pARcount, - uint32_t *pAHcount, - uint32_t *pHRcount, - uint32_t *pHHcount, - struct skiplist *uniq_active_nves, - struct skiplist *uniq_holddown_nves) +static void rfapiDeleteRemotePrefixesIt( + struct bgp *bgp, struct rfapi_import_table *it, struct prefix *un, + struct prefix *vn, struct prefix *p, int delete_active, + int delete_holddown, uint32_t *pARcount, uint32_t *pAHcount, + uint32_t *pHRcount, uint32_t *pHHcount, + struct skiplist *uniq_active_nves, struct skiplist *uniq_holddown_nves) { - afi_t afi; + afi_t afi; #if DEBUG_L2_EXTRA - { - char buf_pfx[BUFSIZ]; - - if (p) - { - prefix2str (p, buf_pfx, BUFSIZ); - } - else - { - buf_pfx[0] = '*'; - buf_pfx[1] = 0; - } - - vnc_zlog_debug_verbose ("%s: entry, p=%s, delete_active=%d, delete_holddown=%d", - __func__, buf_pfx, delete_active, delete_holddown); - } + { + char buf_pfx[BUFSIZ]; + + if (p) { + prefix2str(p, buf_pfx, BUFSIZ); + } else { + buf_pfx[0] = '*'; + buf_pfx[1] = 0; + } + + vnc_zlog_debug_verbose( + "%s: entry, p=%s, delete_active=%d, delete_holddown=%d", + __func__, buf_pfx, delete_active, delete_holddown); + } #endif - for (afi = AFI_IP; afi < AFI_MAX; ++afi) - { - - struct route_table *rt; - struct route_node *rn; - - if (p && (family2afi (p->family) != afi)) - { - continue; - } - - rt = it->imported_vpn[afi]; - if (!rt) - continue; - - vnc_zlog_debug_verbose ("%s: scanning rt for afi=%d", __func__, afi); - - for (rn = route_top (rt); rn; rn = route_next (rn)) - { - struct bgp_info *bi; - struct bgp_info *next; - - if (VNC_DEBUG(IMPORT_DEL_REMOTE)) - { - char p1line[BUFSIZ]; - char p2line[BUFSIZ]; - - prefix2str (p, p1line, BUFSIZ); - prefix2str (&rn->p, p2line, BUFSIZ); - vnc_zlog_debug_any ("%s: want %s, have %s", __func__, p1line, p2line); - } - - if (p && prefix_cmp (p, &rn->p)) - continue; - - { - char buf_pfx[BUFSIZ]; - prefix2str (&rn->p, buf_pfx, BUFSIZ); - vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__, buf_pfx); - } - - /* TBD is this valid for afi == AFI_L2VPN? */ - RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1); - - for (bi = rn->info; bi; bi = next) - { - next = bi->next; - - struct prefix qpt; - struct prefix qct; - int qpt_valid = 0; - int qct_valid = 0; - int is_active = 0; - - vnc_zlog_debug_verbose ("%s: examining bi %p", __func__, bi); - - if (bi->attr) - { - if (!rfapiGetNexthop (bi->attr, &qpt)) - qpt_valid = 1; - } - if (vn) - { - if (!qpt_valid || !prefix_match (vn, &qpt)) - { + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + struct route_table *rt; + struct route_node *rn; + + if (p && (family2afi(p->family) != afi)) { + continue; + } + + rt = it->imported_vpn[afi]; + if (!rt) + continue; + + vnc_zlog_debug_verbose("%s: scanning rt for afi=%d", __func__, + afi); + + for (rn = route_top(rt); rn; rn = route_next(rn)) { + struct bgp_info *bi; + struct bgp_info *next; + + if (VNC_DEBUG(IMPORT_DEL_REMOTE)) { + char p1line[BUFSIZ]; + char p2line[BUFSIZ]; + + prefix2str(p, p1line, BUFSIZ); + prefix2str(&rn->p, p2line, BUFSIZ); + vnc_zlog_debug_any("%s: want %s, have %s", + __func__, p1line, p2line); + } + + if (p && prefix_cmp(p, &rn->p)) + continue; + + { + char buf_pfx[BUFSIZ]; + prefix2str(&rn->p, buf_pfx, BUFSIZ); + vnc_zlog_debug_verbose("%s: rn pfx=%s", + __func__, buf_pfx); + } + + /* TBD is this valid for afi == AFI_L2VPN? */ + RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1); + + for (bi = rn->info; bi; bi = next) { + next = bi->next; + + struct prefix qpt; + struct prefix qct; + int qpt_valid = 0; + int qct_valid = 0; + int is_active = 0; + + vnc_zlog_debug_verbose("%s: examining bi %p", + __func__, bi); + + if (bi->attr) { + if (!rfapiGetNexthop(bi->attr, &qpt)) + qpt_valid = 1; + } + if (vn) { + if (!qpt_valid + || !prefix_match(vn, &qpt)) { #if DEBUG_L2_EXTRA - vnc_zlog_debug_verbose - ("%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)", - __func__); + vnc_zlog_debug_verbose( + "%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)", + __func__); #endif - continue; - } - } + continue; + } + } - if (!rfapiGetUnAddrOfVpnBi (bi, &qct)) - qct_valid = 1; + if (!rfapiGetUnAddrOfVpnBi(bi, &qct)) + qct_valid = 1; - if (un) - { - if (!qct_valid || !prefix_match (un, &qct)) - { + if (un) { + if (!qct_valid + || !prefix_match(un, &qct)) { #if DEBUG_L2_EXTRA - vnc_zlog_debug_verbose - ("%s: continue at un && !qct_valid || !prefix_match(un, &qct)", - __func__); + vnc_zlog_debug_verbose( + "%s: continue at un && !qct_valid || !prefix_match(un, &qct)", + __func__); #endif - continue; - } - } - - - /* - * Blow bi away - */ - /* - * If this route is waiting to be deleted because of - * a previous withdraw, we must cancel its timer. - */ - if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)) - { - if (!delete_holddown) - continue; - if (bi->extra->vnc.import.timer) - { - - struct thread *t = - (struct thread *) bi->extra->vnc.import.timer; - struct rfapi_withdraw *wcb = t->arg; - - wcb->import_table->holddown_count[afi] -= 1; - RFAPI_UPDATE_ITABLE_COUNT (bi, wcb->import_table, afi, - 1); - XFREE (MTYPE_RFAPI_WITHDRAW, wcb); - thread_cancel (t); - } - } - else - { - if (!delete_active) - continue; - is_active = 1; - } - - vnc_zlog_debug_verbose - ("%s: deleting bi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)", - __func__, bi, qct_valid, qpt_valid, delete_holddown, - delete_active); - - - /* - * add nve to list - */ - if (qct_valid && qpt_valid) - { - - struct rfapi_nve_addr na; - struct rfapi_nve_addr *nap; - - memset (&na, 0, sizeof (na)); - assert (!rfapiQprefix2Raddr (&qct, &na.un)); - assert (!rfapiQprefix2Raddr (&qpt, &na.vn)); - - if (skiplist_search ((is_active ? uniq_active_nves : - uniq_holddown_nves), &na, - (void **) &nap)) - { - char line[BUFSIZ]; - - nap = XCALLOC (MTYPE_RFAPI_NVE_ADDR, - sizeof (struct rfapi_nve_addr)); - assert (nap); - *nap = na; - nap->info = is_active ? pAHcount : pHHcount; - skiplist_insert ((is_active ? uniq_active_nves : - uniq_holddown_nves), nap, nap); - - rfapiNveAddr2Str (nap, line, BUFSIZ); - } - } - - vnc_direct_bgp_rh_del_route (bgp, afi, &rn->p, bi->peer); - - RFAPI_UPDATE_ITABLE_COUNT (bi, it, afi, -1); - it->holddown_count[afi] += 1; - rfapiExpireVpnNow (it, rn, bi, 1); - - vnc_zlog_debug_verbose ("%s: incrementing count (is_active=%d)", - __func__, is_active); - - if (is_active) - ++ * pARcount; - else - ++ * pHRcount; - } - } - } + continue; + } + } + + + /* + * Blow bi away + */ + /* + * If this route is waiting to be deleted + * because of + * a previous withdraw, we must cancel its + * timer. + */ + if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { + if (!delete_holddown) + continue; + if (bi->extra->vnc.import.timer) { + + struct thread *t = + (struct thread *)bi + ->extra->vnc + .import.timer; + struct rfapi_withdraw *wcb = + t->arg; + + wcb->import_table + ->holddown_count[afi] -= + 1; + RFAPI_UPDATE_ITABLE_COUNT( + bi, wcb->import_table, + afi, 1); + XFREE(MTYPE_RFAPI_WITHDRAW, + wcb); + thread_cancel(t); + } + } else { + if (!delete_active) + continue; + is_active = 1; + } + + vnc_zlog_debug_verbose( + "%s: deleting bi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)", + __func__, bi, qct_valid, qpt_valid, + delete_holddown, delete_active); + + + /* + * add nve to list + */ + if (qct_valid && qpt_valid) { + + struct rfapi_nve_addr na; + struct rfapi_nve_addr *nap; + + memset(&na, 0, sizeof(na)); + assert(!rfapiQprefix2Raddr(&qct, + &na.un)); + assert(!rfapiQprefix2Raddr(&qpt, + &na.vn)); + + if (skiplist_search( + (is_active + ? uniq_active_nves + : uniq_holddown_nves), + &na, (void **)&nap)) { + char line[BUFSIZ]; + + nap = XCALLOC( + MTYPE_RFAPI_NVE_ADDR, + sizeof(struct + rfapi_nve_addr)); + assert(nap); + *nap = na; + nap->info = is_active + ? pAHcount + : pHHcount; + skiplist_insert( + (is_active + ? uniq_active_nves + : uniq_holddown_nves), + nap, nap); + + rfapiNveAddr2Str(nap, line, + BUFSIZ); + } + } + + vnc_direct_bgp_rh_del_route(bgp, afi, &rn->p, + bi->peer); + + RFAPI_UPDATE_ITABLE_COUNT(bi, it, afi, -1); + it->holddown_count[afi] += 1; + rfapiExpireVpnNow(it, rn, bi, 1); + + vnc_zlog_debug_verbose( + "%s: incrementing count (is_active=%d)", + __func__, is_active); + + if (is_active) + ++*pARcount; + else + ++*pHRcount; + } + } + } } @@ -4944,7 +4628,7 @@ rfapiDeleteRemotePrefixesIt ( * * UI helper: For use by the "clear vnc prefixes" command * - * input: + * input: * un if set, tunnel must match this prefix * vn if set, nexthop prefix must match this prefix * p if set, prefix must match this prefix @@ -4959,133 +4643,110 @@ rfapiDeleteRemotePrefixesIt ( * return value: * void --------------------------------------------*/ -void -rfapiDeleteRemotePrefixes ( - struct prefix *un, - struct prefix *vn, - struct prefix *p, - struct rfapi_import_table *arg_it, - int delete_active, - int delete_holddown, - uint32_t *pARcount, - uint32_t *pAHcount, - uint32_t *pHRcount, - uint32_t *pHHcount) +void rfapiDeleteRemotePrefixes(struct prefix *un, struct prefix *vn, + struct prefix *p, + struct rfapi_import_table *arg_it, + int delete_active, int delete_holddown, + uint32_t *pARcount, uint32_t *pAHcount, + uint32_t *pHRcount, uint32_t *pHHcount) { - struct bgp *bgp; - struct rfapi *h; - struct rfapi_import_table *it; - uint32_t deleted_holddown_route_count = 0; - uint32_t deleted_active_route_count = 0; - uint32_t deleted_holddown_nve_count = 0; - uint32_t deleted_active_nve_count = 0; - struct skiplist *uniq_holddown_nves; - struct skiplist *uniq_active_nves; - - VNC_ITRCCK; - - bgp = bgp_get_default (); /* assume 1 instance for now */ - /* If no bgp instantiated yet, no vnc prefixes exist */ - if (!bgp) - return; - - h = bgp->rfapi; - assert (h); - - uniq_holddown_nves = - skiplist_new (0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free); - uniq_active_nves = - skiplist_new (0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free); - - /* - * Iterate over all import tables; do a filtered import - * for the afi/safi combination - */ - - if (arg_it) - it = arg_it; - else - it = h->imports; - for (; it; ) - { - - vnc_zlog_debug_verbose - ("%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p", - __func__, it); - - rfapiDeleteRemotePrefixesIt ( - bgp, - it, - un, - vn, - p, - delete_active, - delete_holddown, - &deleted_active_route_count, - &deleted_active_nve_count, - &deleted_holddown_route_count, - &deleted_holddown_nve_count, - uniq_active_nves, - uniq_holddown_nves); - - if (arg_it) - it = NULL; - else - it = it->next; - } - - /* - * Now iterate over L2 import tables - */ - if (h->import_mac && !(p && (p->family != AF_ETHERNET))) - { - - void *cursor = NULL; - int rc; - - for (cursor = NULL, - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor); - !rc; - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor)) - { - - vnc_zlog_debug_verbose - ("%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p", - __func__, it); - - rfapiDeleteRemotePrefixesIt ( - bgp, - it, - un, - vn, - p, - delete_active, - delete_holddown, - &deleted_active_route_count, - &deleted_active_nve_count, - &deleted_holddown_route_count, - &deleted_holddown_nve_count, - uniq_active_nves, - uniq_holddown_nves); - } - } - - /* - * our custom element freeing function above counts as it deletes - */ - skiplist_free (uniq_holddown_nves); - skiplist_free (uniq_active_nves); - - if (pARcount) - *pARcount = deleted_active_route_count; - if (pAHcount) - *pAHcount = deleted_active_nve_count; - if (pHRcount) - *pHRcount = deleted_holddown_route_count; - if (pHHcount) - *pHHcount = deleted_holddown_nve_count; - - VNC_ITRCCK; + struct bgp *bgp; + struct rfapi *h; + struct rfapi_import_table *it; + uint32_t deleted_holddown_route_count = 0; + uint32_t deleted_active_route_count = 0; + uint32_t deleted_holddown_nve_count = 0; + uint32_t deleted_active_nve_count = 0; + struct skiplist *uniq_holddown_nves; + struct skiplist *uniq_active_nves; + + VNC_ITRCCK; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + /* If no bgp instantiated yet, no vnc prefixes exist */ + if (!bgp) + return; + + h = bgp->rfapi; + assert(h); + + uniq_holddown_nves = + skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free); + uniq_active_nves = + skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free); + + /* + * Iterate over all import tables; do a filtered import + * for the afi/safi combination + */ + + if (arg_it) + it = arg_it; + else + it = h->imports; + for (; it;) { + + vnc_zlog_debug_verbose( + "%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p", + __func__, it); + + rfapiDeleteRemotePrefixesIt( + bgp, it, un, vn, p, delete_active, delete_holddown, + &deleted_active_route_count, &deleted_active_nve_count, + &deleted_holddown_route_count, + &deleted_holddown_nve_count, uniq_active_nves, + uniq_holddown_nves); + + if (arg_it) + it = NULL; + else + it = it->next; + } + + /* + * Now iterate over L2 import tables + */ + if (h->import_mac && !(p && (p->family != AF_ETHERNET))) { + + void *cursor = NULL; + int rc; + + for (cursor = NULL, + rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor); + !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor)) { + + vnc_zlog_debug_verbose( + "%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p", + __func__, it); + + rfapiDeleteRemotePrefixesIt( + bgp, it, un, vn, p, delete_active, + delete_holddown, &deleted_active_route_count, + &deleted_active_nve_count, + &deleted_holddown_route_count, + &deleted_holddown_nve_count, uniq_active_nves, + uniq_holddown_nves); + } + } + + /* + * our custom element freeing function above counts as it deletes + */ + skiplist_free(uniq_holddown_nves); + skiplist_free(uniq_active_nves); + + if (pARcount) + *pARcount = deleted_active_route_count; + if (pAHcount) + *pAHcount = deleted_active_nve_count; + if (pHRcount) + *pHRcount = deleted_holddown_route_count; + if (pHHcount) + *pHHcount = deleted_holddown_nve_count; + + VNC_ITRCCK; } /*------------------------------------------ @@ -5093,7 +4754,7 @@ rfapiDeleteRemotePrefixes ( * * UI helper: count VRF routes from BGP side * - * input: + * input: * * output * pALRcount count of active local routes @@ -5104,83 +4765,73 @@ rfapiDeleteRemotePrefixes ( * return value: * void --------------------------------------------*/ -void -rfapiCountAllItRoutes (int *pALRcount, /* active local routes */ - int *pARRcount, /* active remote routes */ - int *pHRcount, /* holddown routes */ - int *pIRcount) /* imported routes */ +void rfapiCountAllItRoutes(int *pALRcount, /* active local routes */ + int *pARRcount, /* active remote routes */ + int *pHRcount, /* holddown routes */ + int *pIRcount) /* imported routes */ { - struct bgp *bgp; - struct rfapi *h; - struct rfapi_import_table *it; - afi_t afi; - - int total_active_local = 0; - int total_active_remote = 0; - int total_holddown = 0; - int total_imported = 0; - - bgp = bgp_get_default (); /* assume 1 instance for now */ - assert (bgp); - - h = bgp->rfapi; - assert (h); - - /* - * Iterate over all import tables; do a filtered import - * for the afi/safi combination - */ - - for (it = h->imports; it; it = it->next) - { - - for (afi = AFI_IP; afi < AFI_MAX; ++afi) - { - - total_active_local += it->local_count[afi]; - total_active_remote += it->remote_count[afi]; - total_holddown += it->holddown_count[afi]; - total_imported += it->imported_count[afi]; - - } - } - - void *cursor; - int rc; - - if (h->import_mac) - { - for (cursor = NULL, - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor); - !rc; - rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor)) - { - - total_active_local += it->local_count[AFI_L2VPN]; - total_active_remote += it->remote_count[AFI_L2VPN]; - total_holddown += it->holddown_count[AFI_L2VPN]; - total_imported += it->imported_count[AFI_L2VPN]; - - } - } - - - if (pALRcount) - { - *pALRcount = total_active_local; - } - if (pARRcount) - { - *pARRcount = total_active_remote; - } - if (pHRcount) - { - *pHRcount = total_holddown; - } - if (pIRcount) - { - *pIRcount = total_imported; - } + struct bgp *bgp; + struct rfapi *h; + struct rfapi_import_table *it; + afi_t afi; + + int total_active_local = 0; + int total_active_remote = 0; + int total_holddown = 0; + int total_imported = 0; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + assert(bgp); + + h = bgp->rfapi; + assert(h); + + /* + * Iterate over all import tables; do a filtered import + * for the afi/safi combination + */ + + for (it = h->imports; it; it = it->next) { + + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + total_active_local += it->local_count[afi]; + total_active_remote += it->remote_count[afi]; + total_holddown += it->holddown_count[afi]; + total_imported += it->imported_count[afi]; + } + } + + void *cursor; + int rc; + + if (h->import_mac) { + for (cursor = NULL, + rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor); + !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it, + &cursor)) { + + total_active_local += it->local_count[AFI_L2VPN]; + total_active_remote += it->remote_count[AFI_L2VPN]; + total_holddown += it->holddown_count[AFI_L2VPN]; + total_imported += it->imported_count[AFI_L2VPN]; + } + } + + + if (pALRcount) { + *pALRcount = total_active_local; + } + if (pARRcount) { + *pARRcount = total_active_remote; + } + if (pHRcount) { + *pHRcount = total_holddown; + } + if (pIRcount) { + *pIRcount = total_imported; + } } /*------------------------------------------ @@ -5188,7 +4839,7 @@ rfapiCountAllItRoutes (int *pALRcount, /* active local routes */ * * calculate holddown value based on lifetime * - * input: + * input: * lifetime lifetime * * return value: @@ -5197,22 +4848,21 @@ rfapiCountAllItRoutes (int *pALRcount, /* active local routes */ * --------------------------------------------*/ /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */ -uint32_t -rfapiGetHolddownFromLifetime (uint32_t lifetime) +uint32_t rfapiGetHolddownFromLifetime(uint32_t lifetime) { - uint32_t factor; - struct bgp *bgp; - - bgp = bgp_get_default (); - if (bgp && bgp->rfapi_cfg) - factor = bgp->rfapi_cfg->rfp_cfg.holddown_factor; - else - factor = RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR; - - if (factor < 100 || lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY) - lifetime = lifetime * factor / 100; - if (lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY) - return lifetime; - else - return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY; + uint32_t factor; + struct bgp *bgp; + + bgp = bgp_get_default(); + if (bgp && bgp->rfapi_cfg) + factor = bgp->rfapi_cfg->rfp_cfg.holddown_factor; + else + factor = RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR; + + if (factor < 100 || lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY) + lifetime = lifetime * factor / 100; + if (lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY) + return lifetime; + else + return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY; } |
