back to topotato report
topotato coverage report
Current view: top level - bgpd/rfapi - rfapi_import.c (source / functions) Hit Total Coverage
Test: test_exabgp_demo.py::ExaBGPDemo Lines: 75 1892 4.0 %
Date: 2023-02-24 18:37:55 Functions: 5 69 7.2 %

          Line data    Source code
       1             : /*
       2             : *
       3             : * Copyright 2009-2016, LabN Consulting, L.L.C.
       4             : *
       5             : *
       6             : * This program is free software; you can redistribute it and/or
       7             : * modify it under the terms of the GNU General Public License
       8             : * as published by the Free Software Foundation; either version 2
       9             : * of the License, or (at your option) any later version.
      10             : *
      11             : * This program is distributed in the hope that it will be useful,
      12             : * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : * GNU General Public License for more details.
      15             : *
      16             : * You should have received a copy of the GNU General Public License along
      17             : * with this program; see the file COPYING; if not, write to the Free Software
      18             : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             : */
      20             : 
      21             : /*
      22             :  * File:        rfapi_import.c
      23             :  * Purpose:     Handle import of routes from BGP to RFAPI
      24             :  */
      25             : 
      26             : #include "lib/zebra.h"
      27             : #include "lib/prefix.h"
      28             : #include "lib/agg_table.h"
      29             : #include "lib/vty.h"
      30             : #include "lib/memory.h"
      31             : #include "lib/log.h"
      32             : #include "lib/skiplist.h"
      33             : #include "lib/thread.h"
      34             : #include "lib/stream.h"
      35             : #include "lib/lib_errors.h"
      36             : 
      37             : #include "bgpd/bgpd.h"
      38             : #include "bgpd/bgp_ecommunity.h"
      39             : #include "bgpd/bgp_attr.h"
      40             : #include "bgpd/bgp_route.h"
      41             : #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
      42             : #include "bgpd/bgp_vnc_types.h"
      43             : #include "bgpd/bgp_rd.h"
      44             : 
      45             : #include "bgpd/rfapi/rfapi.h"
      46             : #include "bgpd/rfapi/bgp_rfapi_cfg.h"
      47             : #include "bgpd/rfapi/rfapi_backend.h"
      48             : #include "bgpd/rfapi/rfapi_import.h"
      49             : #include "bgpd/rfapi/rfapi_private.h"
      50             : #include "bgpd/rfapi/rfapi_monitor.h"
      51             : #include "bgpd/rfapi/rfapi_nve_addr.h"
      52             : #include "bgpd/rfapi/rfapi_vty.h"
      53             : #include "bgpd/rfapi/vnc_export_bgp.h"
      54             : #include "bgpd/rfapi/vnc_export_bgp_p.h"
      55             : #include "bgpd/rfapi/vnc_zebra.h"
      56             : #include "bgpd/rfapi/vnc_import_bgp.h"
      57             : #include "bgpd/rfapi/vnc_import_bgp_p.h"
      58             : #include "bgpd/rfapi/rfapi_rib.h"
      59             : #include "bgpd/rfapi/rfapi_encap_tlv.h"
      60             : #include "bgpd/rfapi/vnc_debug.h"
      61             : 
      62             : #ifdef HAVE_GLIBC_BACKTRACE
      63             : /* for backtrace and friends */
      64             : #include <execinfo.h>
      65             : #endif /* HAVE_GLIBC_BACKTRACE */
      66             : 
      67             : #undef DEBUG_MONITOR_MOVE_SHORTER
      68             : #undef DEBUG_RETURNED_NHL
      69             : #undef DEBUG_ROUTE_COUNTERS
      70             : #undef DEBUG_ENCAP_MONITOR
      71             : #undef DEBUG_L2_EXTRA
      72             : #undef DEBUG_IT_NODES
      73             : #undef DEBUG_BI_SEARCH
      74             : 
      75             : /*
      76             :  * Allocated for each withdraw timer instance; freed when the timer
      77             :  * expires or is canceled
      78             :  */
      79             : struct rfapi_withdraw {
      80             :         struct rfapi_import_table *import_table;
      81             :         struct agg_node *node;
      82             :         struct bgp_path_info *info;
      83             :         safi_t safi; /* used only for bulk operations */
      84             :         /*
      85             :          * For import table node reference count checking (i.e., debugging).
      86             :          * Normally when a timer expires, lockoffset should be 0. However, if
      87             :          * the timer expiration function is called directly (e.g.,
      88             :          * rfapiExpireVpnNow), the node could be locked by a preceding
      89             :          * agg_route_top() or agg_route_next() in a loop, so we need to pass
      90             :          * this value in.
      91             :          */
      92             :         int lockoffset;
      93             : };
      94             : 
      95             : /*
      96             :  * DEBUG FUNCTION
      97             :  * It's evil and fiendish. It's compiler-dependent.
      98             :  * ? Might need LDFLAGS -rdynamic to produce all function names
      99             :  */
     100           0 : void rfapiDebugBacktrace(void)
     101             : {
     102             : #ifdef HAVE_GLIBC_BACKTRACE
     103             : #define RFAPI_DEBUG_BACKTRACE_NENTRIES  200
     104             :         void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES];
     105             :         char **syms;
     106             :         size_t i;
     107             :         size_t size;
     108             : 
     109             :         size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES);
     110             :         syms = backtrace_symbols(buf, size);
     111             : 
     112             :         for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) {
     113             :                 vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i, syms[i]);
     114             :         }
     115             : 
     116             :         free(syms);
     117             : #else
     118             : #endif
     119           0 : }
     120             : 
     121             : /*
     122             :  * DEBUG FUNCTION
     123             :  * Count remote routes and compare with actively-maintained values.
     124             :  * Abort if they disagree.
     125             :  */
     126           0 : void rfapiCheckRouteCount(void)
     127             : {
     128           0 :         struct bgp *bgp = bgp_get_default();
     129           0 :         struct rfapi *h;
     130           0 :         struct rfapi_import_table *it;
     131           0 :         afi_t afi;
     132             : 
     133           0 :         assert(bgp);
     134             : 
     135           0 :         h = bgp->rfapi;
     136           0 :         assert(h);
     137             : 
     138           0 :         for (it = h->imports; it; it = it->next) {
     139           0 :                 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
     140             : 
     141           0 :                         struct agg_table *rt;
     142           0 :                         struct agg_node *rn;
     143             : 
     144           0 :                         int holddown_count = 0;
     145           0 :                         int local_count = 0;
     146           0 :                         int imported_count = 0;
     147           0 :                         int remote_count = 0;
     148             : 
     149           0 :                         rt = it->imported_vpn[afi];
     150             : 
     151           0 :                         for (rn = agg_route_top(rt); rn;
     152           0 :                              rn = agg_route_next(rn)) {
     153           0 :                                 struct bgp_path_info *bpi;
     154           0 :                                 struct bgp_path_info *next;
     155             : 
     156           0 :                                 for (bpi = rn->info; bpi; bpi = next) {
     157           0 :                                         next = bpi->next;
     158             : 
     159           0 :                                         if (CHECK_FLAG(bpi->flags,
     160             :                                                        BGP_PATH_REMOVED)) {
     161           0 :                                                 ++holddown_count;
     162             : 
     163             :                                         } else {
     164           0 :                                                 if (RFAPI_LOCAL_BI(bpi)) {
     165           0 :                                                         ++local_count;
     166             :                                                 } else {
     167           0 :                                                         if (RFAPI_DIRECT_IMPORT_BI(
     168             :                                                                     bpi)) {
     169           0 :                                                                 ++imported_count;
     170             :                                                         } else {
     171           0 :                                                                 ++remote_count;
     172             :                                                         }
     173             :                                                 }
     174             :                                         }
     175             :                                 }
     176             :                         }
     177             : 
     178           0 :                         if (it->holddown_count[afi] != holddown_count) {
     179           0 :                                 vnc_zlog_debug_verbose(
     180             :                                         "%s: it->holddown_count %d != holddown_count %d",
     181             :                                         __func__, it->holddown_count[afi],
     182             :                                         holddown_count);
     183           0 :                                 assert(0);
     184             :                         }
     185           0 :                         if (it->remote_count[afi] != remote_count) {
     186           0 :                                 vnc_zlog_debug_verbose(
     187             :                                         "%s: it->remote_count %d != remote_count %d",
     188             :                                         __func__, it->remote_count[afi],
     189             :                                         remote_count);
     190           0 :                                 assert(0);
     191             :                         }
     192           0 :                         if (it->imported_count[afi] != imported_count) {
     193           0 :                                 vnc_zlog_debug_verbose(
     194             :                                         "%s: it->imported_count %d != imported_count %d",
     195             :                                         __func__, it->imported_count[afi],
     196             :                                         imported_count);
     197           0 :                                 assert(0);
     198             :                         }
     199             :                 }
     200             :         }
     201           0 : }
     202             : 
     203             : #ifdef DEBUG_ROUTE_COUNTERS
     204             : #define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
     205             : #else
     206             : #define VNC_ITRCCK
     207             : #endif
     208             : 
     209             : /*
     210             :  * Validate reference count for a node in an import table
     211             :  *
     212             :  * Normally lockoffset is 0 for nodes in quiescent state. However,
     213             :  * agg_unlock_node will delete the node if it is called when
     214             :  * node->lock == 1, and we have to validate the refcount before
     215             :  * the node is deleted. In this case, we specify lockoffset 1.
     216             :  */
     217           0 : void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, int lockoffset)
     218             : {
     219           0 :         unsigned int count_bpi = 0;
     220           0 :         unsigned int count_monitor = 0;
     221           0 :         struct bgp_path_info *bpi;
     222           0 :         struct rfapi_monitor_encap *hme;
     223           0 :         struct rfapi_monitor_vpn *hmv;
     224             : 
     225           0 :         for (bpi = rn->info; bpi; bpi = bpi->next)
     226           0 :                 ++count_bpi;
     227             : 
     228             : 
     229           0 :         if (rn->aggregate) {
     230           0 :                 ++count_monitor; /* rfapi_it_extra */
     231             : 
     232           0 :                 switch (safi) {
     233           0 :                         void *cursor;
     234           0 :                         int rc;
     235             : 
     236             :                 case SAFI_ENCAP:
     237           0 :                         for (hme = RFAPI_MONITOR_ENCAP(rn); hme;
     238           0 :                              hme = hme->next)
     239           0 :                                 ++count_monitor;
     240           0 :                         break;
     241             : 
     242             :                 case SAFI_MPLS_VPN:
     243             : 
     244           0 :                         for (hmv = RFAPI_MONITOR_VPN(rn); hmv; hmv = hmv->next)
     245           0 :                                 ++count_monitor;
     246             : 
     247           0 :                         if (RFAPI_MONITOR_EXTERIOR(rn)->source) {
     248           0 :                                 ++count_monitor; /* sl */
     249           0 :                                 cursor = NULL;
     250           0 :                                 for (rc = skiplist_next(
     251             :                                              RFAPI_MONITOR_EXTERIOR(rn)->source,
     252             :                                              NULL, NULL, &cursor);
     253           0 :                                      !rc;
     254           0 :                                      rc = skiplist_next(
     255           0 :                                              RFAPI_MONITOR_EXTERIOR(rn)->source,
     256             :                                              NULL, NULL, &cursor)) {
     257             : 
     258           0 :                                         ++count_monitor; /* sl entry */
     259             :                                 }
     260             :                         }
     261             :                         break;
     262             : 
     263             :                 case SAFI_UNSPEC:
     264             :                 case SAFI_UNICAST:
     265             :                 case SAFI_MULTICAST:
     266             :                 case SAFI_EVPN:
     267             :                 case SAFI_LABELED_UNICAST:
     268             :                 case SAFI_FLOWSPEC:
     269             :                 case SAFI_MAX:
     270           0 :                         assert(!"Passed in safi should be impossible");
     271             :                 }
     272             :         }
     273             : 
     274           0 :         if (count_bpi + count_monitor + lockoffset
     275           0 :             != agg_node_get_lock_count(rn)) {
     276           0 :                 vnc_zlog_debug_verbose(
     277             :                         "%s: count_bpi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
     278             :                         __func__, count_bpi, count_monitor, lockoffset,
     279             :                         agg_node_get_lock_count(rn));
     280           0 :                 assert(0);
     281             :         }
     282           0 : }
     283             : 
     284             : /*
     285             :  * Perform deferred rfapi_close operations that were queued
     286             :  * during callbacks.
     287             :  */
     288           0 : static wq_item_status rfapi_deferred_close_workfunc(struct work_queue *q,
     289             :                                                     void *data)
     290             : {
     291           0 :         struct rfapi_descriptor *rfd = data;
     292           0 :         struct rfapi *h = q->spec.data;
     293             : 
     294           0 :         assert(!(h->flags & RFAPI_INCALLBACK));
     295           0 :         rfapi_close(rfd);
     296           0 :         vnc_zlog_debug_verbose("%s: completed deferred close on handle %p",
     297             :                                __func__, rfd);
     298           0 :         return WQ_SUCCESS;
     299             : }
     300             : 
     301             : /*
     302             :  * Extract layer 2 option from Encap TLVS in BGP attrs
     303             :  */
     304           0 : int rfapiGetL2o(struct attr *attr, struct rfapi_l2address_option *l2o)
     305             : {
     306           0 :         if (attr) {
     307           0 :                 struct bgp_attr_encap_subtlv *pEncap;
     308             : 
     309           0 :                 for (pEncap = bgp_attr_get_vnc_subtlvs(attr); pEncap;
     310           0 :                      pEncap = pEncap->next) {
     311             : 
     312           0 :                         if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) {
     313           0 :                                 if (pEncap->value[0]
     314             :                                     == RFAPI_VN_OPTION_TYPE_L2ADDR) {
     315             : 
     316           0 :                                         if (pEncap->value[1] == 14) {
     317           0 :                                                 memcpy(l2o->macaddr.octet,
     318             :                                                        pEncap->value + 2,
     319             :                                                        ETH_ALEN);
     320           0 :                                                 l2o->label =
     321           0 :                                                         ((pEncap->value[10]
     322             :                                                           >> 4)
     323           0 :                                                          & 0x0f)
     324           0 :                                                         + ((pEncap->value[9]
     325           0 :                                                             << 4)
     326             :                                                            & 0xff0)
     327           0 :                                                         + ((pEncap->value[8]
     328           0 :                                                             << 12)
     329             :                                                            & 0xff000);
     330             : 
     331           0 :                                                 l2o->local_nve_id =
     332           0 :                                                         pEncap->value[12];
     333             : 
     334           0 :                                                 l2o->logical_net_id =
     335           0 :                                                         (pEncap->value[15]
     336           0 :                                                          & 0xff)
     337           0 :                                                         + ((pEncap->value[14]
     338           0 :                                                             << 8)
     339             :                                                            & 0xff00)
     340           0 :                                                         + ((pEncap->value[13]
     341           0 :                                                             << 16)
     342             :                                                            & 0xff0000);
     343             :                                         }
     344             : 
     345           0 :                                         return 0;
     346             :                                 }
     347             :                         }
     348             :                 }
     349             :         }
     350             : 
     351             :         return ENOENT;
     352             : }
     353             : 
     354             : /*
     355             :  * Extract the lifetime from the Tunnel Encap attribute of a route in
     356             :  * an import table
     357             :  */
     358           0 : int rfapiGetVncLifetime(struct attr *attr, uint32_t *lifetime)
     359             : {
     360           0 :         struct bgp_attr_encap_subtlv *pEncap;
     361             : 
     362           0 :         *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */
     363             : 
     364           0 :         if (attr) {
     365             : 
     366           0 :                 for (pEncap = bgp_attr_get_vnc_subtlvs(attr); pEncap;
     367           0 :                      pEncap = pEncap->next) {
     368             : 
     369           0 :                         if (pEncap->type
     370             :                             == BGP_VNC_SUBTLV_TYPE_LIFETIME) { /* lifetime */
     371           0 :                                 if (pEncap->length == 4) {
     372           0 :                                         memcpy(lifetime, pEncap->value, 4);
     373           0 :                                         *lifetime = ntohl(*lifetime);
     374           0 :                                         return 0;
     375             :                                 }
     376             :                         }
     377             :                 }
     378             :         }
     379             : 
     380             :         return ENOENT;
     381             : }
     382             : 
     383             : /*
     384             :  * Look for UN address in Encap attribute
     385             :  */
     386           0 : int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p)
     387             : {
     388           0 :         struct bgp_attr_encap_subtlv *pEncap;
     389           0 :         bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS;/*Default tunnel type*/
     390             : 
     391           0 :         bgp_attr_extcom_tunnel_type(attr, &tun_type);
     392           0 :         if (tun_type == BGP_ENCAP_TYPE_MPLS) {
     393           0 :                 if (!p)
     394             :                         return 0;
     395             :                 /* MPLS carries UN address in next hop */
     396           0 :                 rfapiNexthop2Prefix(attr, p);
     397           0 :                 if (p->family != AF_UNSPEC)
     398             :                         return 0;
     399             : 
     400             :                 return ENOENT;
     401             :         }
     402           0 :         if (attr) {
     403           0 :                 for (pEncap = attr->encap_subtlvs; pEncap;
     404           0 :                      pEncap = pEncap->next) {
     405             : 
     406           0 :                         if (pEncap->type
     407             :                             == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT) { /* un
     408             :                                                                            addr
     409             :                                                                            */
     410           0 :                                 switch (pEncap->length) {
     411           0 :                                 case 8:
     412           0 :                                         if (p) {
     413           0 :                                                 p->family = AF_INET;
     414           0 :                                                 p->prefixlen = IPV4_MAX_BITLEN;
     415           0 :                                                 memcpy(p->u.val, pEncap->value,
     416             :                                                        4);
     417             :                                         }
     418           0 :                                         return 0;
     419             : 
     420           0 :                                 case 20:
     421           0 :                                         if (p) {
     422           0 :                                                 p->family = AF_INET6;
     423           0 :                                                 p->prefixlen = IPV6_MAX_BITLEN;
     424           0 :                                                 memcpy(p->u.val, pEncap->value,
     425             :                                                        16);
     426             :                                         }
     427           0 :                                         return 0;
     428             :                                 }
     429             :                         }
     430             :                 }
     431             :         }
     432             : 
     433             :         return ENOENT;
     434             : }
     435             : 
     436             : /*
     437             :  * Get UN address wherever it might be
     438             :  */
     439           0 : int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p)
     440             : {
     441             :         /* If it's in this route's VNC attribute, we're done */
     442           0 :         if (!rfapiGetVncTunnelUnAddr(bpi->attr, p))
     443             :                 return 0;
     444             :         /*
     445             :          * Otherwise, see if it's cached from a corresponding ENCAP SAFI
     446             :          * advertisement
     447             :          */
     448           0 :         if (bpi->extra) {
     449           0 :                 switch (bpi->extra->vnc.import.un_family) {
     450           0 :                 case AF_INET:
     451           0 :                         if (p) {
     452           0 :                                 p->family = bpi->extra->vnc.import.un_family;
     453           0 :                                 p->u.prefix4 = bpi->extra->vnc.import.un.addr4;
     454           0 :                                 p->prefixlen = IPV4_MAX_BITLEN;
     455             :                         }
     456           0 :                         return 0;
     457           0 :                 case AF_INET6:
     458           0 :                         if (p) {
     459           0 :                                 p->family = bpi->extra->vnc.import.un_family;
     460           0 :                                 p->u.prefix6 = bpi->extra->vnc.import.un.addr6;
     461           0 :                                 p->prefixlen = IPV6_MAX_BITLEN;
     462             :                         }
     463           0 :                         return 0;
     464           0 :                 default:
     465           0 :                         if (p)
     466           0 :                                 p->family = AF_UNSPEC;
     467             : #ifdef DEBUG_ENCAP_MONITOR
     468             :                         vnc_zlog_debug_verbose(
     469             :                                 "%s: bpi->extra->vnc.import.un_family is 0, no UN addr",
     470             :                                 __func__);
     471             : #endif
     472             :                         break;
     473             :                 }
     474             :         }
     475             : 
     476             :         return ENOENT;
     477             : }
     478             : 
     479             : 
     480             : /*
     481             :  * Make a new bgp_path_info from gathered parameters
     482             :  */
     483           0 : static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
     484             :                                                 struct peer *peer, void *rfd,
     485             :                                                 struct prefix_rd *prd,
     486             :                                                 uint8_t type, uint8_t sub_type,
     487             :                                                 uint32_t *label)
     488             : {
     489           0 :         struct bgp_path_info *new;
     490             : 
     491           0 :         new = info_make(type, sub_type, 0, peer, attr, NULL);
     492             : 
     493           0 :         new->attr = bgp_attr_intern(attr);
     494             : 
     495           0 :         bgp_path_info_extra_get(new);
     496           0 :         if (prd) {
     497           0 :                 new->extra->vnc.import.rd = *prd;
     498           0 :                 new->extra->vnc.import.create_time = monotime(NULL);
     499             :         }
     500           0 :         if (label)
     501           0 :                 encode_label(*label, &new->extra->label[0]);
     502             : 
     503           0 :         peer_lock(peer);
     504             : 
     505           0 :         return new;
     506             : }
     507             : 
     508             : /*
     509             :  * Frees bgp_path_info as used in import tables (parts are not
     510             :  * allocated exactly the way they are in the main RIBs)
     511             :  */
     512           0 : static void rfapiBgpInfoFree(struct bgp_path_info *goner)
     513             : {
     514           0 :         if (!goner)
     515             :                 return;
     516             : 
     517           0 :         if (goner->peer) {
     518           0 :                 vnc_zlog_debug_verbose("%s: calling peer_unlock(%p), #%d",
     519             :                                        __func__, goner->peer,
     520             :                                        goner->peer->lock);
     521           0 :                 peer_unlock(goner->peer);
     522             :         }
     523             : 
     524           0 :         bgp_attr_unintern(&goner->attr);
     525             : 
     526           0 :         if (goner->extra)
     527           0 :                 bgp_path_info_extra_free(&goner->extra);
     528           0 :         XFREE(MTYPE_BGP_ROUTE, goner);
     529             : }
     530             : 
     531           0 : struct rfapi_import_table *rfapiMacImportTableGetNoAlloc(struct bgp *bgp,
     532             :                                                          uint32_t lni)
     533             : {
     534           0 :         struct rfapi *h;
     535           0 :         struct rfapi_import_table *it = NULL;
     536           0 :         uintptr_t lni_as_ptr = lni;
     537             : 
     538           0 :         h = bgp->rfapi;
     539           0 :         if (!h)
     540             :                 return NULL;
     541             : 
     542           0 :         if (!h->import_mac)
     543             :                 return NULL;
     544             : 
     545           0 :         if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it))
     546             :                 return NULL;
     547             : 
     548           0 :         return it;
     549             : }
     550             : 
     551           0 : struct rfapi_import_table *rfapiMacImportTableGet(struct bgp *bgp, uint32_t lni)
     552             : {
     553           0 :         struct rfapi *h;
     554           0 :         struct rfapi_import_table *it = NULL;
     555           0 :         uintptr_t lni_as_ptr = lni;
     556             : 
     557           0 :         h = bgp->rfapi;
     558           0 :         assert(h);
     559             : 
     560           0 :         if (!h->import_mac) {
     561             :                 /* default cmp is good enough for LNI */
     562           0 :                 h->import_mac = skiplist_new(0, NULL, NULL);
     563             :         }
     564             : 
     565           0 :         if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it)) {
     566             : 
     567           0 :                 struct ecommunity *enew;
     568           0 :                 struct ecommunity_val eval;
     569           0 :                 afi_t afi;
     570             : 
     571           0 :                 it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
     572             :                              sizeof(struct rfapi_import_table));
     573             :                 /* set RT list of new import table based on LNI */
     574           0 :                 memset((char *)&eval, 0, sizeof(eval));
     575           0 :                 eval.val[0] = 0; /* VNC L2VPN */
     576           0 :                 eval.val[1] = 2; /* VNC L2VPN */
     577           0 :                 eval.val[5] = (lni >> 16) & 0xff;
     578           0 :                 eval.val[6] = (lni >> 8) & 0xff;
     579           0 :                 eval.val[7] = (lni >> 0) & 0xff;
     580             : 
     581           0 :                 enew = ecommunity_new();
     582           0 :                 ecommunity_add_val(enew, &eval, false, false);
     583           0 :                 it->rt_import_list = enew;
     584             : 
     585           0 :                 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
     586           0 :                         it->imported_vpn[afi] = agg_table_init();
     587           0 :                         it->imported_encap[afi] = agg_table_init();
     588             :                 }
     589             : 
     590           0 :                 it->l2_logical_net_id = lni;
     591             : 
     592           0 :                 skiplist_insert(h->import_mac, (void *)lni_as_ptr, it);
     593             :         }
     594             : 
     595           0 :         assert(it);
     596           0 :         return it;
     597             : }
     598             : 
     599             : /*
     600             :  * Implement MONITOR_MOVE_SHORTER(original_node) from
     601             :  * RFAPI-Import-Event-Handling.txt
     602             :  *
     603             :  * Returns pointer to the list of moved monitors
     604             :  */
     605             : static struct rfapi_monitor_vpn *
     606           0 : rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset)
     607             : {
     608           0 :         struct bgp_path_info *bpi;
     609           0 :         struct agg_node *par;
     610           0 :         struct rfapi_monitor_vpn *m;
     611           0 :         struct rfapi_monitor_vpn *mlast;
     612           0 :         struct rfapi_monitor_vpn *moved;
     613           0 :         int movecount = 0;
     614           0 :         int parent_already_refcounted = 0;
     615             : 
     616           0 :         RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN, lockoffset);
     617             : 
     618             : #ifdef DEBUG_MONITOR_MOVE_SHORTER
     619             :         {
     620             :                 vnc_zlog_debug_verbose("%s: called with node pfx=%pFX",
     621             :                                        __func__, &original_vpn_node->p);
     622             :         }
     623             : #endif
     624             : 
     625             :         /*
     626             :          * 1. If there is at least one bpi (either regular route or
     627             :          *    route marked as withdrawn, with a pending timer) at
     628             :          *    original_node with a valid UN address, we're done. Return.
     629             :          */
     630           0 :         for (bpi = original_vpn_node->info; bpi; bpi = bpi->next) {
     631           0 :                 struct prefix pfx;
     632             : 
     633           0 :                 if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx)) {
     634             : #ifdef DEBUG_MONITOR_MOVE_SHORTER
     635             :                         vnc_zlog_debug_verbose(
     636             :                                 "%s: have valid UN at original node, no change",
     637             :                                 __func__);
     638             : #endif
     639           0 :                         return NULL;
     640             :                 }
     641             :         }
     642             : 
     643             :         /*
     644             :          * 2. Travel up the tree (toward less-specific prefixes) from
     645             :          *    original_node to find the first node that has at least
     646             :          *    one route (even if it is only a withdrawn route) with a
     647             :          *    valid UN address. Call this node "Node P."
     648             :          */
     649           0 :         for (par = agg_node_parent(original_vpn_node); par;
     650           0 :              par = agg_node_parent(par)) {
     651           0 :                 for (bpi = par->info; bpi; bpi = bpi->next) {
     652           0 :                         struct prefix pfx;
     653           0 :                         if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx)) {
     654             :                                 break;
     655             :                         }
     656             :                 }
     657           0 :                 if (bpi)
     658             :                         break;
     659             :         }
     660             : 
     661           0 :         if (par) {
     662           0 :                 RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 0);
     663             :         }
     664             : 
     665             :         /*
     666             :          * If no less-specific routes, try to use the 0/0 node
     667             :          */
     668           0 :         if (!par) {
     669           0 :                 const struct prefix *p;
     670             :                 /* this isn't necessarily 0/0 */
     671           0 :                 par = agg_route_table_top(original_vpn_node);
     672             : 
     673           0 :                 if (par)
     674           0 :                         p = agg_node_get_prefix(par);
     675             :                 /*
     676             :                  * If we got the top node but it wasn't 0/0,
     677             :                  * ignore it
     678             :                  */
     679           0 :                 if (par && p->prefixlen) {
     680           0 :                         agg_unlock_node(par); /* maybe free */
     681           0 :                         par = NULL;
     682             :                 }
     683             : 
     684           0 :                 if (par) {
     685             :                         ++parent_already_refcounted;
     686             :                 }
     687             :         }
     688             : 
     689             :         /*
     690             :          * Create 0/0 node if it isn't there
     691             :          */
     692           0 :         if (!par) {
     693           0 :                 struct prefix pfx_default;
     694           0 :                 const struct prefix *p = agg_node_get_prefix(original_vpn_node);
     695             : 
     696           0 :                 memset(&pfx_default, 0, sizeof(pfx_default));
     697           0 :                 pfx_default.family = p->family;
     698             : 
     699             :                 /* creates default node if none exists */
     700           0 :                 par = agg_node_get(agg_get_table(original_vpn_node),
     701             :                                    &pfx_default);
     702           0 :                 ++parent_already_refcounted;
     703             :         }
     704             : 
     705             :         /*
     706             :          * 3. Move each of the monitors found at original_node to Node P.
     707             :          *    These are "Moved Monitors."
     708             :          *
     709             :          */
     710             : 
     711             :         /*
     712             :          * Attach at end so that the list pointer we return points
     713             :          * only to the moved routes
     714             :          */
     715           0 :         for (m = RFAPI_MONITOR_VPN(par), mlast = NULL; m;
     716           0 :              mlast = m, m = m->next)
     717             :                 ;
     718             : 
     719           0 :         if (mlast) {
     720           0 :                 moved = mlast->next = RFAPI_MONITOR_VPN(original_vpn_node);
     721             :         } else {
     722           0 :                 moved = RFAPI_MONITOR_VPN_W_ALLOC(par) =
     723           0 :                         RFAPI_MONITOR_VPN(original_vpn_node);
     724             :         }
     725           0 :         if (RFAPI_MONITOR_VPN(
     726             :                     original_vpn_node)) /* check agg, so not allocated */
     727           0 :                 RFAPI_MONITOR_VPN_W_ALLOC(original_vpn_node) = NULL;
     728             : 
     729             :         /*
     730             :          * update the node pointers on the monitors
     731             :          */
     732           0 :         for (m = moved; m; m = m->next) {
     733           0 :                 ++movecount;
     734           0 :                 m->node = par;
     735             :         }
     736             : 
     737             :         RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN,
     738             :                              parent_already_refcounted - movecount);
     739           0 :         while (movecount > parent_already_refcounted) {
     740           0 :                 agg_lock_node(par);
     741           0 :                 ++parent_already_refcounted;
     742             :         }
     743           0 :         while (movecount < parent_already_refcounted) {
     744             :                 /* unlikely, but code defensively */
     745           0 :                 agg_unlock_node(par);
     746           0 :                 --parent_already_refcounted;
     747             :         }
     748             :         RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN,
     749             :                              movecount + lockoffset);
     750           0 :         while (movecount--) {
     751           0 :                 agg_unlock_node(original_vpn_node);
     752             :         }
     753             : 
     754             : #ifdef DEBUG_MONITOR_MOVE_SHORTER
     755             :         {
     756             :                 vnc_zlog_debug_verbose("%s: moved to node pfx=%pFX", __func__,
     757             :                                        &par->p);
     758             :         }
     759             : #endif
     760             : 
     761             : 
     762             :         return moved;
     763             : }
     764             : 
     765             : /*
     766             :  * Implement MONITOR_MOVE_LONGER(new_node) from
     767             :  * RFAPI-Import-Event-Handling.txt
     768             :  */
     769           0 : static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node)
     770             : {
     771           0 :         struct rfapi_monitor_vpn *monitor;
     772           0 :         struct rfapi_monitor_vpn *mlast;
     773           0 :         struct bgp_path_info *bpi;
     774           0 :         struct agg_node *par;
     775           0 :         const struct prefix *new_vpn_node_p = agg_node_get_prefix(new_vpn_node);
     776             : 
     777           0 :         RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
     778             : 
     779             :         /*
     780             :          * Make sure we have at least one valid route at the new node
     781             :          */
     782           0 :         for (bpi = new_vpn_node->info; bpi; bpi = bpi->next) {
     783           0 :                 struct prefix pfx;
     784           0 :                 if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx))
     785             :                         break;
     786             :         }
     787             : 
     788           0 :         if (!bpi) {
     789           0 :                 vnc_zlog_debug_verbose(
     790             :                         "%s: no valid routes at node %p, so not attempting moves",
     791             :                         __func__, new_vpn_node);
     792           0 :                 return;
     793             :         }
     794             : 
     795             :         /*
     796             :          * Find first parent node that has monitors
     797             :          */
     798           0 :         for (par = agg_node_parent(new_vpn_node); par;
     799           0 :              par = agg_node_parent(par)) {
     800           0 :                 if (RFAPI_MONITOR_VPN(par))
     801             :                         break;
     802             :         }
     803             : 
     804           0 :         if (!par) {
     805           0 :                 vnc_zlog_debug_verbose(
     806             :                         "%s: no parent nodes with monitors, done", __func__);
     807           0 :                 return;
     808             :         }
     809             : 
     810             :         /*
     811             :          * Check each of these monitors to see of their longest-match
     812             :          * is now the updated node. Move any such monitors to the more-
     813             :          * specific updated node
     814             :          */
     815           0 :         for (mlast = NULL, monitor = RFAPI_MONITOR_VPN(par); monitor;) {
     816             :                 /*
     817             :                  * If new longest match for monitor prefix is the new
     818             :                  * route's prefix, move monitor to new route's prefix
     819             :                  */
     820           0 :                 if (prefix_match(new_vpn_node_p, &monitor->p)) {
     821             :                         /* detach */
     822           0 :                         if (mlast) {
     823           0 :                                 mlast->next = monitor->next;
     824             :                         } else {
     825           0 :                                 RFAPI_MONITOR_VPN_W_ALLOC(par) = monitor->next;
     826             :                         }
     827             : 
     828             : 
     829             :                         /* attach */
     830           0 :                         monitor->next = RFAPI_MONITOR_VPN(new_vpn_node);
     831           0 :                         RFAPI_MONITOR_VPN_W_ALLOC(new_vpn_node) = monitor;
     832           0 :                         monitor->node = new_vpn_node;
     833             : 
     834           0 :                         agg_lock_node(new_vpn_node); /* incr refcount */
     835             : 
     836           0 :                         monitor = mlast ? mlast->next : RFAPI_MONITOR_VPN(par);
     837             : 
     838           0 :                         RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 1);
     839             :                         /* decr refcount after we're done with par as this might
     840             :                          * free it */
     841           0 :                         agg_unlock_node(par);
     842             : 
     843           0 :                         continue;
     844             :                 }
     845           0 :                 mlast = monitor;
     846           0 :                 monitor = monitor->next;
     847             :         }
     848             : 
     849           0 :         RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
     850             : }
     851             : 
     852             : 
     853           0 : static void rfapiBgpInfoChainFree(struct bgp_path_info *bpi)
     854             : {
     855           0 :         struct bgp_path_info *next;
     856             : 
     857           0 :         while (bpi) {
     858             : 
     859             :                 /*
     860             :                  * If there is a timer waiting to delete this bpi, cancel
     861             :                  * the timer and delete immediately
     862             :                  */
     863           0 :                 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
     864           0 :                     && bpi->extra->vnc.import.timer) {
     865           0 :                         struct rfapi_withdraw *wcb =
     866             :                                 THREAD_ARG(bpi->extra->vnc.import.timer);
     867             : 
     868           0 :                         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
     869           0 :                         THREAD_OFF(bpi->extra->vnc.import.timer);
     870             :                 }
     871             : 
     872           0 :                 next = bpi->next;
     873           0 :                 bpi->next = NULL;
     874           0 :                 rfapiBgpInfoFree(bpi);
     875           0 :                 bpi = next;
     876             :         }
     877           0 : }
     878             : 
     879           0 : static void rfapiImportTableFlush(struct rfapi_import_table *it)
     880             : {
     881           0 :         afi_t afi;
     882             : 
     883             :         /*
     884             :          * Free ecommunity
     885             :          */
     886           0 :         ecommunity_free(&it->rt_import_list);
     887           0 :         it->rt_import_list = NULL;
     888             : 
     889           0 :         for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
     890             : 
     891           0 :                 struct agg_node *rn;
     892             : 
     893           0 :                 for (rn = agg_route_top(it->imported_vpn[afi]); rn;
     894           0 :                      rn = agg_route_next(rn)) {
     895             :                         /*
     896             :                          * Each route_node has:
     897             :                          * aggregate: points to rfapi_it_extra with monitor
     898             :                          * chain(s)
     899             :                          * info: points to chain of bgp_path_info
     900             :                          */
     901             :                         /* free bgp_path_info and its children */
     902           0 :                         rfapiBgpInfoChainFree(rn->info);
     903           0 :                         rn->info = NULL;
     904             : 
     905           0 :                         rfapiMonitorExtraFlush(SAFI_MPLS_VPN, rn);
     906             :                 }
     907             : 
     908           0 :                 for (rn = agg_route_top(it->imported_encap[afi]); rn;
     909           0 :                      rn = agg_route_next(rn)) {
     910             :                         /* free bgp_path_info and its children */
     911           0 :                         rfapiBgpInfoChainFree(rn->info);
     912           0 :                         rn->info = NULL;
     913             : 
     914           0 :                         rfapiMonitorExtraFlush(SAFI_ENCAP, rn);
     915             :                 }
     916             : 
     917           0 :                 agg_table_finish(it->imported_vpn[afi]);
     918           0 :                 agg_table_finish(it->imported_encap[afi]);
     919             :         }
     920           0 :         if (it->monitor_exterior_orphans) {
     921           0 :                 skiplist_free(it->monitor_exterior_orphans);
     922             :         }
     923           0 : }
     924             : 
     925           0 : void rfapiImportTableRefDelByIt(struct bgp *bgp,
     926             :                                 struct rfapi_import_table *it_target)
     927             : {
     928           0 :         struct rfapi *h;
     929           0 :         struct rfapi_import_table *it;
     930           0 :         struct rfapi_import_table *prev = NULL;
     931             : 
     932           0 :         assert(it_target);
     933             : 
     934           0 :         h = bgp->rfapi;
     935           0 :         assert(h);
     936             : 
     937           0 :         for (it = h->imports; it; prev = it, it = it->next) {
     938           0 :                 if (it == it_target)
     939             :                         break;
     940             :         }
     941             : 
     942           0 :         assert(it);
     943           0 :         assert(it->refcount);
     944             : 
     945           0 :         it->refcount -= 1;
     946             : 
     947           0 :         if (!it->refcount) {
     948           0 :                 if (prev) {
     949           0 :                         prev->next = it->next;
     950             :                 } else {
     951           0 :                         h->imports = it->next;
     952             :                 }
     953           0 :                 rfapiImportTableFlush(it);
     954           0 :                 XFREE(MTYPE_RFAPI_IMPORTTABLE, it);
     955             :         }
     956           0 : }
     957             : 
     958             : #ifdef RFAPI_REQUIRE_ENCAP_BEEC
     959             : /*
     960             :  * Look for magic BGP Encapsulation Extended Community value
     961             :  * Format in RFC 5512 Sect. 4.5
     962             :  */
     963             : static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom,
     964             :                                       bgp_encap_types type)
     965             : {
     966             :         int i;
     967             : 
     968             :         if (!ecom)
     969             :                 return 0;
     970             : 
     971             :         for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) {
     972             : 
     973             :                 uint8_t *ep;
     974             : 
     975             :                 ep = ecom->val + i;
     976             : 
     977             :                 if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE
     978             :                     && ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
     979             :                     && ep[6] == ((type && 0xff00) >> 8)
     980             :                     && ep[7] == (type & 0xff)) {
     981             : 
     982             :                         return 1;
     983             :                 }
     984             :         }
     985             :         return 0;
     986             : }
     987             : #endif
     988             : 
     989           0 : int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
     990             : {
     991           0 :         uint32_t i, j;
     992             : 
     993           0 :         if (!e1 || !e2)
     994             :                 return 0;
     995             : 
     996             :         {
     997           0 :                 char *s1, *s2;
     998           0 :                 s1 = ecommunity_ecom2str(e1, ECOMMUNITY_FORMAT_DISPLAY, 0);
     999           0 :                 s2 = ecommunity_ecom2str(e2, ECOMMUNITY_FORMAT_DISPLAY, 0);
    1000           0 :                 vnc_zlog_debug_verbose("%s: e1[%s], e2[%s]", __func__, s1, s2);
    1001           0 :                 XFREE(MTYPE_ECOMMUNITY_STR, s1);
    1002           0 :                 XFREE(MTYPE_ECOMMUNITY_STR, s2);
    1003             :         }
    1004             : 
    1005           0 :         for (i = 0; i < e1->size; ++i) {
    1006           0 :                 for (j = 0; j < e2->size; ++j) {
    1007           0 :                         if (!memcmp(e1->val + (i * ECOMMUNITY_SIZE),
    1008           0 :                                     e2->val + (j * ECOMMUNITY_SIZE),
    1009             :                                     ECOMMUNITY_SIZE)) {
    1010             : 
    1011             :                                 return 1;
    1012             :                         }
    1013             :                 }
    1014             :         }
    1015             :         return 0;
    1016             : }
    1017             : 
    1018           0 : int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni)
    1019             : {
    1020           0 :         if (ecom) {
    1021             :                 uint32_t i;
    1022             : 
    1023           0 :                 for (i = 0; i < ecom->size; ++i) {
    1024           0 :                         uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
    1025             : 
    1026           0 :                         if ((*(p + 0) == 0x00) && (*(p + 1) == 0x02)) {
    1027             : 
    1028           0 :                                 *lni = (*(p + 5) << 16) | (*(p + 6) << 8)
    1029           0 :                                        | (*(p + 7));
    1030           0 :                                 return 0;
    1031             :                         }
    1032             :                 }
    1033             :         }
    1034             :         return ENOENT;
    1035             : }
    1036             : 
    1037           0 : int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
    1038             : {
    1039           0 :         struct bgp *bgp = bgp_get_default();
    1040           0 :         *tag_id = 0; /* default to untagged */
    1041           0 :         if (ecom) {
    1042             :                 uint32_t i;
    1043             : 
    1044           0 :                 for (i = 0; i < ecom->size; ++i) {
    1045           0 :                         as_t as = 0;
    1046           0 :                         int encode = 0;
    1047           0 :                         const uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
    1048             : 
    1049             :                         /* High-order octet of type. */
    1050           0 :                         encode = *p++;
    1051             : 
    1052           0 :                         if (*p++ == ECOMMUNITY_ROUTE_TARGET) {
    1053           0 :                                 if (encode == ECOMMUNITY_ENCODE_AS4) {
    1054           0 :                                         p = ptr_get_be32(p, &as);
    1055           0 :                                 } else if (encode == ECOMMUNITY_ENCODE_AS) {
    1056           0 :                                         as = (*p++ << 8);
    1057           0 :                                         as |= (*p++);
    1058           0 :                                         p += 2; /* skip next two, tag/vid
    1059             :                                                    always in lowest bytes */
    1060             :                                 }
    1061           0 :                                 if (as == bgp->as) {
    1062           0 :                                         *tag_id = *p++ << 8;
    1063           0 :                                         *tag_id |= (*p++);
    1064           0 :                                         return 0;
    1065             :                                 }
    1066             :                         }
    1067             :                 }
    1068             :         }
    1069             :         return ENOENT;
    1070             : }
    1071             : 
    1072           0 : static int rfapiVpnBiNhEqualsPt(struct bgp_path_info *bpi,
    1073             :                                 struct rfapi_ip_addr *hpt)
    1074             : {
    1075           0 :         uint8_t family;
    1076             : 
    1077           0 :         if (!hpt || !bpi)
    1078             :                 return 0;
    1079             : 
    1080           0 :         family = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len);
    1081             : 
    1082           0 :         if (hpt->addr_family != family)
    1083             :                 return 0;
    1084             : 
    1085           0 :         switch (family) {
    1086           0 :         case AF_INET:
    1087           0 :                 if (bpi->attr->mp_nexthop_global_in.s_addr
    1088           0 :                     != hpt->addr.v4.s_addr)
    1089           0 :                         return 0;
    1090             :                 break;
    1091             : 
    1092           0 :         case AF_INET6:
    1093           0 :                 if (IPV6_ADDR_CMP(&bpi->attr->mp_nexthop_global, &hpt->addr.v6))
    1094           0 :                         return 0;
    1095             :                 break;
    1096             : 
    1097             :         default:
    1098             :                 return 0;
    1099             :         }
    1100             : 
    1101             :         return 1;
    1102             : }
    1103             : 
    1104             : 
    1105             : /*
    1106             :  * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
    1107             :  */
    1108           0 : static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
    1109             :                               struct bgp_path_info *bpi2)
    1110             : {
    1111           0 :         struct prefix pfx_un1;
    1112           0 :         struct prefix pfx_un2;
    1113             : 
    1114           0 :         if (!bpi1 || !bpi2)
    1115             :                 return 0;
    1116             : 
    1117             :         /*
    1118             :          * VN address comparisons
    1119             :          */
    1120             : 
    1121           0 :         if (BGP_MP_NEXTHOP_FAMILY(bpi1->attr->mp_nexthop_len)
    1122           0 :             != BGP_MP_NEXTHOP_FAMILY(bpi2->attr->mp_nexthop_len)) {
    1123             :                 return 0;
    1124             :         }
    1125             : 
    1126           0 :         switch (BGP_MP_NEXTHOP_FAMILY(bpi1->attr->mp_nexthop_len)) {
    1127             :         case AF_INET:
    1128           0 :                 if (bpi1->attr->mp_nexthop_global_in.s_addr
    1129           0 :                     != bpi2->attr->mp_nexthop_global_in.s_addr)
    1130             :                         return 0;
    1131             :                 break;
    1132             : 
    1133           0 :         case AF_INET6:
    1134           0 :                 if (IPV6_ADDR_CMP(&bpi1->attr->mp_nexthop_global,
    1135             :                                   &bpi2->attr->mp_nexthop_global))
    1136             :                         return 0;
    1137             :                 break;
    1138             : 
    1139             :         default:
    1140             :                 return 0;
    1141             :         }
    1142             : 
    1143           0 :         memset(&pfx_un1, 0, sizeof(pfx_un1));
    1144           0 :         memset(&pfx_un2, 0, sizeof(pfx_un2));
    1145             : 
    1146             :         /*
    1147             :          * UN address comparisons
    1148             :          */
    1149           0 :         if (rfapiGetVncTunnelUnAddr(bpi1->attr, &pfx_un1)) {
    1150           0 :                 if (bpi1->extra) {
    1151           0 :                         pfx_un1.family = bpi1->extra->vnc.import.un_family;
    1152           0 :                         switch (bpi1->extra->vnc.import.un_family) {
    1153           0 :                         case AF_INET:
    1154           0 :                                 pfx_un1.u.prefix4 =
    1155             :                                         bpi1->extra->vnc.import.un.addr4;
    1156           0 :                                 break;
    1157           0 :                         case AF_INET6:
    1158           0 :                                 pfx_un1.u.prefix6 =
    1159             :                                         bpi1->extra->vnc.import.un.addr6;
    1160           0 :                                 break;
    1161           0 :                         default:
    1162           0 :                                 pfx_un1.family = AF_UNSPEC;
    1163           0 :                                 break;
    1164             :                         }
    1165             :                 }
    1166             :         }
    1167             : 
    1168           0 :         if (rfapiGetVncTunnelUnAddr(bpi2->attr, &pfx_un2)) {
    1169           0 :                 if (bpi2->extra) {
    1170           0 :                         pfx_un2.family = bpi2->extra->vnc.import.un_family;
    1171           0 :                         switch (bpi2->extra->vnc.import.un_family) {
    1172           0 :                         case AF_INET:
    1173           0 :                                 pfx_un2.u.prefix4 =
    1174             :                                         bpi2->extra->vnc.import.un.addr4;
    1175           0 :                                 break;
    1176           0 :                         case AF_INET6:
    1177           0 :                                 pfx_un2.u.prefix6 =
    1178             :                                         bpi2->extra->vnc.import.un.addr6;
    1179           0 :                                 break;
    1180           0 :                         default:
    1181           0 :                                 pfx_un2.family = AF_UNSPEC;
    1182           0 :                                 break;
    1183             :                         }
    1184             :                 }
    1185             :         }
    1186             : 
    1187           0 :         if (pfx_un1.family == AF_UNSPEC || pfx_un2.family == AF_UNSPEC)
    1188             :                 return 0;
    1189             : 
    1190           0 :         if (pfx_un1.family != pfx_un2.family)
    1191             :                 return 0;
    1192             : 
    1193           0 :         switch (pfx_un1.family) {
    1194             :         case AF_INET:
    1195           0 :                 if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4, &pfx_un2.u.prefix4))
    1196             :                         return 0;
    1197             :                 break;
    1198           0 :         case AF_INET6:
    1199           0 :                 if (!IPV6_ADDR_SAME(&pfx_un1.u.prefix6, &pfx_un2.u.prefix6))
    1200             :                         return 0;
    1201             :                 break;
    1202             :         }
    1203             : 
    1204             : 
    1205             :         return 1;
    1206             : }
    1207             : 
    1208           0 : uint8_t rfapiRfpCost(struct attr *attr)
    1209             : {
    1210           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
    1211           0 :                 if (attr->local_pref > 255) {
    1212             :                         return 0;
    1213             :                 }
    1214           0 :                 return 255 - attr->local_pref;
    1215             :         }
    1216             : 
    1217             :         return 255;
    1218             : }
    1219             : 
    1220             : /*------------------------------------------
    1221             :  * rfapi_extract_l2o
    1222             :  *
    1223             :  * Find Layer 2 options in an option chain
    1224             :  *
    1225             :  * input:
    1226             :  *      pHop            option chain
    1227             :  *
    1228             :  * output:
    1229             :  *      l2o             layer 2 options extracted
    1230             :  *
    1231             :  * return value:
    1232             :  *      0               OK
    1233             :  *      1               no options found
    1234             :  *
    1235             :  --------------------------------------------*/
    1236           0 : int rfapi_extract_l2o(
    1237             :         struct bgp_tea_options *pHop,       /* chain of options */
    1238             :         struct rfapi_l2address_option *l2o) /* return extracted value */
    1239             : {
    1240           0 :         struct bgp_tea_options *p;
    1241             : 
    1242           0 :         for (p = pHop; p; p = p->next) {
    1243           0 :                 if ((p->type == RFAPI_VN_OPTION_TYPE_L2ADDR)
    1244           0 :                     && (p->length >= 8)) {
    1245             : 
    1246           0 :                         char *v = p->value;
    1247             : 
    1248           0 :                         memcpy(&l2o->macaddr, v, 6);
    1249             : 
    1250           0 :                         l2o->label = ((v[6] << 12) & 0xff000)
    1251           0 :                                      + ((v[7] << 4) & 0xff0)
    1252           0 :                                      + ((v[8] >> 4) & 0xf);
    1253             : 
    1254           0 :                         l2o->local_nve_id = (uint8_t)v[10];
    1255             : 
    1256           0 :                         l2o->logical_net_id =
    1257           0 :                                 (v[11] << 16) + (v[12] << 8) + (v[13] << 0);
    1258             : 
    1259           0 :                         return 0;
    1260             :                 }
    1261             :         }
    1262             :         return 1;
    1263             : }
    1264             : 
    1265             : static struct rfapi_next_hop_entry *
    1266           0 : rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
    1267             :                             struct bgp_path_info *bpi, /* route to encode */
    1268             :                             uint32_t lifetime,   /* use this in nhe */
    1269             :                             struct agg_node *rn)       /* req for L2 eth addr */
    1270             : {
    1271           0 :         struct rfapi_next_hop_entry *new;
    1272           0 :         int have_vnc_tunnel_un = 0;
    1273           0 :         const struct prefix *p = agg_node_get_prefix(rn);
    1274             : 
    1275             : #ifdef DEBUG_ENCAP_MONITOR
    1276             :         vnc_zlog_debug_verbose("%s: entry, bpi %p, rn %p", __func__, bpi, rn);
    1277             : #endif
    1278             : 
    1279           0 :         new = XCALLOC(MTYPE_RFAPI_NEXTHOP, sizeof(struct rfapi_next_hop_entry));
    1280             : 
    1281           0 :         new->prefix = *rprefix;
    1282             : 
    1283           0 :         if (bpi->extra
    1284           0 :             && decode_rd_type(bpi->extra->vnc.import.rd.val)
    1285             :                        == RD_TYPE_VNC_ETH) {
    1286             :                 /* ethernet */
    1287             : 
    1288           0 :                 struct rfapi_vn_option *vo;
    1289             : 
    1290           0 :                 vo = XCALLOC(MTYPE_RFAPI_VN_OPTION,
    1291             :                              sizeof(struct rfapi_vn_option));
    1292             : 
    1293           0 :                 vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
    1294             : 
    1295           0 :                 memcpy(&vo->v.l2addr.macaddr, &p->u.prefix_eth.octet, ETH_ALEN);
    1296             :                 /* only low 3 bytes of this are significant */
    1297           0 :                 (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr),
    1298             :                                             &vo->v.l2addr.logical_net_id);
    1299           0 :                 (void)rfapiEcommunityGetEthernetTag(
    1300           0 :                         bgp_attr_get_ecommunity(bpi->attr),
    1301             :                         &vo->v.l2addr.tag_id);
    1302             : 
    1303             :                 /* local_nve_id comes from lower byte of RD type */
    1304           0 :                 vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1];
    1305             : 
    1306             :                 /* label comes from MP_REACH_NLRI label */
    1307           0 :                 vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
    1308             : 
    1309           0 :                 new->vn_options = vo;
    1310             : 
    1311             :                 /*
    1312             :                  * If there is an auxiliary prefix (i.e., host IP address),
    1313             :                  * use it as the nexthop prefix instead of the query prefix
    1314             :                  */
    1315           0 :                 if (bpi->extra->vnc.import.aux_prefix.family) {
    1316           0 :                         rfapiQprefix2Rprefix(&bpi->extra->vnc.import.aux_prefix,
    1317             :                                              &new->prefix);
    1318             :                 }
    1319             :         }
    1320             : 
    1321           0 :         bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/
    1322           0 :         new->prefix.cost = rfapiRfpCost(bpi->attr);
    1323             : 
    1324           0 :         struct bgp_attr_encap_subtlv *pEncap;
    1325             : 
    1326           0 :         switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) {
    1327             :         case AF_INET:
    1328           0 :                 new->vn_address.addr_family = AF_INET;
    1329           0 :                 new->vn_address.addr.v4 = bpi->attr->mp_nexthop_global_in;
    1330           0 :                 break;
    1331             : 
    1332           0 :         case AF_INET6:
    1333           0 :                 new->vn_address.addr_family = AF_INET6;
    1334           0 :                 new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global;
    1335           0 :                 break;
    1336             : 
    1337             :         default:
    1338           0 :                 zlog_warn("%s: invalid vpn nexthop length: %d", __func__,
    1339             :                           bpi->attr->mp_nexthop_len);
    1340           0 :                 rfapi_free_next_hop_list(new);
    1341           0 :                 return NULL;
    1342             :         }
    1343             : 
    1344           0 :         for (pEncap = bgp_attr_get_vnc_subtlvs(bpi->attr); pEncap;
    1345           0 :              pEncap = pEncap->next) {
    1346           0 :                 switch (pEncap->type) {
    1347             :                 case BGP_VNC_SUBTLV_TYPE_LIFETIME:
    1348             :                         /* use configured lifetime, not attr lifetime */
    1349             :                         break;
    1350             : 
    1351           0 :                 default:
    1352           0 :                         zlog_warn("%s: unknown VNC option type %d", __func__,
    1353             :                                   pEncap->type);
    1354             : 
    1355           0 :                         break;
    1356             :                 }
    1357             :         }
    1358             : 
    1359           0 :         bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
    1360           0 :         if (tun_type == BGP_ENCAP_TYPE_MPLS) {
    1361           0 :                 struct prefix p;
    1362             :                 /* MPLS carries UN address in next hop */
    1363           0 :                 rfapiNexthop2Prefix(bpi->attr, &p);
    1364           0 :                 if (p.family != AF_UNSPEC) {
    1365           0 :                         rfapiQprefix2Raddr(&p, &new->un_address);
    1366           0 :                         have_vnc_tunnel_un = 1;
    1367             :                 }
    1368             :         }
    1369             : 
    1370           0 :         for (pEncap = bpi->attr->encap_subtlvs; pEncap; pEncap = pEncap->next) {
    1371           0 :                 switch (pEncap->type) {
    1372           0 :                 case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
    1373             :                         /*
    1374             :                          * Overrides ENCAP UN address, if any
    1375             :                          */
    1376           0 :                         switch (pEncap->length) {
    1377             : 
    1378           0 :                         case 8:
    1379           0 :                                 new->un_address.addr_family = AF_INET;
    1380           0 :                                 memcpy(&new->un_address.addr.v4, pEncap->value,
    1381             :                                        4);
    1382           0 :                                 have_vnc_tunnel_un = 1;
    1383           0 :                                 break;
    1384             : 
    1385           0 :                         case 20:
    1386           0 :                                 new->un_address.addr_family = AF_INET6;
    1387           0 :                                 memcpy(&new->un_address.addr.v6, pEncap->value,
    1388             :                                        16);
    1389           0 :                                 have_vnc_tunnel_un = 1;
    1390           0 :                                 break;
    1391             : 
    1392           0 :                         default:
    1393           0 :                                 zlog_warn(
    1394             :                                         "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p",
    1395             :                                         __func__, pEncap->length, bpi);
    1396             :                         }
    1397             :                         break;
    1398             : 
    1399           0 :                 default:
    1400           0 :                         zlog_warn("%s: unknown Encap Attribute option type %d",
    1401             :                                   __func__, pEncap->type);
    1402           0 :                         break;
    1403             :                 }
    1404             :         }
    1405             : 
    1406           0 :         new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr);
    1407             : 
    1408             : #ifdef DEBUG_ENCAP_MONITOR
    1409             :         vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", __func__,
    1410             :                                __LINE__, have_vnc_tunnel_un);
    1411             : #endif
    1412             : 
    1413           0 :         if (!have_vnc_tunnel_un && bpi->extra) {
    1414             :                 /*
    1415             :                  * use cached UN address from ENCAP route
    1416             :                  */
    1417           0 :                 new->un_address.addr_family = bpi->extra->vnc.import.un_family;
    1418           0 :                 switch (new->un_address.addr_family) {
    1419           0 :                 case AF_INET:
    1420           0 :                         new->un_address.addr.v4 =
    1421             :                                 bpi->extra->vnc.import.un.addr4;
    1422           0 :                         break;
    1423           0 :                 case AF_INET6:
    1424           0 :                         new->un_address.addr.v6 =
    1425             :                                 bpi->extra->vnc.import.un.addr6;
    1426           0 :                         break;
    1427           0 :                 default:
    1428           0 :                         zlog_warn("%s: invalid UN addr family (%d) for bpi %p",
    1429             :                                   __func__, new->un_address.addr_family, bpi);
    1430           0 :                         rfapi_free_next_hop_list(new);
    1431           0 :                         return NULL;
    1432             :                 }
    1433             :         }
    1434             : 
    1435           0 :         new->lifetime = lifetime;
    1436           0 :         return new;
    1437             : }
    1438             : 
    1439           0 : int rfapiHasNonRemovedRoutes(struct agg_node *rn)
    1440             : {
    1441           0 :         struct bgp_path_info *bpi;
    1442             : 
    1443           0 :         for (bpi = rn->info; bpi; bpi = bpi->next) {
    1444           0 :                 struct prefix pfx;
    1445             : 
    1446           0 :                 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
    1447           0 :                     && (bpi->extra && !rfapiGetUnAddrOfVpnBi(bpi, &pfx))) {
    1448             : 
    1449           0 :                         return 1;
    1450             :                 }
    1451             :         }
    1452             :         return 0;
    1453             : }
    1454             : 
    1455             : #ifdef DEBUG_IT_NODES
    1456             : /*
    1457             :  * DEBUG FUNCTION
    1458             :  */
    1459             : void rfapiDumpNode(struct agg_node *rn)
    1460             : {
    1461             :         struct bgp_path_info *bpi;
    1462             : 
    1463             :         vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn);
    1464             :         for (bpi = rn->info; bpi; bpi = bpi->next) {
    1465             :                 struct prefix pfx;
    1466             :                 int ctrc = rfapiGetUnAddrOfVpnBi(bpi, &pfx);
    1467             :                 int nr;
    1468             : 
    1469             :                 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
    1470             :                     && (bpi->extra && !ctrc)) {
    1471             : 
    1472             :                         nr = 1;
    1473             :                 } else {
    1474             :                         nr = 0;
    1475             :                 }
    1476             : 
    1477             :                 vnc_zlog_debug_verbose(
    1478             :                         "  bpi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d", bpi,
    1479             :                         nr, bpi->flags, bpi->extra, ctrc);
    1480             :         }
    1481             : }
    1482             : #endif
    1483             : 
    1484           0 : static int rfapiNhlAddNodeRoutes(
    1485             :         struct agg_node *rn,                  /* in */
    1486             :         struct rfapi_ip_prefix *rprefix,      /* in */
    1487             :         uint32_t lifetime,                    /* in */
    1488             :         int removed,                          /* in */
    1489             :         struct rfapi_next_hop_entry **head,   /* in/out */
    1490             :         struct rfapi_next_hop_entry **tail,   /* in/out */
    1491             :         struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
    1492             :         struct agg_node *rfd_rib_node,  /* preload this NVE rib node */
    1493             :         struct prefix *pfx_target_original)   /* query target */
    1494             : {
    1495           0 :         struct bgp_path_info *bpi;
    1496           0 :         struct rfapi_next_hop_entry *new;
    1497           0 :         struct prefix pfx_un;
    1498           0 :         struct skiplist *seen_nexthops;
    1499           0 :         int count = 0;
    1500           0 :         const struct prefix *p = agg_node_get_prefix(rn);
    1501           0 :         int is_l2 = (p->family == AF_ETHERNET);
    1502             : 
    1503           0 :         if (rfd_rib_node) {
    1504           0 :                 struct agg_table *atable = agg_get_table(rfd_rib_node);
    1505           0 :                 struct rfapi_descriptor *rfd;
    1506             : 
    1507           0 :                 if (atable) {
    1508           0 :                         rfd = agg_get_table_info(atable);
    1509             : 
    1510           0 :                         if (rfapiRibFTDFilterRecentPrefix(rfd, rn,
    1511             :                                                           pfx_target_original))
    1512             :                                 return 0;
    1513             :                 }
    1514             :         }
    1515             : 
    1516           0 :         seen_nexthops =
    1517           0 :                 skiplist_new(0, vnc_prefix_cmp, prefix_free_lists);
    1518             : 
    1519           0 :         for (bpi = rn->info; bpi; bpi = bpi->next) {
    1520             : 
    1521           0 :                 struct prefix pfx_vn;
    1522           0 :                 struct prefix *newpfx;
    1523             : 
    1524           0 :                 if (removed && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
    1525             : #ifdef DEBUG_RETURNED_NHL
    1526             :                         vnc_zlog_debug_verbose(
    1527             :                                 "%s: want holddown, this route not holddown, skip",
    1528             :                                 __func__);
    1529             : #endif
    1530           0 :                         continue;
    1531             :                 }
    1532           0 :                 if (!removed && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
    1533           0 :                         continue;
    1534             :                 }
    1535             : 
    1536           0 :                 if (!bpi->extra) {
    1537           0 :                         continue;
    1538             :                 }
    1539             : 
    1540             :                 /*
    1541             :                  * Check for excluded VN address
    1542             :                  */
    1543           0 :                 if (rfapiVpnBiNhEqualsPt(bpi, exclude_vnaddr))
    1544           0 :                         continue;
    1545             : 
    1546             :                 /*
    1547             :                  * Check for VN address (nexthop) copied already
    1548             :                  */
    1549           0 :                 if (is_l2) {
    1550             :                         /* L2 routes: semantic nexthop in aux_prefix; VN addr
    1551             :                          * ain't it */
    1552           0 :                         pfx_vn = bpi->extra->vnc.import.aux_prefix;
    1553             :                 } else {
    1554           0 :                         rfapiNexthop2Prefix(bpi->attr, &pfx_vn);
    1555             :                 }
    1556           0 :                 if (!skiplist_search(seen_nexthops, &pfx_vn, NULL)) {
    1557             : #ifdef DEBUG_RETURNED_NHL
    1558             :                         vnc_zlog_debug_verbose(
    1559             :                                 "%s: already put VN/nexthop %pFX, skip",
    1560             :                                 __func__, &pfx_vn);
    1561             : #endif
    1562           0 :                         continue;
    1563             :                 }
    1564             : 
    1565           0 :                 if (rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) {
    1566             : #ifdef DEBUG_ENCAP_MONITOR
    1567             :                         vnc_zlog_debug_verbose(
    1568             :                                 "%s: failed to get UN address of this VPN bpi",
    1569             :                                 __func__);
    1570             : #endif
    1571           0 :                         continue;
    1572             :                 }
    1573             : 
    1574           0 :                 newpfx = prefix_new();
    1575           0 :                 *newpfx = pfx_vn;
    1576           0 :                 skiplist_insert(seen_nexthops, newpfx, newpfx);
    1577             : 
    1578           0 :                 new = rfapiRouteInfo2NextHopEntry(rprefix, bpi, lifetime, rn);
    1579           0 :                 if (new) {
    1580           0 :                         if (rfapiRibPreloadBi(rfd_rib_node, &pfx_vn, &pfx_un,
    1581             :                                               lifetime, bpi)) {
    1582             :                                 /* duplicate filtered by RIB */
    1583           0 :                                 rfapi_free_next_hop_list(new);
    1584           0 :                                 new = NULL;
    1585             :                         }
    1586             :                 }
    1587             : 
    1588           0 :                 if (new) {
    1589           0 :                         if (*tail) {
    1590           0 :                                 (*tail)->next = new;
    1591             :                         } else {
    1592           0 :                                 *head = new;
    1593             :                         }
    1594           0 :                         *tail = new;
    1595           0 :                         ++count;
    1596             :                 }
    1597             :         }
    1598             : 
    1599           0 :         skiplist_free(seen_nexthops);
    1600             : 
    1601           0 :         return count;
    1602             : }
    1603             : 
    1604             : 
    1605             : /*
    1606             :  * Breadth-first
    1607             :  *
    1608             :  * omit_node is meant for the situation where we are adding a subtree
    1609             :  * of a parent of some original requested node. The response already
    1610             :  * contains the original requested node, and we don't want to duplicate
    1611             :  * its routes in the list, so we skip it if the right or left node
    1612             :  * matches (of course, we still travel down its child subtrees).
    1613             :  */
    1614           0 : static int rfapiNhlAddSubtree(
    1615             :         struct agg_node *rn,                  /* in */
    1616             :         uint32_t lifetime,                    /* in */
    1617             :         struct rfapi_next_hop_entry **head,   /* in/out */
    1618             :         struct rfapi_next_hop_entry **tail,   /* in/out */
    1619             :         struct agg_node *omit_node,        /* in */
    1620             :         struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
    1621             :         struct agg_table *rfd_rib_table,      /* preload here */
    1622             :         struct prefix *pfx_target_original)   /* query target */
    1623             : {
    1624           0 :         struct rfapi_ip_prefix rprefix;
    1625           0 :         int rcount = 0;
    1626             : 
    1627             :         /* FIXME: need to find a better way here to work without sticking our
    1628             :          * hands in node->link */
    1629           0 :         if (agg_node_left(rn) && agg_node_left(rn) != omit_node) {
    1630           0 :                 if (agg_node_left(rn)->info) {
    1631           0 :                         const struct prefix *p =
    1632           0 :                                 agg_node_get_prefix(agg_node_left(rn));
    1633           0 :                         int count = 0;
    1634           0 :                         struct agg_node *rib_rn = NULL;
    1635             : 
    1636           0 :                         rfapiQprefix2Rprefix(p, &rprefix);
    1637           0 :                         if (rfd_rib_table)
    1638           0 :                                 rib_rn = agg_node_get(rfd_rib_table, p);
    1639             : 
    1640           0 :                         count = rfapiNhlAddNodeRoutes(
    1641             :                                 agg_node_left(rn), &rprefix, lifetime, 0, head,
    1642             :                                 tail, exclude_vnaddr, rib_rn,
    1643             :                                 pfx_target_original);
    1644           0 :                         if (!count) {
    1645           0 :                                 count = rfapiNhlAddNodeRoutes(
    1646             :                                         agg_node_left(rn), &rprefix, lifetime,
    1647             :                                         1, head, tail, exclude_vnaddr, rib_rn,
    1648             :                                         pfx_target_original);
    1649             :                         }
    1650           0 :                         rcount += count;
    1651           0 :                         if (rib_rn)
    1652           0 :                                 agg_unlock_node(rib_rn);
    1653             :                 }
    1654             :         }
    1655             : 
    1656           0 :         if (agg_node_right(rn) && agg_node_right(rn) != omit_node) {
    1657           0 :                 if (agg_node_right(rn)->info) {
    1658           0 :                         const struct prefix *p =
    1659           0 :                                 agg_node_get_prefix(agg_node_right(rn));
    1660           0 :                         int count = 0;
    1661           0 :                         struct agg_node *rib_rn = NULL;
    1662             : 
    1663           0 :                         rfapiQprefix2Rprefix(p, &rprefix);
    1664           0 :                         if (rfd_rib_table)
    1665           0 :                                 rib_rn = agg_node_get(rfd_rib_table, p);
    1666             : 
    1667           0 :                         count = rfapiNhlAddNodeRoutes(
    1668             :                                 agg_node_right(rn), &rprefix, lifetime, 0, head,
    1669             :                                 tail, exclude_vnaddr, rib_rn,
    1670             :                                 pfx_target_original);
    1671           0 :                         if (!count) {
    1672           0 :                                 count = rfapiNhlAddNodeRoutes(
    1673             :                                         agg_node_right(rn), &rprefix, lifetime,
    1674             :                                         1, head, tail, exclude_vnaddr, rib_rn,
    1675             :                                         pfx_target_original);
    1676             :                         }
    1677           0 :                         rcount += count;
    1678           0 :                         if (rib_rn)
    1679           0 :                                 agg_unlock_node(rib_rn);
    1680             :                 }
    1681             :         }
    1682             : 
    1683           0 :         if (agg_node_left(rn)) {
    1684           0 :                 rcount += rfapiNhlAddSubtree(
    1685             :                         agg_node_left(rn), lifetime, head, tail, omit_node,
    1686             :                         exclude_vnaddr, rfd_rib_table, pfx_target_original);
    1687             :         }
    1688           0 :         if (agg_node_right(rn)) {
    1689           0 :                 rcount += rfapiNhlAddSubtree(
    1690             :                         agg_node_right(rn), lifetime, head, tail, omit_node,
    1691             :                         exclude_vnaddr, rfd_rib_table, pfx_target_original);
    1692             :         }
    1693             : 
    1694           0 :         return rcount;
    1695             : }
    1696             : 
    1697             : /*
    1698             :  * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
    1699             :  *
    1700             :  * Construct an rfapi nexthop list based on the routes attached to
    1701             :  * the specified node.
    1702             :  *
    1703             :  * If there are any routes that do NOT have BGP_PATH_REMOVED set,
    1704             :  * return those only. If there are ONLY routes with BGP_PATH_REMOVED,
    1705             :  * then return those, and also include all the non-removed routes from the
    1706             :  * next less-specific node (i.e., this node's parent) at the end.
    1707             :  */
    1708           0 : struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
    1709             :         struct agg_node *rn, uint32_t lifetime, /* put into nexthop entries */
    1710             :         struct rfapi_ip_addr *exclude_vnaddr,   /* omit routes to same NVE */
    1711             :         struct agg_table *rfd_rib_table,        /* preload here */
    1712             :         struct prefix *pfx_target_original)     /* query target */
    1713             : {
    1714           0 :         struct rfapi_ip_prefix rprefix;
    1715           0 :         struct rfapi_next_hop_entry *answer = NULL;
    1716           0 :         struct rfapi_next_hop_entry *last = NULL;
    1717           0 :         struct agg_node *parent;
    1718           0 :         const struct prefix *p = agg_node_get_prefix(rn);
    1719           0 :         int count = 0;
    1720           0 :         struct agg_node *rib_rn;
    1721             : 
    1722             : #ifdef DEBUG_RETURNED_NHL
    1723             :         vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn);
    1724             :         rfapiDebugBacktrace();
    1725             : #endif
    1726             : 
    1727           0 :         rfapiQprefix2Rprefix(p, &rprefix);
    1728             : 
    1729           0 :         rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
    1730             : 
    1731             :         /*
    1732             :          * Add non-withdrawn routes at this node
    1733             :          */
    1734           0 :         count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 0, &answer, &last,
    1735             :                                       exclude_vnaddr, rib_rn,
    1736             :                                       pfx_target_original);
    1737             : 
    1738             :         /*
    1739             :          * If the list has at least one entry, it's finished
    1740             :          */
    1741           0 :         if (count) {
    1742           0 :                 count += rfapiNhlAddSubtree(rn, lifetime, &answer, &last, NULL,
    1743             :                                             exclude_vnaddr, rfd_rib_table,
    1744             :                                             pfx_target_original);
    1745           0 :                 vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__,
    1746             :                                        count, answer);
    1747             : #ifdef DEBUG_RETURNED_NHL
    1748             :                 rfapiPrintNhl(NULL, answer);
    1749             : #endif
    1750           0 :                 if (rib_rn)
    1751           0 :                         agg_unlock_node(rib_rn);
    1752           0 :                 return answer;
    1753             :         }
    1754             : 
    1755             :         /*
    1756             :          * Add withdrawn routes at this node
    1757             :          */
    1758           0 :         count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 1, &answer, &last,
    1759             :                                       exclude_vnaddr, rib_rn,
    1760             :                                       pfx_target_original);
    1761           0 :         if (rib_rn)
    1762           0 :                 agg_unlock_node(rib_rn);
    1763             : 
    1764             :         // rfapiPrintNhl(NULL, answer);
    1765             : 
    1766             :         /*
    1767             :          * walk up the tree until we find a node with non-deleted
    1768             :          * routes, then add them
    1769             :          */
    1770           0 :         for (parent = agg_node_parent(rn); parent;
    1771           0 :              parent = agg_node_parent(parent)) {
    1772           0 :                 if (rfapiHasNonRemovedRoutes(parent)) {
    1773             :                         break;
    1774             :                 }
    1775             :         }
    1776             : 
    1777             :         /*
    1778             :          * Add non-withdrawn routes from less-specific prefix
    1779             :          */
    1780           0 :         if (parent) {
    1781           0 :                 const struct prefix *p = agg_node_get_prefix(parent);
    1782             : 
    1783           0 :                 rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
    1784           0 :                 rfapiQprefix2Rprefix(p, &rprefix);
    1785           0 :                 count += rfapiNhlAddNodeRoutes(parent, &rprefix, lifetime, 0,
    1786             :                                                &answer, &last, exclude_vnaddr,
    1787             :                                                rib_rn, pfx_target_original);
    1788           0 :                 count += rfapiNhlAddSubtree(parent, lifetime, &answer, &last,
    1789             :                                             rn, exclude_vnaddr, rfd_rib_table,
    1790             :                                             pfx_target_original);
    1791           0 :                 if (rib_rn)
    1792           0 :                         agg_unlock_node(rib_rn);
    1793             :         } else {
    1794             :                 /*
    1795             :                  * There is no parent with non-removed routes. Still need to
    1796             :                  * add subtree of original node if it contributed routes to the
    1797             :                  * answer.
    1798             :                  */
    1799           0 :                 if (count)
    1800           0 :                         count += rfapiNhlAddSubtree(rn, lifetime, &answer,
    1801             :                                                     &last, rn, exclude_vnaddr,
    1802             :                                                     rfd_rib_table,
    1803             :                                                     pfx_target_original);
    1804             :         }
    1805             : 
    1806           0 :         vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__, count,
    1807             :                                answer);
    1808             : #ifdef DEBUG_RETURNED_NHL
    1809             :         rfapiPrintNhl(NULL, answer);
    1810             : #endif
    1811           0 :         return answer;
    1812             : }
    1813             : 
    1814             : /*
    1815             :  * Construct nexthop list of all routes in table
    1816             :  */
    1817           0 : struct rfapi_next_hop_entry *rfapiRouteTable2NextHopList(
    1818             :         struct agg_table *rt, uint32_t lifetime, /* put into nexthop entries */
    1819             :         struct rfapi_ip_addr *exclude_vnaddr,    /* omit routes to same NVE */
    1820             :         struct agg_table *rfd_rib_table,    /* preload this NVE rib table */
    1821             :         struct prefix *pfx_target_original) /* query target */
    1822             : {
    1823           0 :         struct agg_node *rn;
    1824           0 :         struct rfapi_next_hop_entry *biglist = NULL;
    1825           0 :         struct rfapi_next_hop_entry *nhl;
    1826           0 :         struct rfapi_next_hop_entry *tail = NULL;
    1827           0 :         int count = 0;
    1828             : 
    1829           0 :         for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
    1830             : 
    1831           0 :                 nhl = rfapiRouteNode2NextHopList(rn, lifetime, exclude_vnaddr,
    1832             :                                                  rfd_rib_table,
    1833             :                                                  pfx_target_original);
    1834           0 :                 if (!tail) {
    1835           0 :                         tail = biglist = nhl;
    1836           0 :                         if (tail)
    1837           0 :                                 count = 1;
    1838             :                 } else {
    1839           0 :                         tail->next = nhl;
    1840             :                 }
    1841           0 :                 if (tail) {
    1842           0 :                         while (tail->next) {
    1843           0 :                                 ++count;
    1844           0 :                                 tail = tail->next;
    1845             :                         }
    1846             :                 }
    1847             :         }
    1848             : 
    1849           0 :         vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count);
    1850           0 :         return biglist;
    1851             : }
    1852             : 
    1853           0 : struct rfapi_next_hop_entry *rfapiEthRouteNode2NextHopList(
    1854             :         struct agg_node *rn, struct rfapi_ip_prefix *rprefix,
    1855             :         uint32_t lifetime,                    /* put into nexthop entries */
    1856             :         struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
    1857             :         struct agg_table *rfd_rib_table,      /* preload NVE rib table */
    1858             :         struct prefix *pfx_target_original)   /* query target */
    1859             : {
    1860           0 :         int count = 0;
    1861           0 :         struct rfapi_next_hop_entry *answer = NULL;
    1862           0 :         struct rfapi_next_hop_entry *last = NULL;
    1863           0 :         struct agg_node *rib_rn;
    1864             : 
    1865           0 :         rib_rn = rfd_rib_table
    1866           0 :                          ? agg_node_get(rfd_rib_table, agg_node_get_prefix(rn))
    1867           0 :                          : NULL;
    1868             : 
    1869           0 :         count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 0, &answer, &last,
    1870             :                                       NULL, rib_rn, pfx_target_original);
    1871             : 
    1872             : #ifdef DEBUG_ENCAP_MONITOR
    1873             :         vnc_zlog_debug_verbose("%s: node %p: %d non-holddown routes", __func__,
    1874             :                                rn, count);
    1875             : #endif
    1876             : 
    1877           0 :         if (!count) {
    1878           0 :                 count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 1, &answer,
    1879             :                                               &last, exclude_vnaddr, rib_rn,
    1880             :                                               pfx_target_original);
    1881           0 :                 vnc_zlog_debug_verbose("%s: node %p: %d holddown routes",
    1882             :                                        __func__, rn, count);
    1883             :         }
    1884             : 
    1885           0 :         if (rib_rn)
    1886           0 :                 agg_unlock_node(rib_rn);
    1887             : 
    1888             : #ifdef DEBUG_RETURNED_NHL
    1889             :         rfapiPrintNhl(NULL, answer);
    1890             : #endif
    1891             : 
    1892           0 :         return answer;
    1893             : }
    1894             : 
    1895             : 
    1896             : /*
    1897             :  * Construct nexthop list of all routes in table
    1898             :  */
    1899           0 : struct rfapi_next_hop_entry *rfapiEthRouteTable2NextHopList(
    1900             :         uint32_t logical_net_id, struct rfapi_ip_prefix *rprefix,
    1901             :         uint32_t lifetime,                    /* put into nexthop entries */
    1902             :         struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
    1903             :         struct agg_table *rfd_rib_table,      /* preload NVE rib node */
    1904             :         struct prefix *pfx_target_original)   /* query target */
    1905             : {
    1906           0 :         struct rfapi_import_table *it;
    1907           0 :         struct bgp *bgp = bgp_get_default();
    1908           0 :         struct agg_table *rt;
    1909           0 :         struct agg_node *rn;
    1910           0 :         struct rfapi_next_hop_entry *biglist = NULL;
    1911           0 :         struct rfapi_next_hop_entry *nhl;
    1912           0 :         struct rfapi_next_hop_entry *tail = NULL;
    1913           0 :         int count = 0;
    1914             : 
    1915             : 
    1916           0 :         it = rfapiMacImportTableGet(bgp, logical_net_id);
    1917           0 :         rt = it->imported_vpn[AFI_L2VPN];
    1918             : 
    1919           0 :         for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
    1920             : 
    1921           0 :                 nhl = rfapiEthRouteNode2NextHopList(
    1922             :                         rn, rprefix, lifetime, exclude_vnaddr, rfd_rib_table,
    1923             :                         pfx_target_original);
    1924           0 :                 if (!tail) {
    1925           0 :                         tail = biglist = nhl;
    1926           0 :                         if (tail)
    1927           0 :                                 count = 1;
    1928             :                 } else {
    1929           0 :                         tail->next = nhl;
    1930             :                 }
    1931           0 :                 if (tail) {
    1932           0 :                         while (tail->next) {
    1933           0 :                                 ++count;
    1934           0 :                                 tail = tail->next;
    1935             :                         }
    1936             :                 }
    1937             :         }
    1938             : 
    1939           0 :         vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count);
    1940           0 :         return biglist;
    1941             : }
    1942             : 
    1943             : /*
    1944             :  * Insert a new bpi to the imported route table node,
    1945             :  * keeping the list of BPIs sorted best route first
    1946             :  */
    1947           0 : static void rfapiBgpInfoAttachSorted(struct agg_node *rn,
    1948             :                                      struct bgp_path_info *info_new, afi_t afi,
    1949             :                                      safi_t safi)
    1950             : {
    1951           0 :         struct bgp *bgp;
    1952           0 :         struct bgp_path_info *prev;
    1953           0 :         struct bgp_path_info *next;
    1954           0 :         char pfx_buf[PREFIX2STR_BUFFER];
    1955             : 
    1956             : 
    1957           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    1958             : 
    1959           0 :         if (VNC_DEBUG(IMPORT_BI_ATTACH)) {
    1960           0 :                 vnc_zlog_debug_verbose("%s: info_new->peer=%p", __func__,
    1961             :                                        info_new->peer);
    1962           0 :                 vnc_zlog_debug_verbose("%s: info_new->peer->su_remote=%p",
    1963             :                                        __func__, info_new->peer->su_remote);
    1964             :         }
    1965             : 
    1966           0 :         for (prev = NULL, next = rn->info; next;
    1967           0 :              prev = next, next = next->next) {
    1968           0 :                 enum bgp_path_selection_reason reason;
    1969             : 
    1970           0 :                 if (!bgp
    1971           0 :                     || (!CHECK_FLAG(info_new->flags, BGP_PATH_REMOVED)
    1972           0 :                         && CHECK_FLAG(next->flags, BGP_PATH_REMOVED))
    1973           0 :                     || bgp_path_info_cmp_compatible(bgp, info_new, next,
    1974             :                                                     pfx_buf, afi, safi,
    1975             :                                                     &reason)
    1976             :                                == -1) { /* -1 if 1st is better */
    1977             :                         break;
    1978             :                 }
    1979             :         }
    1980           0 :         vnc_zlog_debug_verbose("%s: prev=%p, next=%p", __func__, prev, next);
    1981           0 :         if (prev) {
    1982           0 :                 prev->next = info_new;
    1983             :         } else {
    1984           0 :                 rn->info = info_new;
    1985             :         }
    1986           0 :         info_new->prev = prev;
    1987           0 :         info_new->next = next;
    1988           0 :         if (next)
    1989           0 :                 next->prev = info_new;
    1990           0 :         bgp_attr_intern(info_new->attr);
    1991           0 : }
    1992             : 
    1993           0 : static void rfapiBgpInfoDetach(struct agg_node *rn, struct bgp_path_info *bpi)
    1994             : {
    1995             :         /*
    1996             :          * Remove the route (doubly-linked)
    1997             :          */
    1998             :         //  bgp_attr_unintern (&bpi->attr);
    1999           0 :         if (bpi->next)
    2000           0 :                 bpi->next->prev = bpi->prev;
    2001           0 :         if (bpi->prev)
    2002           0 :                 bpi->prev->next = bpi->next;
    2003             :         else
    2004           0 :                 rn->info = bpi->next;
    2005             : }
    2006             : 
    2007             : /*
    2008             :  * For L3-indexed import tables
    2009             :  */
    2010           0 : static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2)
    2011             : {
    2012           0 :         const struct bgp_path_info *bpi1 = b1;
    2013           0 :         const struct bgp_path_info *bpi2 = b2;
    2014             : 
    2015             :         /*
    2016             :          * Compare peers
    2017             :          */
    2018           0 :         if (bpi1->peer < bpi2->peer)
    2019             :                 return -1;
    2020           0 :         if (bpi1->peer > bpi2->peer)
    2021             :                 return 1;
    2022             : 
    2023             :         /*
    2024             :          * compare RDs
    2025             :          */
    2026           0 :         return vnc_prefix_cmp(
    2027           0 :                 (const struct prefix *)&bpi1->extra->vnc.import.rd,
    2028           0 :                 (const struct prefix *)&bpi2->extra->vnc.import.rd);
    2029             : }
    2030             : 
    2031             : /*
    2032             :  * For L2-indexed import tables
    2033             :  * The BPIs in these tables should ALWAYS have an aux_prefix set because
    2034             :  * they arrive via IPv4 or IPv6 advertisements.
    2035             :  */
    2036           0 : static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2)
    2037             : {
    2038           0 :         const struct bgp_path_info *bpi1 = b1;
    2039           0 :         const struct bgp_path_info *bpi2 = b2;
    2040           0 :         int rc;
    2041             : 
    2042             :         /*
    2043             :          * Compare peers
    2044             :          */
    2045           0 :         if (bpi1->peer < bpi2->peer)
    2046             :                 return -1;
    2047           0 :         if (bpi1->peer > bpi2->peer)
    2048             :                 return 1;
    2049             : 
    2050             :         /*
    2051             :          * compare RDs
    2052             :          */
    2053           0 :         rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd,
    2054           0 :                             (struct prefix *)&bpi2->extra->vnc.import.rd);
    2055           0 :         if (rc) {
    2056             :                 return rc;
    2057             :         }
    2058             : 
    2059             :         /*
    2060             :          * L2 import tables can have multiple entries with the
    2061             :          * same MAC address, same RD, but different L3 addresses.
    2062             :          *
    2063             :          * Use presence of aux_prefix with AF=ethernet and prefixlen=1
    2064             :          * as magic value to signify explicit wildcarding of the aux_prefix.
    2065             :          * This magic value will not appear in bona fide bpi entries in
    2066             :          * the import table, but is allowed in the "fake" bpi used to
    2067             :          * probe the table when searching. (We have to test both b1 and b2
    2068             :          * because there is no guarantee of the order the test key and
    2069             :          * the real key will be passed)
    2070             :          */
    2071           0 :         if ((bpi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET
    2072           0 :              && (bpi1->extra->vnc.import.aux_prefix.prefixlen == 1))
    2073           0 :             || (bpi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET
    2074           0 :                 && (bpi2->extra->vnc.import.aux_prefix.prefixlen == 1))) {
    2075             : 
    2076             :                 /*
    2077             :                  * wildcard aux address specified
    2078             :                  */
    2079             :                 return 0;
    2080             :         }
    2081             : 
    2082           0 :         return vnc_prefix_cmp(&bpi1->extra->vnc.import.aux_prefix,
    2083           0 :                               &bpi2->extra->vnc.import.aux_prefix);
    2084             : }
    2085             : 
    2086             : 
    2087             : /*
    2088             :  * Index on RD and Peer
    2089             :  */
    2090           0 : static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
    2091             :                               struct bgp_path_info *bpi) /* new BPI */
    2092             : {
    2093           0 :         struct skiplist *sl;
    2094           0 :         const struct prefix *p;
    2095             : 
    2096           0 :         assert(rn);
    2097           0 :         assert(bpi);
    2098           0 :         assert(bpi->extra);
    2099             : 
    2100           0 :         vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
    2101             :                                bpi->peer, &bpi->extra->vnc.import.rd);
    2102             : 
    2103           0 :         sl = RFAPI_RDINDEX_W_ALLOC(rn);
    2104           0 :         if (!sl) {
    2105           0 :                 p = agg_node_get_prefix(rn);
    2106           0 :                 if (AF_ETHERNET == p->family) {
    2107           0 :                         sl = skiplist_new(0, rfapi_bi_peer_rd_aux_cmp, NULL);
    2108             :                 } else {
    2109           0 :                         sl = skiplist_new(0, rfapi_bi_peer_rd_cmp, NULL);
    2110             :                 }
    2111           0 :                 RFAPI_IT_EXTRA_GET(rn)->u.vpn.idx_rd = sl;
    2112           0 :                 agg_lock_node(rn); /* for skiplist */
    2113             :         }
    2114           0 :         assert(!skiplist_insert(sl, (void *)bpi, (void *)bpi));
    2115           0 :         agg_lock_node(rn); /* for skiplist entry */
    2116             : 
    2117             :         /* NB: BPIs in import tables are not refcounted */
    2118           0 : }
    2119             : 
    2120           0 : static void rfapiItBiIndexDump(struct agg_node *rn)
    2121             : {
    2122           0 :         struct skiplist *sl;
    2123           0 :         void *cursor = NULL;
    2124           0 :         struct bgp_path_info *k;
    2125           0 :         struct bgp_path_info *v;
    2126           0 :         int rc;
    2127             : 
    2128           0 :         sl = RFAPI_RDINDEX(rn);
    2129           0 :         if (!sl)
    2130           0 :                 return;
    2131             : 
    2132           0 :         for (rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor); !rc;
    2133           0 :              rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor)) {
    2134             : 
    2135           0 :                 char buf[RD_ADDRSTRLEN];
    2136           0 :                 char buf_aux_pfx[PREFIX_STRLEN];
    2137             : 
    2138           0 :                 prefix_rd2str(&k->extra->vnc.import.rd, buf, sizeof(buf));
    2139           0 :                 if (k->extra->vnc.import.aux_prefix.family) {
    2140           0 :                         prefix2str(&k->extra->vnc.import.aux_prefix,
    2141             :                                    buf_aux_pfx, sizeof(buf_aux_pfx));
    2142             :                 } else
    2143           0 :                         strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx));
    2144             : 
    2145           0 :                 vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s",
    2146             :                                        k, k->peer, buf, buf_aux_pfx);
    2147             :         }
    2148             : }
    2149             : 
    2150           0 : static struct bgp_path_info *rfapiItBiIndexSearch(
    2151             :         struct agg_node *rn, /* Import table VPN node */
    2152             :         struct prefix_rd *prd, struct peer *peer,
    2153             :         const struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */
    2154             : {
    2155           0 :         struct skiplist *sl;
    2156           0 :         int rc;
    2157           0 :         struct bgp_path_info bpi_fake = {0};
    2158           0 :         struct bgp_path_info_extra bpi_extra = {0};
    2159           0 :         struct bgp_path_info *bpi_result;
    2160             : 
    2161           0 :         sl = RFAPI_RDINDEX(rn);
    2162           0 :         if (!sl)
    2163             :                 return NULL;
    2164             : 
    2165             : #ifdef DEBUG_BI_SEARCH
    2166             :         {
    2167             :                 char buf_aux_pfx[PREFIX_STRLEN];
    2168             : 
    2169             :                 if (aux_prefix) {
    2170             :                         prefix2str(aux_prefix, buf_aux_pfx,
    2171             :                                    sizeof(buf_aux_pfx));
    2172             :                 } else
    2173             :                         strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
    2174             : 
    2175             :                 vnc_zlog_debug_verbose(
    2176             :                         "%s want prd=%pRD, peer=%p, aux_prefix=%s", __func__,
    2177             :                         prd, peer, buf_aux_pfx);
    2178             :                 rfapiItBiIndexDump(rn);
    2179             :         }
    2180             : #endif
    2181             : 
    2182             :         /* threshold is a WAG */
    2183           0 :         if (sl->count < 3) {
    2184             : #ifdef DEBUG_BI_SEARCH
    2185             :                 vnc_zlog_debug_verbose("%s: short list algorithm", __func__);
    2186             : #endif
    2187             :                 /* if short list, linear search might be faster */
    2188           0 :                 for (bpi_result = rn->info; bpi_result;
    2189           0 :                      bpi_result = bpi_result->next) {
    2190             : #ifdef DEBUG_BI_SEARCH
    2191             :                         vnc_zlog_debug_verbose(
    2192             :                                 "%s: bpi has prd=%pRD, peer=%p", __func__,
    2193             :                                 &bpi_result->extra->vnc.import.rd,
    2194             :                                 bpi_result->peer);
    2195             : #endif
    2196           0 :                         if (peer == bpi_result->peer
    2197           0 :                             && !prefix_cmp((struct prefix *)&bpi_result->extra
    2198             :                                                    ->vnc.import.rd,
    2199             :                                            (struct prefix *)prd)) {
    2200             : 
    2201             : #ifdef DEBUG_BI_SEARCH
    2202             :                                 vnc_zlog_debug_verbose(
    2203             :                                         "%s: peer and RD same, doing aux_prefix check",
    2204             :                                         __func__);
    2205             : #endif
    2206           0 :                                 if (!aux_prefix
    2207           0 :                                     || !prefix_cmp(
    2208             :                                                aux_prefix,
    2209           0 :                                                &bpi_result->extra->vnc.import
    2210             :                                                         .aux_prefix)) {
    2211             : 
    2212             : #ifdef DEBUG_BI_SEARCH
    2213             :                                         vnc_zlog_debug_verbose("%s: match",
    2214             :                                                                __func__);
    2215             : #endif
    2216             :                                         break;
    2217             :                                 }
    2218             :                         }
    2219             :                 }
    2220           0 :                 return bpi_result;
    2221             :         }
    2222             : 
    2223           0 :         bpi_fake.peer = peer;
    2224           0 :         bpi_fake.extra = &bpi_extra;
    2225           0 :         bpi_fake.extra->vnc.import.rd = *prd;
    2226           0 :         if (aux_prefix) {
    2227           0 :                 bpi_fake.extra->vnc.import.aux_prefix = *aux_prefix;
    2228             :         } else {
    2229             :                 /* wildcard */
    2230           0 :                 bpi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET;
    2231           0 :                 bpi_fake.extra->vnc.import.aux_prefix.prefixlen = 1;
    2232             :         }
    2233             : 
    2234           0 :         rc = skiplist_search(sl, (void *)&bpi_fake, (void *)&bpi_result);
    2235             : 
    2236           0 :         if (rc) {
    2237             : #ifdef DEBUG_BI_SEARCH
    2238             :                 vnc_zlog_debug_verbose("%s: no match", __func__);
    2239             : #endif
    2240             :                 return NULL;
    2241             :         }
    2242             : 
    2243             : #ifdef DEBUG_BI_SEARCH
    2244             :         vnc_zlog_debug_verbose("%s: matched bpi=%p", __func__, bpi_result);
    2245             : #endif
    2246             : 
    2247           0 :         return bpi_result;
    2248             : }
    2249             : 
    2250           0 : static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
    2251             :                               struct bgp_path_info *bpi) /* old BPI */
    2252             : {
    2253           0 :         struct skiplist *sl;
    2254           0 :         int rc;
    2255             : 
    2256           0 :         vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
    2257             :                                bpi->peer, &bpi->extra->vnc.import.rd);
    2258             : 
    2259           0 :         sl = RFAPI_RDINDEX(rn);
    2260           0 :         assert(sl);
    2261             : 
    2262           0 :         rc = skiplist_delete(sl, (void *)(bpi), (void *)bpi);
    2263           0 :         if (rc) {
    2264           0 :                 rfapiItBiIndexDump(rn);
    2265             :         }
    2266           0 :         assert(!rc);
    2267             : 
    2268           0 :         agg_unlock_node(rn); /* for skiplist entry */
    2269             : 
    2270             :         /* NB: BPIs in import tables are not refcounted */
    2271           0 : }
    2272             : 
    2273             : /*
    2274             :  * Add a backreference at the ENCAP node to the VPN route that
    2275             :  * refers to it
    2276             :  */
    2277             : static void
    2278           0 : rfapiMonitorEncapAdd(struct rfapi_import_table *import_table,
    2279             :                      struct prefix *p,              /* VN address */
    2280             :                      struct agg_node *vpn_rn,       /* VPN node */
    2281             :                      struct bgp_path_info *vpn_bpi) /* VPN bpi/route */
    2282             : {
    2283           0 :         afi_t afi = family2afi(p->family);
    2284           0 :         struct agg_node *rn;
    2285           0 :         struct rfapi_monitor_encap *m;
    2286             : 
    2287           0 :         assert(afi);
    2288           0 :         rn = agg_node_get(import_table->imported_encap[afi], p); /* locks rn */
    2289           0 :         assert(rn);
    2290             : 
    2291           0 :         m = XCALLOC(MTYPE_RFAPI_MONITOR_ENCAP,
    2292             :                     sizeof(struct rfapi_monitor_encap));
    2293             : 
    2294           0 :         m->node = vpn_rn;
    2295           0 :         m->bpi = vpn_bpi;
    2296           0 :         m->rn = rn;
    2297             : 
    2298             :         /* insert to encap node's list */
    2299           0 :         m->next = RFAPI_MONITOR_ENCAP(rn);
    2300           0 :         if (m->next)
    2301           0 :                 m->next->prev = m;
    2302           0 :         RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m;
    2303             : 
    2304             :         /* for easy lookup when deleting vpn route */
    2305           0 :         vpn_bpi->extra->vnc.import.hme = m;
    2306             : 
    2307           0 :         vnc_zlog_debug_verbose(
    2308             :                 "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p",
    2309             :                 __func__, import_table, vpn_bpi, afi, rn, m);
    2310             : 
    2311           0 :         RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
    2312           0 :         bgp_attr_intern(vpn_bpi->attr);
    2313           0 : }
    2314             : 
    2315           0 : static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi)
    2316             : {
    2317             :         /*
    2318             :          * Remove encap monitor
    2319             :          */
    2320           0 :         vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
    2321           0 :         if (vpn_bpi->extra) {
    2322           0 :                 struct rfapi_monitor_encap *hme =
    2323             :                         vpn_bpi->extra->vnc.import.hme;
    2324             : 
    2325           0 :                 if (hme) {
    2326             : 
    2327           0 :                         vnc_zlog_debug_verbose("%s: hme=%p", __func__, hme);
    2328             : 
    2329             :                         /* Refcount checking takes too long here */
    2330             :                         // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
    2331           0 :                         if (hme->next)
    2332           0 :                                 hme->next->prev = hme->prev;
    2333           0 :                         if (hme->prev)
    2334           0 :                                 hme->prev->next = hme->next;
    2335             :                         else
    2336           0 :                                 RFAPI_MONITOR_ENCAP_W_ALLOC(hme->rn) =
    2337           0 :                                         hme->next;
    2338             :                         /* Refcount checking takes too long here */
    2339             :                         // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
    2340             : 
    2341             :                         /* see if the struct rfapi_it_extra is empty and can be
    2342             :                          * freed */
    2343           0 :                         rfapiMonitorExtraPrune(SAFI_ENCAP, hme->rn);
    2344             : 
    2345           0 :                         agg_unlock_node(hme->rn); /* decr ref count */
    2346           0 :                         XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme);
    2347           0 :                         vpn_bpi->extra->vnc.import.hme = NULL;
    2348             :                 }
    2349             :         }
    2350           0 : }
    2351             : 
    2352             : /*
    2353             :  * quagga lib/thread.h says this must return int even though
    2354             :  * it doesn't do anything with the return value
    2355             :  */
    2356           0 : static void rfapiWithdrawTimerVPN(struct thread *t)
    2357             : {
    2358           0 :         struct rfapi_withdraw *wcb = THREAD_ARG(t);
    2359           0 :         struct bgp_path_info *bpi = wcb->info;
    2360           0 :         struct bgp *bgp = bgp_get_default();
    2361           0 :         const struct prefix *p;
    2362           0 :         struct rfapi_monitor_vpn *moved;
    2363           0 :         afi_t afi;
    2364             : 
    2365           0 :         if (bgp == NULL) {
    2366           0 :                 vnc_zlog_debug_verbose(
    2367             :                    "%s: NULL BGP pointer, assume shutdown race condition!!!",
    2368             :                    __func__);
    2369           0 :                 return;
    2370             :         }
    2371           0 :         if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
    2372           0 :                 vnc_zlog_debug_verbose(
    2373             :                         "%s: BGP delete in progress, assume shutdown race condition!!!",
    2374             :                         __func__);
    2375           0 :                 return;
    2376             :         }
    2377           0 :         assert(wcb->node);
    2378           0 :         assert(bpi);
    2379           0 :         assert(wcb->import_table);
    2380           0 :         assert(bpi->extra);
    2381             : 
    2382           0 :         RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, wcb->lockoffset);
    2383             : 
    2384           0 :         vnc_zlog_debug_verbose("%s: removing bpi %p at prefix %pRN", __func__,
    2385             :                                bpi, wcb->node);
    2386             : 
    2387             :         /*
    2388             :          * Remove the route (doubly-linked)
    2389             :          */
    2390           0 :         if (CHECK_FLAG(bpi->flags, BGP_PATH_VALID)
    2391           0 :             && VALID_INTERIOR_TYPE(bpi->type))
    2392           0 :                 RFAPI_MONITOR_EXTERIOR(wcb->node)->valid_interior_count--;
    2393             : 
    2394           0 :         p = agg_node_get_prefix(wcb->node);
    2395           0 :         afi = family2afi(p->family);
    2396           0 :         wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */
    2397           0 :         rfapiItBiIndexDel(wcb->node, bpi);
    2398           0 :         rfapiBgpInfoDetach(wcb->node, bpi); /* with removed bpi */
    2399             : 
    2400           0 :         vnc_import_bgp_exterior_del_route_interior(bgp, wcb->import_table,
    2401             :                                                    wcb->node, bpi);
    2402             : 
    2403             : 
    2404             :         /*
    2405             :          * If VNC is configured to send response remove messages, AND
    2406             :          * if the removed route had a UN address, do response removal
    2407             :          * processing.
    2408             :          */
    2409           0 :         if (!(bgp->rfapi_cfg->flags
    2410           0 :               & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) {
    2411             : 
    2412           0 :                 int has_valid_duplicate = 0;
    2413           0 :                 struct bgp_path_info *bpii;
    2414             : 
    2415             :                 /*
    2416             :                  * First check if there are any OTHER routes at this node
    2417             :                  * that have the same nexthop and a valid UN address. If
    2418             :                  * there are (e.g., from other peers), then the route isn't
    2419             :                  * really gone, so skip sending a response removal message.
    2420             :                  */
    2421           0 :                 for (bpii = wcb->node->info; bpii; bpii = bpii->next) {
    2422           0 :                         if (rfapiVpnBiSamePtUn(bpi, bpii)) {
    2423             :                                 has_valid_duplicate = 1;
    2424             :                                 break;
    2425             :                         }
    2426             :                 }
    2427             : 
    2428           0 :                 vnc_zlog_debug_verbose("%s: has_valid_duplicate=%d", __func__,
    2429             :                                        has_valid_duplicate);
    2430             : 
    2431           0 :                 if (!has_valid_duplicate) {
    2432           0 :                         rfapiRibPendingDeleteRoute(bgp, wcb->import_table, afi,
    2433             :                                                    wcb->node);
    2434             :                 }
    2435             :         }
    2436             : 
    2437           0 :         rfapiMonitorEncapDelete(bpi);
    2438             : 
    2439             :         /*
    2440             :          * If there are no VPN monitors at this VPN Node A,
    2441             :          * we are done
    2442             :          */
    2443           0 :         if (!RFAPI_MONITOR_VPN(wcb->node)) {
    2444           0 :                 vnc_zlog_debug_verbose("%s: no VPN monitors at this node",
    2445             :                                        __func__);
    2446           0 :                 goto done;
    2447             :         }
    2448             : 
    2449             :         /*
    2450             :          * rfapiMonitorMoveShorter only moves monitors if there are
    2451             :          * no remaining valid routes at the current node
    2452             :          */
    2453           0 :         moved = rfapiMonitorMoveShorter(wcb->node, 1);
    2454             : 
    2455           0 :         if (moved) {
    2456           0 :                 rfapiMonitorMovedUp(wcb->import_table, wcb->node, moved->node,
    2457             :                                     moved);
    2458             :         }
    2459             : 
    2460           0 : done:
    2461             :         /*
    2462             :          * Free VPN bpi
    2463             :          */
    2464           0 :         rfapiBgpInfoFree(bpi);
    2465           0 :         wcb->info = NULL;
    2466             : 
    2467             :         /*
    2468             :          * If route count at this node has gone to 0, withdraw exported prefix
    2469             :          */
    2470           0 :         if (!wcb->node->info) {
    2471             :                 /* see if the struct rfapi_it_extra is empty and can be freed */
    2472           0 :                 rfapiMonitorExtraPrune(SAFI_MPLS_VPN, wcb->node);
    2473           0 :                 vnc_direct_bgp_del_prefix(bgp, wcb->import_table, wcb->node);
    2474           0 :                 vnc_zebra_del_prefix(bgp, wcb->import_table, wcb->node);
    2475             :         } else {
    2476             :                 /*
    2477             :                  * nexthop change event
    2478             :                  * vnc_direct_bgp_add_prefix() will recompute the VN addr
    2479             :                  * ecommunity
    2480             :                  */
    2481           0 :                 vnc_direct_bgp_add_prefix(bgp, wcb->import_table, wcb->node);
    2482             :         }
    2483             : 
    2484           0 :         RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset);
    2485           0 :         agg_unlock_node(wcb->node); /* decr ref count */
    2486           0 :         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
    2487             : }
    2488             : 
    2489             : /*
    2490             :  * This works for multiprotocol extension, but not for plain ol'
    2491             :  * unicast IPv4 because that nexthop is stored in attr->nexthop
    2492             :  */
    2493           0 : void rfapiNexthop2Prefix(struct attr *attr, struct prefix *p)
    2494             : {
    2495           0 :         assert(p);
    2496           0 :         assert(attr);
    2497             : 
    2498           0 :         memset(p, 0, sizeof(struct prefix));
    2499             : 
    2500           0 :         switch (p->family = BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) {
    2501           0 :         case AF_INET:
    2502           0 :                 p->u.prefix4 = attr->mp_nexthop_global_in;
    2503           0 :                 p->prefixlen = IPV4_MAX_BITLEN;
    2504           0 :                 break;
    2505             : 
    2506           0 :         case AF_INET6:
    2507           0 :                 p->u.prefix6 = attr->mp_nexthop_global;
    2508           0 :                 p->prefixlen = IPV6_MAX_BITLEN;
    2509           0 :                 break;
    2510             : 
    2511           0 :         default:
    2512           0 :                 vnc_zlog_debug_verbose("%s: Family is unknown = %d", __func__,
    2513             :                                        p->family);
    2514             :         }
    2515           0 : }
    2516             : 
    2517           0 : void rfapiUnicastNexthop2Prefix(afi_t afi, struct attr *attr, struct prefix *p)
    2518             : {
    2519           0 :         if (afi == AFI_IP) {
    2520           0 :                 p->family = AF_INET;
    2521           0 :                 p->prefixlen = IPV4_MAX_BITLEN;
    2522           0 :                 p->u.prefix4 = attr->nexthop;
    2523             :         } else {
    2524           0 :                 rfapiNexthop2Prefix(attr, p);
    2525             :         }
    2526           0 : }
    2527             : 
    2528           0 : static int rfapiAttrNexthopAddrDifferent(struct prefix *p1, struct prefix *p2)
    2529             : {
    2530           0 :         if (!p1 || !p2) {
    2531           0 :                 vnc_zlog_debug_verbose("%s: p1 or p2 is NULL", __func__);
    2532           0 :                 return 1;
    2533             :         }
    2534             : 
    2535             :         /*
    2536             :          * Are address families the same?
    2537             :          */
    2538           0 :         if (p1->family != p2->family) {
    2539             :                 return 1;
    2540             :         }
    2541             : 
    2542           0 :         switch (p1->family) {
    2543           0 :         case AF_INET:
    2544           0 :                 if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
    2545             :                         return 0;
    2546             :                 break;
    2547             : 
    2548           0 :         case AF_INET6:
    2549           0 :                 if (IPV6_ADDR_SAME(&p1->u.prefix6, &p2->u.prefix6))
    2550             :                         return 0;
    2551             :                 break;
    2552             : 
    2553             :         default:
    2554             :                 assert(1);
    2555             :         }
    2556             : 
    2557             :         return 1;
    2558             : }
    2559             : 
    2560           0 : static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
    2561             :                                  struct bgp_path_info *vpn_bpi)
    2562             : {
    2563           0 :         if (!vpn_bpi || !vpn_bpi->extra) {
    2564           0 :                 zlog_warn("%s: no vpn  bpi attr/extra, can't copy UN address",
    2565             :                           __func__);
    2566           0 :                 return;
    2567             :         }
    2568             : 
    2569           0 :         switch (BGP_MP_NEXTHOP_FAMILY(encap_bpi->attr->mp_nexthop_len)) {
    2570             :         case AF_INET:
    2571             : 
    2572             :                 /*
    2573             :                  * instrumentation to debug segfault of 091127
    2574             :                  */
    2575           0 :                 vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
    2576           0 :                 vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__,
    2577             :                                        vpn_bpi->extra);
    2578             : 
    2579           0 :                 vpn_bpi->extra->vnc.import.un_family = AF_INET;
    2580           0 :                 vpn_bpi->extra->vnc.import.un.addr4 =
    2581           0 :                         encap_bpi->attr->mp_nexthop_global_in;
    2582           0 :                 break;
    2583             : 
    2584           0 :         case AF_INET6:
    2585           0 :                 vpn_bpi->extra->vnc.import.un_family = AF_INET6;
    2586           0 :                 vpn_bpi->extra->vnc.import.un.addr6 =
    2587             :                         encap_bpi->attr->mp_nexthop_global;
    2588           0 :                 break;
    2589             : 
    2590             :         default:
    2591           0 :                 zlog_warn("%s: invalid encap nexthop length: %d", __func__,
    2592             :                           encap_bpi->attr->mp_nexthop_len);
    2593           0 :                 vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
    2594           0 :                 break;
    2595             :         }
    2596             : }
    2597             : 
    2598             : /*
    2599             :  * returns 0 on success, nonzero on error
    2600             :  */
    2601             : static int
    2602           0 : rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table,
    2603             :                                  struct bgp_path_info *encap_bpi,
    2604             :                                  struct agg_node *vpn_rn,
    2605             :                                  struct bgp_path_info *vpn_bpi)
    2606             : {
    2607           0 :         if (!encap_bpi) {
    2608             : 
    2609             :                 /*
    2610             :                  * clear cached UN address
    2611             :                  */
    2612           0 :                 if (!vpn_bpi || !vpn_bpi->extra) {
    2613           0 :                         zlog_warn(
    2614             :                                 "%s: missing VPN bpi/extra, can't clear UN addr",
    2615             :                                 __func__);
    2616           0 :                         return 1;
    2617             :                 }
    2618           0 :                 vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
    2619           0 :                 memset(&vpn_bpi->extra->vnc.import.un, 0,
    2620             :                        sizeof(vpn_bpi->extra->vnc.import.un));
    2621           0 :                 if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
    2622           0 :                         if (rfapiGetVncTunnelUnAddr(vpn_bpi->attr, NULL)) {
    2623           0 :                                 UNSET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
    2624           0 :                                 if (VALID_INTERIOR_TYPE(vpn_bpi->type))
    2625           0 :                                         RFAPI_MONITOR_EXTERIOR(vpn_rn)
    2626           0 :                                                 ->valid_interior_count--;
    2627             :                                 /* signal interior route withdrawal to
    2628             :                                  * import-exterior */
    2629           0 :                                 vnc_import_bgp_exterior_del_route_interior(
    2630             :                                         bgp_get_default(), import_table, vpn_rn,
    2631             :                                         vpn_bpi);
    2632             :                         }
    2633             :                 }
    2634             : 
    2635             :         } else {
    2636           0 :                 if (!vpn_bpi) {
    2637           0 :                         zlog_warn("%s: missing VPN bpi, can't clear UN addr",
    2638             :                                   __func__);
    2639           0 :                         return 1;
    2640             :                 }
    2641           0 :                 rfapiCopyUnEncap2VPN(encap_bpi, vpn_bpi);
    2642           0 :                 if (!CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
    2643           0 :                         SET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
    2644           0 :                         if (VALID_INTERIOR_TYPE(vpn_bpi->type))
    2645           0 :                                 RFAPI_MONITOR_EXTERIOR(vpn_rn)
    2646           0 :                                         ->valid_interior_count++;
    2647             :                         /* signal interior route withdrawal to import-exterior
    2648             :                          */
    2649           0 :                         vnc_import_bgp_exterior_add_route_interior(
    2650             :                                 bgp_get_default(), import_table, vpn_rn,
    2651             :                                 vpn_bpi);
    2652             :                 }
    2653             :         }
    2654             :         return 0;
    2655             : }
    2656             : 
    2657           0 : static void rfapiWithdrawTimerEncap(struct thread *t)
    2658             : {
    2659           0 :         struct rfapi_withdraw *wcb = THREAD_ARG(t);
    2660           0 :         struct bgp_path_info *bpi = wcb->info;
    2661           0 :         int was_first_route = 0;
    2662           0 :         struct rfapi_monitor_encap *em;
    2663           0 :         struct skiplist *vpn_node_sl = skiplist_new(0, NULL, NULL);
    2664             : 
    2665           0 :         assert(wcb->node);
    2666           0 :         assert(bpi);
    2667           0 :         assert(wcb->import_table);
    2668             : 
    2669           0 :         RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 0);
    2670             : 
    2671           0 :         if (wcb->node->info == bpi)
    2672           0 :                 was_first_route = 1;
    2673             : 
    2674             :         /*
    2675             :          * Remove the route/bpi and free it
    2676             :          */
    2677           0 :         rfapiBgpInfoDetach(wcb->node, bpi);
    2678           0 :         rfapiBgpInfoFree(bpi);
    2679             : 
    2680           0 :         if (!was_first_route)
    2681           0 :                 goto done;
    2682             : 
    2683           0 :         for (em = RFAPI_MONITOR_ENCAP(wcb->node); em; em = em->next) {
    2684             : 
    2685             :                 /*
    2686             :                  * Update monitoring VPN BPIs with new encap info at the
    2687             :                  * head of the encap bpi chain (which could be NULL after
    2688             :                  * removing the expiring bpi above)
    2689             :                  */
    2690           0 :                 if (rfapiWithdrawEncapUpdateCachedUn(wcb->import_table,
    2691           0 :                                                      wcb->node->info, em->node,
    2692             :                                                      em->bpi))
    2693           0 :                         continue;
    2694             : 
    2695             :                 /*
    2696             :                  * Build a list of unique VPN nodes referenced by these
    2697             :                  * monitors.
    2698             :                  * Use a skiplist for speed.
    2699             :                  */
    2700           0 :                 skiplist_insert(vpn_node_sl, em->node, em->node);
    2701             :         }
    2702             : 
    2703             : 
    2704             :         /*
    2705             :          * for each VPN node referenced in the ENCAP monitors:
    2706             :          */
    2707             :         struct agg_node *rn;
    2708           0 :         while (!skiplist_first(vpn_node_sl, (void **)&rn, NULL)) {
    2709           0 :                 if (!wcb->node->info) {
    2710           0 :                         struct rfapi_monitor_vpn *moved;
    2711             : 
    2712           0 :                         moved = rfapiMonitorMoveShorter(rn, 0);
    2713           0 :                         if (moved) {
    2714             :                                 // rfapiDoRouteCallback(wcb->import_table,
    2715             :                                 // moved->node, moved);
    2716           0 :                                 rfapiMonitorMovedUp(wcb->import_table, rn,
    2717             :                                                     moved->node, moved);
    2718             :                         }
    2719             :                 } else {
    2720             :                         // rfapiDoRouteCallback(wcb->import_table, rn, NULL);
    2721           0 :                         rfapiMonitorItNodeChanged(wcb->import_table, rn, NULL);
    2722             :                 }
    2723           0 :                 skiplist_delete_first(vpn_node_sl);
    2724             :         }
    2725             : 
    2726           0 : done:
    2727           0 :         RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 1);
    2728           0 :         agg_unlock_node(wcb->node); /* decr ref count */
    2729           0 :         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
    2730           0 :         skiplist_free(vpn_node_sl);
    2731           0 : }
    2732             : 
    2733             : 
    2734             : /*
    2735             :  * Works for both VPN and ENCAP routes; timer_service_func is different
    2736             :  * in each case
    2737             :  */
    2738             : static void
    2739           0 : rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
    2740             :                           struct agg_node *rn, struct bgp_path_info *bpi,
    2741             :                           afi_t afi, safi_t safi,
    2742             :                           void (*timer_service_func)(struct thread *))
    2743             : {
    2744           0 :         uint32_t lifetime;
    2745           0 :         struct rfapi_withdraw *wcb;
    2746             : 
    2747           0 :         if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
    2748             :                 /*
    2749             :                  * Already on the path to being withdrawn,
    2750             :                  * should already have a timer set up to
    2751             :                  * delete it.
    2752             :                  */
    2753           0 :                 vnc_zlog_debug_verbose(
    2754             :                         "%s: already being withdrawn, do nothing", __func__);
    2755           0 :                 return;
    2756             :         }
    2757             : 
    2758           0 :         rfapiGetVncLifetime(bpi->attr, &lifetime);
    2759           0 :         vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__, lifetime);
    2760             : 
    2761             :         /*
    2762             :          * withdrawn routes get to hang around for a while
    2763             :          */
    2764           0 :         SET_FLAG(bpi->flags, BGP_PATH_REMOVED);
    2765             : 
    2766             :         /* set timer to remove the route later */
    2767           0 :         lifetime = rfapiGetHolddownFromLifetime(lifetime);
    2768           0 :         vnc_zlog_debug_verbose("%s: using timeout %u", __func__, lifetime);
    2769             : 
    2770             :         /*
    2771             :          * Stash import_table, node, and info for use by timer
    2772             :          * service routine, which is supposed to free the wcb.
    2773             :          */
    2774           0 :         wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
    2775           0 :         wcb->node = rn;
    2776           0 :         wcb->info = bpi;
    2777           0 :         wcb->import_table = import_table;
    2778           0 :         bgp_attr_intern(bpi->attr);
    2779             : 
    2780           0 :         if (VNC_DEBUG(VERBOSE)) {
    2781           0 :                 vnc_zlog_debug_verbose(
    2782             :                         "%s: wcb values: node=%p, info=%p, import_table=%p (bpi follows)",
    2783             :                         __func__, wcb->node, wcb->info, wcb->import_table);
    2784           0 :                 rfapiPrintBi(NULL, bpi);
    2785             :         }
    2786             : 
    2787             : 
    2788           0 :         assert(bpi->extra);
    2789           0 :         if (lifetime > UINT32_MAX / 1001) {
    2790             :                 /* sub-optimal case, but will probably never happen */
    2791           0 :                 bpi->extra->vnc.import.timer = NULL;
    2792           0 :                 thread_add_timer(bm->master, timer_service_func, wcb, lifetime,
    2793             :                                  &bpi->extra->vnc.import.timer);
    2794             :         } else {
    2795           0 :                 static uint32_t jitter;
    2796           0 :                 uint32_t lifetime_msec;
    2797             : 
    2798             :                 /*
    2799             :                  * the goal here is to spread out the timers so they are
    2800             :                  * sortable in the skip list
    2801             :                  */
    2802           0 :                 if (++jitter >= 1000)
    2803           0 :                         jitter = 0;
    2804             : 
    2805           0 :                 lifetime_msec = (lifetime * 1000) + jitter;
    2806             : 
    2807           0 :                 bpi->extra->vnc.import.timer = NULL;
    2808           0 :                 thread_add_timer_msec(bm->master, timer_service_func, wcb,
    2809             :                                       lifetime_msec,
    2810             :                                       &bpi->extra->vnc.import.timer);
    2811             :         }
    2812             : 
    2813             :         /* re-sort route list (BGP_PATH_REMOVED routes are last) */
    2814           0 :         if (((struct bgp_path_info *)rn->info)->next) {
    2815           0 :                 rfapiBgpInfoDetach(rn, bpi);
    2816           0 :                 rfapiBgpInfoAttachSorted(rn, bpi, afi, safi);
    2817             :         }
    2818             : }
    2819             : 
    2820             : 
    2821             : typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *table,
    2822             :                                          int action, struct peer *peer,
    2823             :                                          void *rfd, const struct prefix *prefix,
    2824             :                                          const struct prefix *aux_prefix,
    2825             :                                          afi_t afi, struct prefix_rd *prd,
    2826             :                                          struct attr *attr, uint8_t type,
    2827             :                                          uint8_t sub_type, uint32_t *label);
    2828             : 
    2829             : 
    2830           0 : static void rfapiExpireEncapNow(struct rfapi_import_table *it,
    2831             :                                 struct agg_node *rn, struct bgp_path_info *bpi)
    2832             : {
    2833           0 :         struct rfapi_withdraw *wcb;
    2834           0 :         struct thread t;
    2835             : 
    2836             :         /*
    2837             :          * pretend we're an expiring timer
    2838             :          */
    2839           0 :         wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
    2840           0 :         wcb->info = bpi;
    2841           0 :         wcb->node = rn;
    2842           0 :         wcb->import_table = it;
    2843           0 :         memset(&t, 0, sizeof(t));
    2844           0 :         t.arg = wcb;
    2845           0 :         rfapiWithdrawTimerEncap(&t); /* frees wcb */
    2846           0 : }
    2847             : 
    2848           0 : static int rfapiGetNexthop(struct attr *attr, struct prefix *prefix)
    2849             : {
    2850           0 :         switch (BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) {
    2851             :         case AF_INET:
    2852           0 :                 prefix->family = AF_INET;
    2853           0 :                 prefix->prefixlen = IPV4_MAX_BITLEN;
    2854           0 :                 prefix->u.prefix4 = attr->mp_nexthop_global_in;
    2855           0 :                 break;
    2856           0 :         case AF_INET6:
    2857           0 :                 prefix->family = AF_INET6;
    2858           0 :                 prefix->prefixlen = IPV6_MAX_BITLEN;
    2859           0 :                 prefix->u.prefix6 = attr->mp_nexthop_global;
    2860           0 :                 break;
    2861             :         default:
    2862           0 :                 vnc_zlog_debug_verbose("%s: unknown attr->mp_nexthop_len %d",
    2863             :                                        __func__, attr->mp_nexthop_len);
    2864             :                 return EINVAL;
    2865             :         }
    2866             :         return 0;
    2867             : }
    2868             : 
    2869             : /*
    2870             :  * import a bgp_path_info if its route target list intersects with the
    2871             :  * import table's route target list
    2872             :  */
    2873           0 : static void rfapiBgpInfoFilteredImportEncap(
    2874             :         struct rfapi_import_table *import_table, int action, struct peer *peer,
    2875             :         void *rfd, /* set for looped back routes */
    2876             :         const struct prefix *p,
    2877             :         const struct prefix *aux_prefix, /* Unused for encap routes */
    2878             :         afi_t afi, struct prefix_rd *prd,
    2879             :         struct attr *attr, /* part of bgp_path_info */
    2880             :         uint8_t type,      /* part of bgp_path_info */
    2881             :         uint8_t sub_type,  /* part of bgp_path_info */
    2882             :         uint32_t *label)   /* part of bgp_path_info */
    2883             : {
    2884           0 :         struct agg_table *rt = NULL;
    2885           0 :         struct agg_node *rn;
    2886           0 :         struct bgp_path_info *info_new;
    2887           0 :         struct bgp_path_info *bpi;
    2888           0 :         struct bgp_path_info *next;
    2889           0 :         char buf[BUFSIZ];
    2890             : 
    2891           0 :         struct prefix p_firstbpi_old;
    2892           0 :         struct prefix p_firstbpi_new;
    2893           0 :         int replacing = 0;
    2894           0 :         const char *action_str = NULL;
    2895           0 :         struct prefix un_prefix;
    2896             : 
    2897           0 :         struct bgp *bgp;
    2898           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    2899             : 
    2900           0 :         switch (action) {
    2901             :         case FIF_ACTION_UPDATE:
    2902             :                 action_str = "update";
    2903             :                 break;
    2904           0 :         case FIF_ACTION_WITHDRAW:
    2905           0 :                 action_str = "withdraw";
    2906           0 :                 break;
    2907           0 :         case FIF_ACTION_KILL:
    2908           0 :                 action_str = "kill";
    2909           0 :                 break;
    2910             :         default:
    2911           0 :                 assert(0);
    2912             :                 break;
    2913             :         }
    2914             : 
    2915           0 :         vnc_zlog_debug_verbose(
    2916             :                 "%s: entry: %s: prefix %s/%d", __func__, action_str,
    2917             :                 inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
    2918             :                 p->prefixlen);
    2919             : 
    2920           0 :         memset(&p_firstbpi_old, 0, sizeof(p_firstbpi_old));
    2921           0 :         memset(&p_firstbpi_new, 0, sizeof(p_firstbpi_new));
    2922             : 
    2923           0 :         if (action == FIF_ACTION_UPDATE) {
    2924             :                 /*
    2925             :                  * Compare rt lists. If no intersection, don't import this route
    2926             :                  * On a withdraw, peer and RD are sufficient to determine if
    2927             :                  * we should act.
    2928             :                  */
    2929           0 :                 if (!attr || !bgp_attr_get_ecommunity(attr)) {
    2930             : 
    2931           0 :                         vnc_zlog_debug_verbose(
    2932             :                                 "%s: attr, extra, or ecommunity missing, not importing",
    2933             :                                 __func__);
    2934           0 :                         return;
    2935             :                 }
    2936             : #ifdef RFAPI_REQUIRE_ENCAP_BEEC
    2937             :                 if (!rfapiEcommunitiesMatchBeec(
    2938             :                             bgp_attr_get_ecommunity(attr))) {
    2939             :                         vnc_zlog_debug_verbose(
    2940             :                                 "%s: it=%p: no match for BGP Encapsulation ecommunity",
    2941             :                                 __func__, import_table);
    2942             :                         return;
    2943             :                 }
    2944             : #endif
    2945           0 :                 if (!rfapiEcommunitiesIntersect(
    2946             :                             import_table->rt_import_list,
    2947             :                             bgp_attr_get_ecommunity(attr))) {
    2948             : 
    2949           0 :                         vnc_zlog_debug_verbose(
    2950             :                                 "%s: it=%p: no ecommunity intersection",
    2951             :                                 __func__, import_table);
    2952           0 :                         return;
    2953             :                 }
    2954             : 
    2955             :                 /*
    2956             :                  * Updates must also have a nexthop address
    2957             :                  */
    2958           0 :                 memset(&un_prefix, 0,
    2959             :                        sizeof(un_prefix)); /* keep valgrind happy */
    2960           0 :                 if (rfapiGetNexthop(attr, &un_prefix)) {
    2961           0 :                         vnc_zlog_debug_verbose("%s: missing nexthop address",
    2962             :                                                __func__);
    2963           0 :                         return;
    2964             :                 }
    2965             :         }
    2966             : 
    2967             :         /*
    2968             :          * Figure out which radix tree the route would go into
    2969             :          */
    2970           0 :         switch (afi) {
    2971           0 :         case AFI_IP:
    2972             :         case AFI_IP6:
    2973           0 :                 rt = import_table->imported_encap[afi];
    2974           0 :                 break;
    2975             : 
    2976           0 :         case AFI_UNSPEC:
    2977             :         case AFI_L2VPN:
    2978             :         case AFI_MAX:
    2979           0 :                 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
    2980           0 :                 return;
    2981             :         }
    2982             : 
    2983             :         /*
    2984             :          * agg_node_lookup returns a node only if there is at least
    2985             :          * one route attached.
    2986             :          */
    2987           0 :         rn = agg_node_lookup(rt, p);
    2988             : 
    2989             : #ifdef DEBUG_ENCAP_MONITOR
    2990             :         vnc_zlog_debug_verbose("%s: initial encap lookup(it=%p) rn=%p",
    2991             :                                __func__, import_table, rn);
    2992             : #endif
    2993             : 
    2994           0 :         if (rn) {
    2995             : 
    2996           0 :                 RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 1);
    2997           0 :                 agg_unlock_node(rn); /* undo lock in agg_node_lookup */
    2998             : 
    2999             : 
    3000             :                 /*
    3001             :                  * capture nexthop of first bpi
    3002             :                  */
    3003           0 :                 if (rn->info) {
    3004           0 :                         rfapiNexthop2Prefix(
    3005             :                                 ((struct bgp_path_info *)(rn->info))->attr,
    3006             :                                 &p_firstbpi_old);
    3007             :                 }
    3008             : 
    3009           0 :                 for (bpi = rn->info; bpi; bpi = bpi->next) {
    3010             : 
    3011             :                         /*
    3012             :                          * Does this bgp_path_info refer to the same route
    3013             :                          * as we are trying to add?
    3014             :                          */
    3015           0 :                         vnc_zlog_debug_verbose("%s: comparing BPI %p", __func__,
    3016             :                                                bpi);
    3017             : 
    3018             : 
    3019             :                         /*
    3020             :                          * Compare RDs
    3021             :                          *
    3022             :                          * RD of import table bpi is in
    3023             :                          * bpi->extra->vnc.import.rd RD of info_orig is in prd
    3024             :                          */
    3025           0 :                         if (!bpi->extra) {
    3026           0 :                                 vnc_zlog_debug_verbose("%s: no bpi->extra",
    3027             :                                                        __func__);
    3028           0 :                                 continue;
    3029             :                         }
    3030           0 :                         if (prefix_cmp(
    3031           0 :                                     (struct prefix *)&bpi->extra->vnc.import.rd,
    3032             :                                     (struct prefix *)prd)) {
    3033             : 
    3034           0 :                                 vnc_zlog_debug_verbose("%s: prd does not match",
    3035             :                                                        __func__);
    3036           0 :                                 continue;
    3037             :                         }
    3038             : 
    3039             :                         /*
    3040             :                          * Compare peers
    3041             :                          */
    3042           0 :                         if (bpi->peer != peer) {
    3043           0 :                                 vnc_zlog_debug_verbose(
    3044             :                                         "%s: peer does not match", __func__);
    3045           0 :                                 continue;
    3046             :                         }
    3047             : 
    3048           0 :                         vnc_zlog_debug_verbose("%s: found matching bpi",
    3049             :                                                __func__);
    3050             : 
    3051             :                         /* Same route. Delete this bpi, replace with new one */
    3052             : 
    3053           0 :                         if (action == FIF_ACTION_WITHDRAW) {
    3054             : 
    3055           0 :                                 vnc_zlog_debug_verbose(
    3056             :                                         "%s: withdrawing at prefix %pRN",
    3057             :                                         __func__, rn);
    3058             : 
    3059           0 :                                 rfapiBiStartWithdrawTimer(
    3060             :                                         import_table, rn, bpi, afi, SAFI_ENCAP,
    3061             :                                         rfapiWithdrawTimerEncap);
    3062             : 
    3063             :                         } else {
    3064           0 :                                 vnc_zlog_debug_verbose(
    3065             :                                         "%s: %s at prefix %pRN", __func__,
    3066             :                                         ((action == FIF_ACTION_KILL)
    3067             :                                                  ? "killing"
    3068             :                                                  : "replacing"),
    3069             :                                         rn);
    3070             : 
    3071             :                                 /*
    3072             :                                  * If this route is waiting to be deleted
    3073             :                                  * because of
    3074             :                                  * a previous withdraw, we must cancel its
    3075             :                                  * timer.
    3076             :                                  */
    3077           0 :                                 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
    3078           0 :                                     && bpi->extra->vnc.import.timer) {
    3079           0 :                                         struct rfapi_withdraw *wcb = THREAD_ARG(
    3080             :                                                 bpi->extra->vnc.import.timer);
    3081             : 
    3082           0 :                                         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
    3083           0 :                                         THREAD_OFF(
    3084             :                                                 bpi->extra->vnc.import.timer);
    3085             :                                 }
    3086             : 
    3087           0 :                                 if (action == FIF_ACTION_UPDATE) {
    3088           0 :                                         rfapiBgpInfoDetach(rn, bpi);
    3089           0 :                                         rfapiBgpInfoFree(bpi);
    3090           0 :                                         replacing = 1;
    3091             :                                 } else {
    3092             :                                         /*
    3093             :                                          * Kill: do export stuff when removing
    3094             :                                          * bpi
    3095             :                                          */
    3096           0 :                                         struct rfapi_withdraw *wcb;
    3097           0 :                                         struct thread t;
    3098             : 
    3099             :                                         /*
    3100             :                                          * pretend we're an expiring timer
    3101             :                                          */
    3102           0 :                                         wcb = XCALLOC(
    3103             :                                                 MTYPE_RFAPI_WITHDRAW,
    3104             :                                                 sizeof(struct rfapi_withdraw));
    3105           0 :                                         wcb->info = bpi;
    3106           0 :                                         wcb->node = rn;
    3107           0 :                                         wcb->import_table = import_table;
    3108           0 :                                         memset(&t, 0, sizeof(t));
    3109           0 :                                         t.arg = wcb;
    3110           0 :                                         rfapiWithdrawTimerEncap(
    3111             :                                                 &t); /* frees wcb */
    3112             :                                 }
    3113             :                         }
    3114             : 
    3115             :                         break;
    3116             :                 }
    3117             :         }
    3118             : 
    3119           0 :         if (rn)
    3120           0 :                 RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, replacing ? 1 : 0);
    3121             : 
    3122           0 :         if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL)
    3123             :                 return;
    3124             : 
    3125           0 :         info_new =
    3126           0 :                 rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, NULL);
    3127             : 
    3128           0 :         if (rn) {
    3129           0 :                 if (!replacing)
    3130           0 :                         agg_lock_node(rn); /* incr ref count for new BPI */
    3131             :         } else {
    3132           0 :                 rn = agg_node_get(rt, p);
    3133             :         }
    3134             : 
    3135           0 :         vnc_zlog_debug_verbose("%s: (afi=%d, rn=%p) inserting at prefix %pRN",
    3136             :                                __func__, afi, rn, rn);
    3137             : 
    3138           0 :         rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_ENCAP);
    3139             : 
    3140             :         /*
    3141             :          * Delete holddown routes from same NVE. See details in
    3142             :          * rfapiBgpInfoFilteredImportVPN()
    3143             :          */
    3144           0 :         for (bpi = info_new->next; bpi; bpi = next) {
    3145             : 
    3146           0 :                 struct prefix pfx_un;
    3147           0 :                 int un_match = 0;
    3148             : 
    3149           0 :                 next = bpi->next;
    3150           0 :                 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
    3151           0 :                         continue;
    3152             : 
    3153             :                 /*
    3154             :                  * We already match the VN address (it is the prefix
    3155             :                  * of the route node)
    3156             :                  */
    3157             : 
    3158           0 :                 if (!rfapiGetNexthop(bpi->attr, &pfx_un)
    3159           0 :                     && prefix_same(&pfx_un, &un_prefix)) {
    3160             : 
    3161           0 :                         un_match = 1;
    3162             :                 }
    3163             : 
    3164           0 :                 if (!un_match)
    3165           0 :                         continue;
    3166             : 
    3167           0 :                 vnc_zlog_debug_verbose(
    3168             :                         "%s: removing holddown bpi matching NVE of new route",
    3169             :                         __func__);
    3170           0 :                 if (bpi->extra->vnc.import.timer) {
    3171           0 :                         struct rfapi_withdraw *wcb =
    3172             :                                 THREAD_ARG(bpi->extra->vnc.import.timer);
    3173             : 
    3174           0 :                         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
    3175           0 :                         THREAD_OFF(bpi->extra->vnc.import.timer);
    3176             :                 }
    3177           0 :                 rfapiExpireEncapNow(import_table, rn, bpi);
    3178             :         }
    3179             : 
    3180           0 :         rfapiNexthop2Prefix(((struct bgp_path_info *)(rn->info))->attr,
    3181             :                             &p_firstbpi_new);
    3182             : 
    3183             :         /*
    3184             :          * If the nexthop address of the selected Encap route (i.e.,
    3185             :          * the UN address) has changed, then we must update the VPN
    3186             :          * routes that refer to this Encap route and possibly force
    3187             :          * rfapi callbacks.
    3188             :          */
    3189           0 :         if (rfapiAttrNexthopAddrDifferent(&p_firstbpi_old, &p_firstbpi_new)) {
    3190             : 
    3191           0 :                 struct rfapi_monitor_encap *m;
    3192           0 :                 struct rfapi_monitor_encap *mnext;
    3193             : 
    3194           0 :                 struct agg_node *referenced_vpn_prefix;
    3195             : 
    3196             :                 /*
    3197             :                  * Optimized approach: build radix tree on the fly to
    3198             :                  * hold list of VPN nodes referenced by the ENCAP monitors
    3199             :                  *
    3200             :                  * The nodes in this table correspond to prefixes of VPN routes.
    3201             :                  * The "info" pointer of the node points to a chain of
    3202             :                  * struct rfapi_monitor_encap, each of which refers to a
    3203             :                  * specific VPN node.
    3204             :                  */
    3205           0 :                 struct agg_table *referenced_vpn_table;
    3206             : 
    3207           0 :                 referenced_vpn_table = agg_table_init();
    3208             : 
    3209             : /*
    3210             :  * iterate over the set of monitors at this ENCAP node.
    3211             :  */
    3212             : #ifdef DEBUG_ENCAP_MONITOR
    3213             :                 vnc_zlog_debug_verbose("%s: examining monitors at rn=%p",
    3214             :                                        __func__, rn);
    3215             : #endif
    3216           0 :                 for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) {
    3217           0 :                         const struct prefix *p;
    3218             : 
    3219             :                         /*
    3220             :                          * For each referenced bpi/route, copy the ENCAP route's
    3221             :                          * nexthop to the VPN route's cached UN address field
    3222             :                          * and set
    3223             :                          * the address family of the cached UN address field.
    3224             :                          */
    3225           0 :                         rfapiCopyUnEncap2VPN(info_new, m->bpi);
    3226           0 :                         if (!CHECK_FLAG(m->bpi->flags, BGP_PATH_VALID)) {
    3227           0 :                                 SET_FLAG(m->bpi->flags, BGP_PATH_VALID);
    3228           0 :                                 if (VALID_INTERIOR_TYPE(m->bpi->type))
    3229           0 :                                         RFAPI_MONITOR_EXTERIOR(m->node)
    3230           0 :                                                 ->valid_interior_count++;
    3231           0 :                                 vnc_import_bgp_exterior_add_route_interior(
    3232             :                                         bgp, import_table, m->node, m->bpi);
    3233             :                         }
    3234             : 
    3235             :                         /*
    3236             :                          * Build a list of unique VPN nodes referenced by these
    3237             :                          * monitors
    3238             :                          *
    3239             :                          * There could be more than one VPN node here with a
    3240             :                          * given
    3241             :                          * prefix. Those are currently in an unsorted linear
    3242             :                          * list
    3243             :                          * per prefix.
    3244             :                          */
    3245           0 :                         p = agg_node_get_prefix(m->node);
    3246           0 :                         referenced_vpn_prefix =
    3247           0 :                                 agg_node_get(referenced_vpn_table, p);
    3248           0 :                         assert(referenced_vpn_prefix);
    3249           0 :                         for (mnext = referenced_vpn_prefix->info; mnext;
    3250           0 :                              mnext = mnext->next) {
    3251             : 
    3252           0 :                                 if (mnext->node == m->node)
    3253             :                                         break;
    3254             :                         }
    3255             : 
    3256           0 :                         if (mnext) {
    3257             :                                 /*
    3258             :                                  * already have an entry for this VPN node
    3259             :                                  */
    3260           0 :                                 agg_unlock_node(referenced_vpn_prefix);
    3261             :                         } else {
    3262           0 :                                 mnext = XCALLOC(
    3263             :                                         MTYPE_RFAPI_MONITOR_ENCAP,
    3264             :                                         sizeof(struct rfapi_monitor_encap));
    3265           0 :                                 mnext->node = m->node;
    3266           0 :                                 mnext->next = referenced_vpn_prefix->info;
    3267           0 :                                 referenced_vpn_prefix->info = mnext;
    3268             :                         }
    3269             :                 }
    3270             : 
    3271             :                 /*
    3272             :                  * for each VPN node referenced in the ENCAP monitors:
    3273             :                  */
    3274           0 :                 for (referenced_vpn_prefix =
    3275           0 :                              agg_route_top(referenced_vpn_table);
    3276           0 :                      referenced_vpn_prefix;
    3277           0 :                      referenced_vpn_prefix =
    3278           0 :                              agg_route_next(referenced_vpn_prefix)) {
    3279             : 
    3280           0 :                         while ((m = referenced_vpn_prefix->info)) {
    3281             : 
    3282           0 :                                 struct agg_node *n;
    3283             : 
    3284           0 :                                 rfapiMonitorMoveLonger(m->node);
    3285           0 :                                 for (n = m->node; n; n = agg_node_parent(n)) {
    3286             :                                         // rfapiDoRouteCallback(import_table, n,
    3287             :                                         // NULL);
    3288           0 :                                 }
    3289           0 :                                 rfapiMonitorItNodeChanged(import_table, m->node,
    3290             :                                                           NULL);
    3291             : 
    3292           0 :                                 referenced_vpn_prefix->info = m->next;
    3293           0 :                                 agg_unlock_node(referenced_vpn_prefix);
    3294           0 :                                 XFREE(MTYPE_RFAPI_MONITOR_ENCAP, m);
    3295             :                         }
    3296             :                 }
    3297           0 :                 agg_table_finish(referenced_vpn_table);
    3298             :         }
    3299             : 
    3300           0 :         RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
    3301             : }
    3302             : 
    3303           0 : static void rfapiExpireVpnNow(struct rfapi_import_table *it,
    3304             :                               struct agg_node *rn, struct bgp_path_info *bpi,
    3305             :                               int lockoffset)
    3306             : {
    3307           0 :         struct rfapi_withdraw *wcb;
    3308           0 :         struct thread t;
    3309             : 
    3310             :         /*
    3311             :          * pretend we're an expiring timer
    3312             :          */
    3313           0 :         wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
    3314           0 :         wcb->info = bpi;
    3315           0 :         wcb->node = rn;
    3316           0 :         wcb->import_table = it;
    3317           0 :         wcb->lockoffset = lockoffset;
    3318           0 :         memset(&t, 0, sizeof(t));
    3319           0 :         t.arg = wcb;
    3320           0 :         rfapiWithdrawTimerVPN(&t); /* frees wcb */
    3321           0 : }
    3322             : 
    3323             : 
    3324             : /*
    3325             :  * import a bgp_path_info if its route target list intersects with the
    3326             :  * import table's route target list
    3327             :  */
    3328           0 : void rfapiBgpInfoFilteredImportVPN(
    3329             :         struct rfapi_import_table *import_table, int action, struct peer *peer,
    3330             :         void *rfd, /* set for looped back routes */
    3331             :         const struct prefix *p,
    3332             :         const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
    3333             :         afi_t afi, struct prefix_rd *prd,
    3334             :         struct attr *attr, /* part of bgp_path_info */
    3335             :         uint8_t type,      /* part of bgp_path_info */
    3336             :         uint8_t sub_type,  /* part of bgp_path_info */
    3337             :         uint32_t *label)   /* part of bgp_path_info */
    3338             : {
    3339           0 :         struct agg_table *rt = NULL;
    3340           0 :         struct agg_node *rn;
    3341           0 :         struct agg_node *n;
    3342           0 :         struct bgp_path_info *info_new;
    3343           0 :         struct bgp_path_info *bpi;
    3344           0 :         struct bgp_path_info *next;
    3345           0 :         char buf[BUFSIZ];
    3346           0 :         struct prefix vn_prefix;
    3347           0 :         struct prefix un_prefix;
    3348           0 :         int un_prefix_valid = 0;
    3349           0 :         struct agg_node *ern;
    3350           0 :         int replacing = 0;
    3351           0 :         int original_had_routes = 0;
    3352           0 :         struct prefix original_nexthop;
    3353           0 :         const char *action_str = NULL;
    3354           0 :         int is_it_ce = 0;
    3355             : 
    3356           0 :         struct bgp *bgp;
    3357           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    3358             : 
    3359           0 :         switch (action) {
    3360             :         case FIF_ACTION_UPDATE:
    3361             :                 action_str = "update";
    3362             :                 break;
    3363           0 :         case FIF_ACTION_WITHDRAW:
    3364           0 :                 action_str = "withdraw";
    3365           0 :                 break;
    3366           0 :         case FIF_ACTION_KILL:
    3367           0 :                 action_str = "kill";
    3368           0 :                 break;
    3369             :         default:
    3370           0 :                 assert(0);
    3371             :                 break;
    3372             :         }
    3373             : 
    3374           0 :         if (import_table == bgp->rfapi->it_ce)
    3375           0 :                 is_it_ce = 1;
    3376             : 
    3377           0 :         vnc_zlog_debug_verbose("%s: entry: %s%s: prefix %s/%d: it %p, afi %s",
    3378             :                                __func__, (is_it_ce ? "CE-IT " : ""), action_str,
    3379             :                                rfapi_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
    3380             :                                p->prefixlen, import_table, afi2str(afi));
    3381             : 
    3382           0 :         VNC_ITRCCK;
    3383             : 
    3384             :         /*
    3385             :          * Compare rt lists. If no intersection, don't import this route
    3386             :          * On a withdraw, peer and RD are sufficient to determine if
    3387             :          * we should act.
    3388             :          */
    3389           0 :         if (action == FIF_ACTION_UPDATE) {
    3390           0 :                 if (!attr || !bgp_attr_get_ecommunity(attr)) {
    3391             : 
    3392           0 :                         vnc_zlog_debug_verbose(
    3393             :                                 "%s: attr, extra, or ecommunity missing, not importing",
    3394             :                                 __func__);
    3395           0 :                         return;
    3396             :                 }
    3397           0 :                 if ((import_table != bgp->rfapi->it_ce) &&
    3398           0 :                     !rfapiEcommunitiesIntersect(
    3399             :                             import_table->rt_import_list,
    3400             :                             bgp_attr_get_ecommunity(attr))) {
    3401             : 
    3402           0 :                         vnc_zlog_debug_verbose(
    3403             :                                 "%s: it=%p: no ecommunity intersection",
    3404             :                                 __func__, import_table);
    3405           0 :                         return;
    3406             :                 }
    3407             : 
    3408           0 :                 memset(&vn_prefix, 0,
    3409             :                        sizeof(vn_prefix)); /* keep valgrind happy */
    3410           0 :                 if (rfapiGetNexthop(attr, &vn_prefix)) {
    3411             :                         /* missing nexthop address would be a bad, bad thing */
    3412           0 :                         vnc_zlog_debug_verbose("%s: missing nexthop", __func__);
    3413           0 :                         return;
    3414             :                 }
    3415             :         }
    3416             : 
    3417             :         /*
    3418             :          * Figure out which radix tree the route would go into
    3419             :          */
    3420           0 :         switch (afi) {
    3421           0 :         case AFI_IP:
    3422             :         case AFI_IP6:
    3423             :         case AFI_L2VPN:
    3424           0 :                 rt = import_table->imported_vpn[afi];
    3425           0 :                 break;
    3426             : 
    3427           0 :         case AFI_UNSPEC:
    3428             :         case AFI_MAX:
    3429           0 :                 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
    3430           0 :                 return;
    3431             :         }
    3432             : 
    3433             :         /* clear it */
    3434           0 :         memset(&original_nexthop, 0, sizeof(original_nexthop));
    3435             : 
    3436             :         /*
    3437             :          * agg_node_lookup returns a node only if there is at least
    3438             :          * one route attached.
    3439             :          */
    3440           0 :         rn = agg_node_lookup(rt, p);
    3441             : 
    3442           0 :         vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn);
    3443             : 
    3444           0 :         if (rn) {
    3445             : 
    3446           0 :                 RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
    3447           0 :                 agg_unlock_node(rn); /* undo lock in agg_node_lookup */
    3448             : 
    3449           0 :                 if (rn->info)
    3450           0 :                         original_had_routes = 1;
    3451             : 
    3452           0 :                 if (VNC_DEBUG(VERBOSE)) {
    3453           0 :                         vnc_zlog_debug_verbose("%s: showing IT node on entry",
    3454             :                                                __func__);
    3455           0 :                         rfapiShowItNode(NULL, rn); /* debug */
    3456             :                 }
    3457             : 
    3458             :                 /*
    3459             :                  * Look for same route (will have same RD and peer)
    3460             :                  */
    3461           0 :                 bpi = rfapiItBiIndexSearch(rn, prd, peer, aux_prefix);
    3462             : 
    3463           0 :                 if (bpi) {
    3464             : 
    3465             :                         /*
    3466             :                          * This was an old test when we iterated over the
    3467             :                          * BPIs linearly. Since we're now looking up with
    3468             :                          * RD and peer, comparing types should not be
    3469             :                          * needed. Changed to assertion.
    3470             :                          *
    3471             :                          * Compare types. Doing so prevents a RFP-originated
    3472             :                          * route from matching an imported route, for example.
    3473             :                          */
    3474           0 :                         if (VNC_DEBUG(VERBOSE) && bpi->type != type)
    3475             :                                 /* should be handled by RDs, but warn for now */
    3476           0 :                                 zlog_warn("%s: type mismatch! (bpi=%d, arg=%d)",
    3477             :                                           __func__, bpi->type, type);
    3478             : 
    3479           0 :                         vnc_zlog_debug_verbose("%s: found matching bpi",
    3480             :                                                __func__);
    3481             : 
    3482             :                         /*
    3483             :                          * In the special CE table, withdrawals occur without
    3484             :                          * holddown
    3485             :                          */
    3486           0 :                         if (import_table == bgp->rfapi->it_ce) {
    3487           0 :                                 vnc_direct_bgp_del_route_ce(bgp, rn, bpi);
    3488           0 :                                 if (action == FIF_ACTION_WITHDRAW)
    3489             :                                         action = FIF_ACTION_KILL;
    3490             :                         }
    3491             : 
    3492           0 :                         if (action == FIF_ACTION_WITHDRAW) {
    3493             : 
    3494           0 :                                 int washolddown = CHECK_FLAG(bpi->flags,
    3495             :                                                              BGP_PATH_REMOVED);
    3496             : 
    3497           0 :                                 vnc_zlog_debug_verbose(
    3498             :                                         "%s: withdrawing at prefix %pRN%s",
    3499             :                                         __func__, rn,
    3500             :                                         (washolddown
    3501             :                                                  ? " (already being withdrawn)"
    3502             :                                                  : ""));
    3503             : 
    3504           0 :                                 VNC_ITRCCK;
    3505           0 :                                 if (!washolddown) {
    3506           0 :                                         rfapiBiStartWithdrawTimer(
    3507             :                                                 import_table, rn, bpi, afi,
    3508             :                                                 SAFI_MPLS_VPN,
    3509             :                                                 rfapiWithdrawTimerVPN);
    3510             : 
    3511           0 :                                         RFAPI_UPDATE_ITABLE_COUNT(
    3512           0 :                                                 bpi, import_table, afi, -1);
    3513           0 :                                         import_table->holddown_count[afi] += 1;
    3514             :                                 }
    3515             :                                 VNC_ITRCCK;
    3516             :                         } else {
    3517           0 :                                 vnc_zlog_debug_verbose(
    3518             :                                         "%s: %s at prefix %pRN", __func__,
    3519             :                                         ((action == FIF_ACTION_KILL)
    3520             :                                                  ? "killing"
    3521             :                                                  : "replacing"),
    3522             :                                         rn);
    3523             : 
    3524             :                                 /*
    3525             :                                  * If this route is waiting to be deleted
    3526             :                                  * because of
    3527             :                                  * a previous withdraw, we must cancel its
    3528             :                                  * timer.
    3529             :                                  */
    3530           0 :                                 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
    3531           0 :                                     && bpi->extra->vnc.import.timer) {
    3532           0 :                                         struct rfapi_withdraw *wcb = THREAD_ARG(
    3533             :                                                 bpi->extra->vnc.import.timer);
    3534             : 
    3535           0 :                                         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
    3536           0 :                                         THREAD_OFF(
    3537             :                                                 bpi->extra->vnc.import.timer);
    3538             : 
    3539           0 :                                         import_table->holddown_count[afi] -= 1;
    3540           0 :                                         RFAPI_UPDATE_ITABLE_COUNT(
    3541           0 :                                                 bpi, import_table, afi, 1);
    3542             :                                 }
    3543             :                                 /*
    3544             :                                  * decrement remote count (if route is remote)
    3545             :                                  * because
    3546             :                                  * we are going to remove it below
    3547             :                                  */
    3548           0 :                                 RFAPI_UPDATE_ITABLE_COUNT(bpi, import_table,
    3549           0 :                                                           afi, -1);
    3550           0 :                                 if (action == FIF_ACTION_UPDATE) {
    3551           0 :                                         replacing = 1;
    3552             : 
    3553             :                                         /*
    3554             :                                          * make copy of original nexthop so we
    3555             :                                          * can see if it changed
    3556             :                                          */
    3557           0 :                                         rfapiGetNexthop(bpi->attr,
    3558             :                                                         &original_nexthop);
    3559             : 
    3560             :                                         /*
    3561             :                                          * remove bpi without doing any export
    3562             :                                          * processing
    3563             :                                          */
    3564           0 :                                         if (CHECK_FLAG(bpi->flags,
    3565             :                                                        BGP_PATH_VALID)
    3566           0 :                                             && VALID_INTERIOR_TYPE(bpi->type))
    3567           0 :                                                 RFAPI_MONITOR_EXTERIOR(rn)
    3568           0 :                                                         ->valid_interior_count--;
    3569           0 :                                         rfapiItBiIndexDel(rn, bpi);
    3570           0 :                                         rfapiBgpInfoDetach(rn, bpi);
    3571           0 :                                         rfapiMonitorEncapDelete(bpi);
    3572           0 :                                         vnc_import_bgp_exterior_del_route_interior(
    3573             :                                                 bgp, import_table, rn, bpi);
    3574           0 :                                         rfapiBgpInfoFree(bpi);
    3575             :                                 } else {
    3576             :                                         /* Kill */
    3577             :                                         /*
    3578             :                                          * remove bpi and do export processing
    3579             :                                          */
    3580           0 :                                         import_table->holddown_count[afi] += 1;
    3581           0 :                                         rfapiExpireVpnNow(import_table, rn, bpi,
    3582             :                                                           0);
    3583             :                                 }
    3584             :                         }
    3585             :                 }
    3586             :         }
    3587             : 
    3588           0 :         if (rn)
    3589           0 :                 RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, replacing ? 1 : 0);
    3590             : 
    3591           0 :         if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) {
    3592             :                 VNC_ITRCCK;
    3593             :                 return;
    3594             :         }
    3595             : 
    3596           0 :         info_new =
    3597           0 :                 rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, label);
    3598             : 
    3599             :         /*
    3600             :          * lookup un address in encap table
    3601             :          */
    3602           0 :         ern = agg_node_match(import_table->imported_encap[afi], &vn_prefix);
    3603           0 :         if (ern) {
    3604           0 :                 rfapiCopyUnEncap2VPN(ern->info, info_new);
    3605           0 :                 agg_unlock_node(ern); /* undo lock in route_note_match */
    3606             :         } else {
    3607             :                 /* Not a big deal, just means VPN route got here first */
    3608           0 :                 vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX",
    3609             :                                        __func__, &vn_prefix);
    3610           0 :                 info_new->extra->vnc.import.un_family = AF_UNSPEC;
    3611             :         }
    3612             : 
    3613           0 :         if (rn) {
    3614           0 :                 if (!replacing)
    3615           0 :                         agg_lock_node(rn);
    3616             :         } else {
    3617             :                 /*
    3618             :                  * No need to increment reference count, so only "get"
    3619             :                  * if the node is not there already
    3620             :                  */
    3621           0 :                 rn = agg_node_get(rt, p);
    3622             :         }
    3623             : 
    3624             :         /*
    3625             :          * For ethernet routes, if there is an accompanying IP address,
    3626             :          * save it in the bpi
    3627             :          */
    3628           0 :         if ((AFI_L2VPN == afi) && aux_prefix) {
    3629             : 
    3630           0 :                 vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix",
    3631             :                                        __func__);
    3632           0 :                 info_new->extra->vnc.import.aux_prefix = *aux_prefix;
    3633             :         }
    3634             : 
    3635           0 :         vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d",
    3636             :                                __func__, info_new, rn,
    3637             :                                agg_node_get_lock_count(rn));
    3638             : 
    3639           0 :         rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_MPLS_VPN);
    3640           0 :         rfapiItBiIndexAdd(rn, info_new);
    3641           0 :         if (!rfapiGetUnAddrOfVpnBi(info_new, NULL)) {
    3642           0 :                 if (VALID_INTERIOR_TYPE(info_new->type))
    3643           0 :                         RFAPI_MONITOR_EXTERIOR(rn)->valid_interior_count++;
    3644           0 :                 SET_FLAG(info_new->flags, BGP_PATH_VALID);
    3645             :         }
    3646           0 :         RFAPI_UPDATE_ITABLE_COUNT(info_new, import_table, afi, 1);
    3647           0 :         vnc_import_bgp_exterior_add_route_interior(bgp, import_table, rn,
    3648             :                                                    info_new);
    3649             : 
    3650           0 :         if (import_table == bgp->rfapi->it_ce)
    3651           0 :                 vnc_direct_bgp_add_route_ce(bgp, rn, info_new);
    3652             : 
    3653           0 :         if (VNC_DEBUG(VERBOSE)) {
    3654           0 :                 vnc_zlog_debug_verbose("%s: showing IT node", __func__);
    3655           0 :                 rfapiShowItNode(NULL, rn); /* debug */
    3656             :         }
    3657             : 
    3658           0 :         rfapiMonitorEncapAdd(import_table, &vn_prefix, rn, info_new);
    3659             : 
    3660           0 :         if (!rfapiGetUnAddrOfVpnBi(info_new, &un_prefix)) {
    3661             : 
    3662             :                 /*
    3663             :                  * if we have a valid UN address (either via Encap route
    3664             :                  * or via tunnel attribute), then we should attempt
    3665             :                  * to move any monitors at less-specific nodes to this node
    3666             :                  */
    3667           0 :                 rfapiMonitorMoveLonger(rn);
    3668             : 
    3669           0 :                 un_prefix_valid = 1;
    3670             :         }
    3671             : 
    3672             :         /*
    3673             :          * 101129 Enhancement: if we add a route (implication: it is not
    3674             :          * in holddown), delete all other routes from this nve at this
    3675             :          * node that are in holddown, regardless of peer.
    3676             :          *
    3677             :          * Reasons it's OK to do that:
    3678             :          *
    3679             :          * - if the holddown route being deleted originally came from BGP VPN,
    3680             :          *   it is already gone from BGP (implication of holddown), so there
    3681             :          *   won't be any added inconsistency with the BGP RIB.
    3682             :          *
    3683             :          * - once a fresh route is added at a prefix, any routes in holddown
    3684             :          *   at that prefix will not show up in RFP responses, so deleting
    3685             :          *   the holddown routes won't affect the contents of responses.
    3686             :          *
    3687             :          * - lifetimes are supposed to be consistent, so there should not
    3688             :          *   be a case where the fresh route has a shorter lifetime than
    3689             :          *   the holddown route, so we don't expect the fresh route to
    3690             :          *   disappear and complete its holddown time before the existing
    3691             :          *   holddown routes time out. Therefore, we won't have a situation
    3692             :          *   where we expect the existing holddown routes to be hidden and
    3693             :          *   then  to reappear sometime later (as holddown routes) in a
    3694             :          *   RFP response.
    3695             :          *
    3696             :          * Among other things, this would enable us to skirt the problem
    3697             :          * of local holddown routes that refer to NVE descriptors that
    3698             :          * have already been closed (if the same NVE triggers a subsequent
    3699             :          * rfapi_open(), the new peer is different and doesn't match the
    3700             :          * peer of the holddown route, so the stale holddown route still
    3701             :          * hangs around until it times out instead of just being replaced
    3702             :          * by the fresh route).
    3703             :          */
    3704             :         /*
    3705             :          * We know that the new bpi will have been inserted before any routes
    3706             :          * in holddown, so we can skip any that came before it
    3707             :          */
    3708           0 :         for (bpi = info_new->next; bpi; bpi = next) {
    3709             : 
    3710           0 :                 struct prefix pfx_vn;
    3711           0 :                 struct prefix pfx_un;
    3712           0 :                 int un_match = 0;
    3713           0 :                 int remote_peer_match = 0;
    3714             : 
    3715           0 :                 next = bpi->next;
    3716             : 
    3717             :                 /*
    3718             :                  * Must be holddown
    3719             :                  */
    3720           0 :                 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
    3721           0 :                         continue;
    3722             : 
    3723             :                 /*
    3724             :                  * Must match VN address (nexthop of VPN route)
    3725             :                  */
    3726           0 :                 if (rfapiGetNexthop(bpi->attr, &pfx_vn))
    3727           0 :                         continue;
    3728           0 :                 if (!prefix_same(&pfx_vn, &vn_prefix))
    3729           0 :                         continue;
    3730             : 
    3731           0 :                 if (un_prefix_valid && /* new route UN addr */
    3732           0 :                     !rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)
    3733           0 :                     &&                                  /* old route UN addr */
    3734           0 :                     prefix_same(&pfx_un, &un_prefix)) { /* compare */
    3735           0 :                         un_match = 1;
    3736             :                 }
    3737           0 :                 if (!RFAPI_LOCAL_BI(bpi) && !RFAPI_LOCAL_BI(info_new)
    3738           0 :                     && sockunion_same(&bpi->peer->su, &info_new->peer->su)) {
    3739             :                         /* old & new are both remote, same peer */
    3740           0 :                         remote_peer_match = 1;
    3741             :                 }
    3742             : 
    3743           0 :                 if (!un_match && !remote_peer_match)
    3744           0 :                         continue;
    3745             : 
    3746           0 :                 vnc_zlog_debug_verbose(
    3747             :                         "%s: removing holddown bpi matching NVE of new route",
    3748             :                         __func__);
    3749           0 :                 if (bpi->extra->vnc.import.timer) {
    3750           0 :                         struct rfapi_withdraw *wcb =
    3751             :                                 THREAD_ARG(bpi->extra->vnc.import.timer);
    3752             : 
    3753           0 :                         XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
    3754           0 :                         THREAD_OFF(bpi->extra->vnc.import.timer);
    3755             :                 }
    3756           0 :                 rfapiExpireVpnNow(import_table, rn, bpi, 0);
    3757             :         }
    3758             : 
    3759           0 :         if (!original_had_routes) {
    3760             :                 /*
    3761             :                  * We went from 0 usable routes to 1 usable route. Perform the
    3762             :                  * "Adding a Route" export process.
    3763             :                  */
    3764           0 :                 vnc_direct_bgp_add_prefix(bgp, import_table, rn);
    3765           0 :                 vnc_zebra_add_prefix(bgp, import_table, rn);
    3766             :         } else {
    3767             :                 /*
    3768             :                  * Check for nexthop change event
    3769             :                  * Note: the prefix_same() test below detects two situations:
    3770             :                  * 1. route is replaced, new route has different nexthop
    3771             :                  * 2. new route is added (original_nexthop is 0)
    3772             :                  */
    3773           0 :                 struct prefix new_nexthop;
    3774             : 
    3775           0 :                 rfapiGetNexthop(attr, &new_nexthop);
    3776           0 :                 if (!prefix_same(&original_nexthop, &new_nexthop)) {
    3777             :                         /*
    3778             :                          * nexthop change event
    3779             :                          * vnc_direct_bgp_add_prefix() will recompute VN addr
    3780             :                          * ecommunity
    3781             :                          */
    3782           0 :                         vnc_direct_bgp_add_prefix(bgp, import_table, rn);
    3783             :                 }
    3784             :         }
    3785             : 
    3786           0 :         if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
    3787           0 :                 for (n = rn; n; n = agg_node_parent(n)) {
    3788             :                         // rfapiDoRouteCallback(import_table, n, NULL);
    3789           0 :                 }
    3790           0 :                 rfapiMonitorItNodeChanged(import_table, rn, NULL);
    3791             :         }
    3792           0 :         RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 0);
    3793           0 :         VNC_ITRCCK;
    3794             : }
    3795             : 
    3796           0 : static void rfapiBgpInfoFilteredImportBadSafi(
    3797             :         struct rfapi_import_table *import_table, int action, struct peer *peer,
    3798             :         void *rfd, /* set for looped back routes */
    3799             :         const struct prefix *p,
    3800             :         const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
    3801             :         afi_t afi, struct prefix_rd *prd,
    3802             :         struct attr *attr, /* part of bgp_path_info */
    3803             :         uint8_t type,      /* part of bgp_path_info */
    3804             :         uint8_t sub_type,  /* part of bgp_path_info */
    3805             :         uint32_t *label)   /* part of bgp_path_info */
    3806             : {
    3807           0 :         vnc_zlog_debug_verbose("%s: Error, bad safi", __func__);
    3808           0 : }
    3809             : 
    3810             : static rfapi_bi_filtered_import_f *
    3811           0 : rfapiBgpInfoFilteredImportFunction(safi_t safi)
    3812             : {
    3813           0 :         switch (safi) {
    3814             :         case SAFI_MPLS_VPN:
    3815             :                 return rfapiBgpInfoFilteredImportVPN;
    3816             : 
    3817           0 :         case SAFI_ENCAP:
    3818           0 :                 return rfapiBgpInfoFilteredImportEncap;
    3819             : 
    3820           0 :         case SAFI_UNSPEC:
    3821             :         case SAFI_UNICAST:
    3822             :         case SAFI_MULTICAST:
    3823             :         case SAFI_EVPN:
    3824             :         case SAFI_LABELED_UNICAST:
    3825             :         case SAFI_FLOWSPEC:
    3826             :         case SAFI_MAX:
    3827             :                 /* not expected */
    3828           0 :                 flog_err(EC_LIB_DEVELOPMENT, "%s: bad safi %d", __func__, safi);
    3829           0 :                 return rfapiBgpInfoFilteredImportBadSafi;
    3830             :         }
    3831             : 
    3832           0 :         assert(!"Reached end of function when we were not expecting to");
    3833             : }
    3834             : 
    3835           0 : void rfapiProcessUpdate(struct peer *peer,
    3836             :                         void *rfd, /* set when looped from RFP/RFAPI */
    3837             :                         const struct prefix *p, struct prefix_rd *prd,
    3838             :                         struct attr *attr, afi_t afi, safi_t safi, uint8_t type,
    3839             :                         uint8_t sub_type, uint32_t *label)
    3840             : {
    3841           0 :         struct bgp *bgp;
    3842           0 :         struct rfapi *h;
    3843           0 :         struct rfapi_import_table *it;
    3844           0 :         int has_ip_route = 1;
    3845           0 :         uint32_t lni = 0;
    3846             : 
    3847           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    3848           0 :         assert(bgp);
    3849             : 
    3850           0 :         h = bgp->rfapi;
    3851           0 :         assert(h);
    3852             : 
    3853             :         /*
    3854             :          * look at high-order byte of RD. FF means MAC
    3855             :          * address is present (VNC L2VPN)
    3856             :          */
    3857           0 :         if ((safi == SAFI_MPLS_VPN)
    3858           0 :             && (decode_rd_type(prd->val) == RD_TYPE_VNC_ETH)) {
    3859           0 :                 struct prefix pfx_mac_buf;
    3860           0 :                 struct prefix pfx_nexthop_buf;
    3861           0 :                 int rc;
    3862             : 
    3863             :                 /*
    3864             :                  * Set flag if prefix and nexthop are the same - don't
    3865             :                  * add the route to normal IP-based import tables
    3866             :                  */
    3867           0 :                 if (!rfapiGetNexthop(attr, &pfx_nexthop_buf)) {
    3868           0 :                         if (!prefix_cmp(&pfx_nexthop_buf, p)) {
    3869           0 :                                 has_ip_route = 0;
    3870             :                         }
    3871             :                 }
    3872             : 
    3873           0 :                 memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf));
    3874           0 :                 pfx_mac_buf.family = AF_ETHERNET;
    3875           0 :                 pfx_mac_buf.prefixlen = 48;
    3876           0 :                 memcpy(&pfx_mac_buf.u.prefix_eth.octet, prd->val + 2, 6);
    3877             : 
    3878             :                 /*
    3879             :                  * Find rt containing LNI (Logical Network ID), which
    3880             :                  * _should_ always be present when mac address is present
    3881             :                  */
    3882           0 :                 rc = rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(attr), &lni);
    3883             : 
    3884           0 :                 vnc_zlog_debug_verbose(
    3885             :                         "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
    3886             :                         __func__, rc, lni, attr);
    3887           0 :                 if (!rc) {
    3888           0 :                         it = rfapiMacImportTableGet(bgp, lni);
    3889             : 
    3890           0 :                         rfapiBgpInfoFilteredImportVPN(
    3891             :                                 it, FIF_ACTION_UPDATE, peer, rfd,
    3892             :                                 &pfx_mac_buf, /* prefix */
    3893             :                                 p,          /* aux prefix: IP addr */
    3894             :                                 AFI_L2VPN, prd, attr, type, sub_type, label);
    3895             :                 }
    3896             :         }
    3897             : 
    3898           0 :         if (!has_ip_route)
    3899           0 :                 return;
    3900             : 
    3901             :         /*
    3902             :          * Iterate over all import tables; do a filtered import
    3903             :          * for the afi/safi combination
    3904             :          */
    3905           0 :         for (it = h->imports; it; it = it->next) {
    3906           0 :                 (*rfapiBgpInfoFilteredImportFunction(safi))(
    3907             :                         it, FIF_ACTION_UPDATE, peer, rfd, p, /* prefix */
    3908             :                         NULL, afi, prd, attr, type, sub_type, label);
    3909             :         }
    3910             : 
    3911           0 :         if (safi == SAFI_MPLS_VPN) {
    3912           0 :                 vnc_direct_bgp_rh_add_route(bgp, afi, p, peer, attr);
    3913           0 :                 rfapiBgpInfoFilteredImportVPN(
    3914           0 :                         bgp->rfapi->it_ce, FIF_ACTION_UPDATE, peer, rfd,
    3915             :                         p, /* prefix */
    3916             :                         NULL, afi, prd, attr, type, sub_type, label);
    3917             :         }
    3918             : }
    3919             : 
    3920             : 
    3921           0 : void rfapiProcessWithdraw(struct peer *peer, void *rfd, const struct prefix *p,
    3922             :                           struct prefix_rd *prd, struct attr *attr, afi_t afi,
    3923             :                           safi_t safi, uint8_t type, int kill)
    3924             : {
    3925           0 :         struct bgp *bgp;
    3926           0 :         struct rfapi *h;
    3927           0 :         struct rfapi_import_table *it;
    3928             : 
    3929           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    3930           0 :         assert(bgp);
    3931             : 
    3932           0 :         h = bgp->rfapi;
    3933           0 :         assert(h);
    3934             : 
    3935             :         /*
    3936             :          * look at high-order byte of RD. FF means MAC
    3937             :          * address is present (VNC L2VPN)
    3938             :          */
    3939           0 :         if (h->import_mac != NULL && safi == SAFI_MPLS_VPN
    3940           0 :             && decode_rd_type(prd->val) == RD_TYPE_VNC_ETH) {
    3941           0 :                 struct prefix pfx_mac_buf;
    3942           0 :                 void *cursor = NULL;
    3943           0 :                 int rc;
    3944             : 
    3945           0 :                 memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf));
    3946           0 :                 pfx_mac_buf.family = AF_ETHERNET;
    3947           0 :                 pfx_mac_buf.prefixlen = 48;
    3948           0 :                 memcpy(&pfx_mac_buf.u.prefix_eth, prd->val + 2, 6);
    3949             : 
    3950             :                 /*
    3951             :                  * withdraw does not contain attrs, so we don't have
    3952             :                  * access to the route's LNI, which would ordinarily
    3953             :                  * select the specific mac-based import table. Instead,
    3954             :                  * we must iterate over all mac-based tables and rely
    3955             :                  * on the RD to match.
    3956             :                  *
    3957             :                  * If this approach is too slow, add an index where
    3958             :                  * key is {RD, peer} and value is the import table
    3959             :                  */
    3960           0 :                 for (rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    3961             :                                         &cursor);
    3962           0 :                      rc == 0; rc = skiplist_next(h->import_mac, NULL,
    3963             :                                                  (void **)&it, &cursor)) {
    3964             : 
    3965             : #ifdef DEBUG_L2_EXTRA
    3966             :                         vnc_zlog_debug_verbose(
    3967             :                                 "%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
    3968             :                                 __func__, it);
    3969             : #endif
    3970             : 
    3971           0 :                         rfapiBgpInfoFilteredImportVPN(
    3972             :                                 it,
    3973             :                                 (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
    3974             :                                 peer, rfd, &pfx_mac_buf, /* prefix */
    3975             :                                 p,                       /* aux_prefix: IP */
    3976             :                                 AFI_L2VPN, prd, attr, type, 0,
    3977             :                                 NULL); /* sub_type & label unused for withdraw
    3978             :                                           */
    3979             :                 }
    3980             :         }
    3981             : 
    3982             :         /*
    3983             :          * XXX For the case where the withdraw involves an L2
    3984             :          * route with no IP information, we rely on the lack
    3985             :          * of RT-list intersection to filter out the withdraw
    3986             :          * from the IP-based import tables below
    3987             :          */
    3988             : 
    3989             :         /*
    3990             :          * Iterate over all import tables; do a filtered import
    3991             :          * for the afi/safi combination
    3992             :          */
    3993             : 
    3994           0 :         for (it = h->imports; it; it = it->next) {
    3995           0 :                 (*rfapiBgpInfoFilteredImportFunction(safi))(
    3996             :                         it, (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
    3997             :                         peer, rfd, p, /* prefix */
    3998             :                         NULL, afi, prd, attr, type, 0,
    3999             :                         NULL); /* sub_type & label unused for withdraw */
    4000             :         }
    4001             : 
    4002             :         /* TBD the deletion should happen after the lifetime expires */
    4003           0 :         if (safi == SAFI_MPLS_VPN)
    4004           0 :                 vnc_direct_bgp_rh_del_route(bgp, afi, p, peer);
    4005             : 
    4006           0 :         if (safi == SAFI_MPLS_VPN) {
    4007           0 :                 rfapiBgpInfoFilteredImportVPN(
    4008           0 :                         bgp->rfapi->it_ce,
    4009             :                         (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), peer,
    4010             :                         rfd, p, /* prefix */
    4011             :                         NULL, afi, prd, attr, type, 0,
    4012             :                         NULL); /* sub_type & label unused for withdraw */
    4013             :         }
    4014           0 : }
    4015             : 
    4016             : /*
    4017             :  * TBD optimized withdraw timer algorithm for case of many
    4018             :  * routes expiring at the same time due to peer drop.
    4019             :  */
    4020             : /*
    4021             :  * 1. Visit all BPIs in all ENCAP import tables.
    4022             :  *
    4023             :  *    a. If a bpi's peer is the failed peer, remove the bpi.
    4024             :  *        b. If the removed ENCAP bpi was first in the list of
    4025             :  *       BPIs at this ENCAP node, loop over all monitors
    4026             :  *       at this node:
    4027             :  *
    4028             :  *       (1) for each ENCAP monitor, loop over all its
    4029             :  *           VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
    4030             :  *           flags.
    4031             :  *
    4032             :  * 2. Visit all BPIs in all VPN import tables.
    4033             :  *    a. If a bpi's peer is the failed peer, remove the bpi.
    4034             :  *    b. loop over all the VPN node monitors and set their
    4035             :  *       RFAPI_MON_FLAG_NEEDCALLBACK flags
    4036             :  *    c. If there are no BPIs left at this VPN node,
    4037             :  *
    4038             :  */
    4039             : 
    4040             : 
    4041             : /* surprise, this gets called from peer_delete(), from rfapi_close() */
    4042          10 : static void rfapiProcessPeerDownRt(struct peer *peer,
    4043             :                                    struct rfapi_import_table *import_table,
    4044             :                                    afi_t afi, safi_t safi)
    4045             : {
    4046          10 :         struct agg_node *rn;
    4047          10 :         struct bgp_path_info *bpi;
    4048          10 :         struct agg_table *rt = NULL;
    4049          10 :         void (*timer_service_func)(struct thread *) = NULL;
    4050             : 
    4051          10 :         assert(afi == AFI_IP || afi == AFI_IP6);
    4052             : 
    4053          10 :         VNC_ITRCCK;
    4054             : 
    4055          10 :         switch (safi) {
    4056          10 :         case SAFI_MPLS_VPN:
    4057          10 :                 rt = import_table->imported_vpn[afi];
    4058          10 :                 timer_service_func = rfapiWithdrawTimerVPN;
    4059          10 :                 break;
    4060           0 :         case SAFI_ENCAP:
    4061           0 :                 rt = import_table->imported_encap[afi];
    4062           0 :                 timer_service_func = rfapiWithdrawTimerEncap;
    4063           0 :                 break;
    4064           0 :         case SAFI_UNSPEC:
    4065             :         case SAFI_UNICAST:
    4066             :         case SAFI_MULTICAST:
    4067             :         case SAFI_EVPN:
    4068             :         case SAFI_LABELED_UNICAST:
    4069             :         case SAFI_FLOWSPEC:
    4070             :         case SAFI_MAX:
    4071             :                 /* Suppress uninitialized variable warning */
    4072           0 :                 rt = NULL;
    4073           0 :                 timer_service_func = NULL;
    4074           0 :                 assert(0);
    4075             :         }
    4076             : 
    4077          20 :         for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
    4078           0 :                 for (bpi = rn->info; bpi; bpi = bpi->next) {
    4079           0 :                         if (bpi->peer == peer) {
    4080             : 
    4081           0 :                                 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
    4082             :                                         /* already in holddown, skip */
    4083           0 :                                         continue;
    4084             :                                 }
    4085             : 
    4086           0 :                                 if (safi == SAFI_MPLS_VPN) {
    4087           0 :                                         RFAPI_UPDATE_ITABLE_COUNT(
    4088           0 :                                                 bpi, import_table, afi, -1);
    4089           0 :                                         import_table->holddown_count[afi] += 1;
    4090             :                                 }
    4091           0 :                                 rfapiBiStartWithdrawTimer(import_table, rn, bpi,
    4092             :                                                           afi, safi,
    4093             :                                                           timer_service_func);
    4094             :                         }
    4095             :                 }
    4096             :         }
    4097          10 :         VNC_ITRCCK;
    4098          10 : }
    4099             : 
    4100             : /*
    4101             :  * This gets called when a peer connection drops. We have to remove
    4102             :  * all the routes from this peer.
    4103             :  *
    4104             :  * Current approach is crude. TBD Optimize by setting fewer timers and
    4105             :  * grouping withdrawn routes so we can generate callbacks more
    4106             :  * efficiently.
    4107             :  */
    4108           5 : void rfapiProcessPeerDown(struct peer *peer)
    4109             : {
    4110           5 :         struct bgp *bgp;
    4111           5 :         struct rfapi *h;
    4112           5 :         struct rfapi_import_table *it;
    4113             : 
    4114             :         /*
    4115             :          * If this peer is a "dummy" peer structure atached to a RFAPI
    4116             :          * nve_descriptor, we don't need to walk the import tables
    4117             :          * because the routes are already withdrawn by rfapi_close()
    4118             :          */
    4119           5 :         if (CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
    4120             :                 return;
    4121             : 
    4122             :         /*
    4123             :          * 1. Visit all BPIs in all ENCAP import tables.
    4124             :          *    Start withdraw timer on the BPIs that match peer.
    4125             :          *
    4126             :          * 2. Visit All BPIs in all VPN import tables.
    4127             :          *    Start withdraw timer on the BPIs that match peer.
    4128             :          */
    4129             : 
    4130           5 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    4131           5 :         if (!bgp)
    4132             :                 return;
    4133             : 
    4134           5 :         h = bgp->rfapi;
    4135           5 :         assert(h);
    4136             : 
    4137           5 :         for (it = h->imports; it; it = it->next) {
    4138           0 :                 rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_ENCAP);
    4139           0 :                 rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_ENCAP);
    4140           0 :                 rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_MPLS_VPN);
    4141           0 :                 rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_MPLS_VPN);
    4142             :         }
    4143             : 
    4144           5 :         if (h->it_ce) {
    4145           5 :                 rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
    4146           5 :                 rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
    4147             :         }
    4148             : }
    4149             : 
    4150             : /*
    4151             :  * Import an entire RIB (for an afi/safi) to an import table RIB,
    4152             :  * filtered according to the import table's RT list
    4153             :  *
    4154             :  * TBD: does this function need additions to match rfapiProcessUpdate()
    4155             :  * for, e.g., L2 handling?
    4156             :  */
    4157           2 : static void rfapiBgpTableFilteredImport(struct bgp *bgp,
    4158             :                                         struct rfapi_import_table *it,
    4159             :                                         afi_t afi, safi_t safi)
    4160             : {
    4161           2 :         struct bgp_dest *dest1;
    4162           2 :         struct bgp_dest *dest2;
    4163             : 
    4164             :         /* Only these SAFIs have 2-level RIBS */
    4165           2 :         assert(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP);
    4166             : 
    4167             :         /*
    4168             :          * Now visit all the rd nodes and the nodes of all the
    4169             :          * route tables attached to them, and import the routes
    4170             :          * if they have matching route targets
    4171             :          */
    4172           4 :         for (dest1 = bgp_table_top(bgp->rib[afi][safi]); dest1;
    4173           0 :              dest1 = bgp_route_next(dest1)) {
    4174             : 
    4175           0 :                 if (bgp_dest_has_bgp_path_info_data(dest1)) {
    4176             : 
    4177           0 :                         for (dest2 = bgp_table_top(
    4178           0 :                                      bgp_dest_get_bgp_table_info(dest1));
    4179           0 :                              dest2; dest2 = bgp_route_next(dest2)) {
    4180             : 
    4181           0 :                                 struct bgp_path_info *bpi;
    4182             : 
    4183           0 :                                 for (bpi = bgp_dest_get_bgp_path_info(dest2);
    4184           0 :                                      bpi; bpi = bpi->next) {
    4185           0 :                                         uint32_t label = 0;
    4186             : 
    4187           0 :                                         if (CHECK_FLAG(bpi->flags,
    4188             :                                                        BGP_PATH_REMOVED))
    4189           0 :                                                 continue;
    4190             : 
    4191           0 :                                         if (bpi->extra)
    4192           0 :                                                 label = decode_label(
    4193             :                                                         &bpi->extra->label[0]);
    4194           0 :                                         (*rfapiBgpInfoFilteredImportFunction(
    4195             :                                                 safi))(
    4196             :                                                 it, /* which import table */
    4197             :                                                 FIF_ACTION_UPDATE, bpi->peer,
    4198             :                                                 NULL,
    4199             :                                                 bgp_dest_get_prefix(dest2),
    4200             :                                                 NULL, afi,
    4201             :                                                 (struct prefix_rd *)
    4202           0 :                                                         bgp_dest_get_prefix(
    4203             :                                                                 dest1),
    4204           0 :                                                 bpi->attr, bpi->type,
    4205           0 :                                                 bpi->sub_type, &label);
    4206             :                                 }
    4207             :                         }
    4208             :                 }
    4209             :         }
    4210           2 : }
    4211             : 
    4212             : 
    4213             : /* per-bgp-instance rfapi data */
    4214           1 : struct rfapi *bgp_rfapi_new(struct bgp *bgp)
    4215             : {
    4216           1 :         struct rfapi *h;
    4217           1 :         afi_t afi;
    4218           1 :         struct rfapi_rfp_cfg *cfg = NULL;
    4219           1 :         struct rfapi_rfp_cb_methods *cbm = NULL;
    4220             : 
    4221           1 :         assert(bgp->rfapi_cfg == NULL);
    4222             : 
    4223           1 :         h = XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi));
    4224             : 
    4225           5 :         for (afi = AFI_IP; afi < AFI_MAX; afi++) {
    4226           3 :                 h->un[afi] = agg_table_init();
    4227             :         }
    4228             : 
    4229             :         /*
    4230             :          * initialize the ce import table
    4231             :          */
    4232           1 :         h->it_ce = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
    4233             :                            sizeof(struct rfapi_import_table));
    4234           1 :         h->it_ce->imported_vpn[AFI_IP] = agg_table_init();
    4235           1 :         h->it_ce->imported_vpn[AFI_IP6] = agg_table_init();
    4236           1 :         h->it_ce->imported_encap[AFI_IP] = agg_table_init();
    4237           1 :         h->it_ce->imported_encap[AFI_IP6] = agg_table_init();
    4238           1 :         rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
    4239           1 :         rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
    4240             : 
    4241             :         /*
    4242             :          * Set up work queue for deferred rfapi_close operations
    4243             :          */
    4244           2 :         h->deferred_close_q =
    4245           1 :                 work_queue_new(bm->master, "rfapi deferred close");
    4246           1 :         h->deferred_close_q->spec.workfunc = rfapi_deferred_close_workfunc;
    4247           1 :         h->deferred_close_q->spec.data = h;
    4248             : 
    4249           1 :         h->rfp = rfp_start(bm->master, &cfg, &cbm);
    4250           1 :         bgp->rfapi_cfg = bgp_rfapi_cfg_new(cfg);
    4251           1 :         if (cbm != NULL) {
    4252           1 :                 h->rfp_methods = *cbm;
    4253             :         }
    4254           1 :         return h;
    4255             : }
    4256             : 
    4257           1 : void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h)
    4258             : {
    4259           1 :         afi_t afi;
    4260             : 
    4261           1 :         if (bgp == NULL || h == NULL)
    4262             :                 return;
    4263             : 
    4264           1 :         if (h->resolve_nve_nexthop) {
    4265           0 :                 skiplist_free(h->resolve_nve_nexthop);
    4266           0 :                 h->resolve_nve_nexthop = NULL;
    4267             :         }
    4268             : 
    4269           1 :         agg_table_finish(h->it_ce->imported_vpn[AFI_IP]);
    4270           1 :         agg_table_finish(h->it_ce->imported_vpn[AFI_IP6]);
    4271           1 :         agg_table_finish(h->it_ce->imported_encap[AFI_IP]);
    4272           1 :         agg_table_finish(h->it_ce->imported_encap[AFI_IP6]);
    4273             : 
    4274           1 :         if (h->import_mac) {
    4275           0 :                 struct rfapi_import_table *it;
    4276           0 :                 void *cursor;
    4277           0 :                 int rc;
    4278             : 
    4279           0 :                 for (cursor = NULL,
    4280           0 :                     rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    4281             :                                        &cursor);
    4282           0 :                      !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    4283             :                                              &cursor)) {
    4284             : 
    4285           0 :                         rfapiImportTableFlush(it);
    4286           0 :                         XFREE(MTYPE_RFAPI_IMPORTTABLE, it);
    4287             :                 }
    4288           0 :                 skiplist_free(h->import_mac);
    4289           0 :                 h->import_mac = NULL;
    4290             :         }
    4291             : 
    4292           1 :         work_queue_free_and_null(&h->deferred_close_q);
    4293             : 
    4294           1 :         if (h->rfp != NULL)
    4295           1 :                 rfp_stop(h->rfp);
    4296             : 
    4297           4 :         for (afi = AFI_IP; afi < AFI_MAX; afi++) {
    4298           3 :                 agg_table_finish(h->un[afi]);
    4299             :         }
    4300             : 
    4301           1 :         XFREE(MTYPE_RFAPI_IMPORTTABLE, h->it_ce);
    4302           1 :         XFREE(MTYPE_RFAPI, h);
    4303             : }
    4304             : 
    4305             : struct rfapi_import_table *
    4306           0 : rfapiImportTableRefAdd(struct bgp *bgp, struct ecommunity *rt_import_list,
    4307             :                        struct rfapi_nve_group_cfg *rfg)
    4308             : {
    4309           0 :         struct rfapi *h;
    4310           0 :         struct rfapi_import_table *it;
    4311           0 :         afi_t afi;
    4312             : 
    4313           0 :         h = bgp->rfapi;
    4314           0 :         assert(h);
    4315             : 
    4316           0 :         for (it = h->imports; it; it = it->next) {
    4317           0 :                 if (ecommunity_cmp(it->rt_import_list, rt_import_list))
    4318             :                         break;
    4319             :         }
    4320             : 
    4321           0 :         vnc_zlog_debug_verbose("%s: matched it=%p", __func__, it);
    4322             : 
    4323           0 :         if (!it) {
    4324           0 :                 it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
    4325             :                              sizeof(struct rfapi_import_table));
    4326           0 :                 it->next = h->imports;
    4327           0 :                 h->imports = it;
    4328             : 
    4329           0 :                 it->rt_import_list = ecommunity_dup(rt_import_list);
    4330           0 :                 it->rfg = rfg;
    4331           0 :                 it->monitor_exterior_orphans =
    4332           0 :                         skiplist_new(0, NULL, prefix_free_lists);
    4333             : 
    4334             :                 /*
    4335             :                  * fill import route tables from RIBs
    4336             :                  *
    4337             :                  * Potential area for optimization. If this occurs when
    4338             :                  * tables are large (e.g., the operator adds a nve group
    4339             :                  * with a new RT list to a running system), it could take
    4340             :                  * a while.
    4341             :                  *
    4342             :                  */
    4343           0 :                 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
    4344             : 
    4345           0 :                         it->imported_vpn[afi] = agg_table_init();
    4346           0 :                         it->imported_encap[afi] = agg_table_init();
    4347             : 
    4348           0 :                         rfapiBgpTableFilteredImport(bgp, it, afi,
    4349             :                                                     SAFI_MPLS_VPN);
    4350           0 :                         rfapiBgpTableFilteredImport(bgp, it, afi, SAFI_ENCAP);
    4351             : 
    4352           0 :                         vnc_import_bgp_exterior_redist_enable_it(bgp, afi, it);
    4353             :                 }
    4354             :         }
    4355             : 
    4356           0 :         it->refcount += 1;
    4357             : 
    4358           0 :         return it;
    4359             : }
    4360             : 
    4361             : /*
    4362             :  * skiplist element free function
    4363             :  */
    4364           0 : static void delete_rem_pfx_na_free(void *na)
    4365             : {
    4366           0 :         uint32_t *pCounter = ((struct rfapi_nve_addr *)na)->info;
    4367             : 
    4368           0 :         *pCounter += 1;
    4369           0 :         XFREE(MTYPE_RFAPI_NVE_ADDR, na);
    4370           0 : }
    4371             : 
    4372             : /*
    4373             :  * Common deleter for IP and MAC import tables
    4374             :  */
    4375           0 : static void rfapiDeleteRemotePrefixesIt(
    4376             :         struct bgp *bgp, struct rfapi_import_table *it, struct prefix *un,
    4377             :         struct prefix *vn, struct prefix *p, int delete_active,
    4378             :         int delete_holddown, uint32_t *pARcount, uint32_t *pAHcount,
    4379             :         uint32_t *pHRcount, uint32_t *pHHcount,
    4380             :         struct skiplist *uniq_active_nves, struct skiplist *uniq_holddown_nves)
    4381             : {
    4382           0 :         afi_t afi;
    4383             : 
    4384             : #ifdef DEBUG_L2_EXTRA
    4385             :         {
    4386             :                 char buf_pfx[PREFIX_STRLEN];
    4387             : 
    4388             :                 if (p) {
    4389             :                         prefix2str(p, buf_pfx, sizeof(buf_pfx));
    4390             :                 } else {
    4391             :                         buf_pfx[0] = '*';
    4392             :                         buf_pfx[1] = 0;
    4393             :                 }
    4394             : 
    4395             :                 vnc_zlog_debug_verbose(
    4396             :                         "%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
    4397             :                         __func__, buf_pfx, delete_active, delete_holddown);
    4398             :         }
    4399             : #endif
    4400             : 
    4401           0 :         for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
    4402             : 
    4403           0 :                 struct agg_table *rt;
    4404           0 :                 struct agg_node *rn;
    4405             : 
    4406           0 :                 if (p && (family2afi(p->family) != afi)) {
    4407           0 :                         continue;
    4408             :                 }
    4409             : 
    4410           0 :                 rt = it->imported_vpn[afi];
    4411           0 :                 if (!rt)
    4412           0 :                         continue;
    4413             : 
    4414           0 :                 vnc_zlog_debug_verbose("%s: scanning rt for afi=%d", __func__,
    4415             :                                        afi);
    4416             : 
    4417           0 :                 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
    4418           0 :                         struct bgp_path_info *bpi;
    4419           0 :                         struct bgp_path_info *next;
    4420           0 :                         const struct prefix *rn_p = agg_node_get_prefix(rn);
    4421             : 
    4422           0 :                         if (p && VNC_DEBUG(IMPORT_DEL_REMOTE))
    4423           0 :                                 vnc_zlog_debug_any("%s: want %pFX, have %pRN",
    4424             :                                                    __func__, p, rn);
    4425             : 
    4426           0 :                         if (p && prefix_cmp(p, rn_p))
    4427           0 :                                 continue;
    4428             : 
    4429           0 :                         vnc_zlog_debug_verbose("%s: rn pfx=%pRN", __func__, rn);
    4430             : 
    4431             :                         /* TBD is this valid for afi == AFI_L2VPN? */
    4432           0 :                         RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
    4433             : 
    4434           0 :                         for (bpi = rn->info; bpi; bpi = next) {
    4435           0 :                                 next = bpi->next;
    4436             : 
    4437           0 :                                 struct prefix qpt;
    4438           0 :                                 struct prefix qct;
    4439           0 :                                 int qpt_valid = 0;
    4440           0 :                                 int qct_valid = 0;
    4441           0 :                                 int is_active = 0;
    4442             : 
    4443           0 :                                 vnc_zlog_debug_verbose("%s: examining bpi %p",
    4444             :                                                        __func__, bpi);
    4445             : 
    4446           0 :                                 if (!rfapiGetNexthop(bpi->attr, &qpt))
    4447           0 :                                         qpt_valid = 1;
    4448             : 
    4449           0 :                                 if (vn) {
    4450           0 :                                         if (!qpt_valid
    4451           0 :                                             || !prefix_match(vn, &qpt)) {
    4452             : #ifdef DEBUG_L2_EXTRA
    4453             :                                                 vnc_zlog_debug_verbose(
    4454             :                                                         "%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
    4455             :                                                         __func__);
    4456             : #endif
    4457           0 :                                                 continue;
    4458             :                                         }
    4459             :                                 }
    4460             : 
    4461           0 :                                 if (!rfapiGetUnAddrOfVpnBi(bpi, &qct))
    4462           0 :                                         qct_valid = 1;
    4463             : 
    4464           0 :                                 if (un) {
    4465           0 :                                         if (!qct_valid
    4466           0 :                                             || !prefix_match(un, &qct)) {
    4467             : #ifdef DEBUG_L2_EXTRA
    4468             :                                                 vnc_zlog_debug_verbose(
    4469             :                                                         "%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
    4470             :                                                         __func__);
    4471             : #endif
    4472           0 :                                                 continue;
    4473             :                                         }
    4474             :                                 }
    4475             : 
    4476             : 
    4477             :                                 /*
    4478             :                                  * Blow bpi away
    4479             :                                  */
    4480             :                                 /*
    4481             :                                  * If this route is waiting to be deleted
    4482             :                                  * because of
    4483             :                                  * a previous withdraw, we must cancel its
    4484             :                                  * timer.
    4485             :                                  */
    4486           0 :                                 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
    4487           0 :                                         if (!delete_holddown)
    4488           0 :                                                 continue;
    4489           0 :                                         if (bpi->extra->vnc.import.timer) {
    4490           0 :                                                 struct rfapi_withdraw *wcb =
    4491             :                                                         THREAD_ARG(
    4492             :                                                                 bpi->extra->vnc
    4493             :                                                                         .import
    4494             :                                                                         .timer);
    4495             : 
    4496           0 :                                                 wcb->import_table
    4497           0 :                                                         ->holddown_count[afi] -=
    4498             :                                                         1;
    4499           0 :                                                 RFAPI_UPDATE_ITABLE_COUNT(
    4500             :                                                         bpi, wcb->import_table,
    4501           0 :                                                         afi, 1);
    4502           0 :                                                 XFREE(MTYPE_RFAPI_WITHDRAW,
    4503             :                                                       wcb);
    4504           0 :                                                 THREAD_OFF(
    4505             :                                                         bpi->extra->vnc.import
    4506             :                                                                 .timer);
    4507             :                                         }
    4508             :                                 } else {
    4509           0 :                                         if (!delete_active)
    4510           0 :                                                 continue;
    4511             :                                         is_active = 1;
    4512             :                                 }
    4513             : 
    4514           0 :                                 vnc_zlog_debug_verbose(
    4515             :                                         "%s: deleting bpi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
    4516             :                                         __func__, bpi, qct_valid, qpt_valid,
    4517             :                                         delete_holddown, delete_active);
    4518             : 
    4519             : 
    4520             :                                 /*
    4521             :                                  * add nve to list
    4522             :                                  */
    4523           0 :                                 if (qct_valid && qpt_valid) {
    4524             : 
    4525           0 :                                         struct rfapi_nve_addr na;
    4526           0 :                                         struct rfapi_nve_addr *nap;
    4527             : 
    4528           0 :                                         memset(&na, 0, sizeof(na));
    4529           0 :                                         assert(!rfapiQprefix2Raddr(&qct,
    4530             :                                                                    &na.un));
    4531           0 :                                         assert(!rfapiQprefix2Raddr(&qpt,
    4532             :                                                                    &na.vn));
    4533             : 
    4534           0 :                                         if (skiplist_search(
    4535             :                                                     (is_active
    4536             :                                                              ? uniq_active_nves
    4537             :                                                              : uniq_holddown_nves),
    4538             :                                                     &na, (void **)&nap)) {
    4539           0 :                                                 char line[BUFSIZ];
    4540             : 
    4541           0 :                                                 nap = XCALLOC(
    4542             :                                                         MTYPE_RFAPI_NVE_ADDR,
    4543             :                                                         sizeof(struct
    4544             :                                                                rfapi_nve_addr));
    4545           0 :                                                 *nap = na;
    4546           0 :                                                 nap->info = is_active
    4547             :                                                                     ? pAHcount
    4548             :                                                                     : pHHcount;
    4549           0 :                                                 skiplist_insert(
    4550             :                                                         (is_active
    4551             :                                                                  ? uniq_active_nves
    4552             :                                                                  : uniq_holddown_nves),
    4553             :                                                         nap, nap);
    4554             : 
    4555           0 :                                                 rfapiNveAddr2Str(nap, line,
    4556             :                                                                  BUFSIZ);
    4557             :                                         }
    4558             :                                 }
    4559             : 
    4560           0 :                                 vnc_direct_bgp_rh_del_route(bgp, afi, rn_p,
    4561             :                                                             bpi->peer);
    4562             : 
    4563           0 :                                 RFAPI_UPDATE_ITABLE_COUNT(bpi, it, afi, -1);
    4564           0 :                                 it->holddown_count[afi] += 1;
    4565           0 :                                 rfapiExpireVpnNow(it, rn, bpi, 1);
    4566             : 
    4567           0 :                                 vnc_zlog_debug_verbose(
    4568             :                                         "%s: incrementing count (is_active=%d)",
    4569             :                                         __func__, is_active);
    4570             : 
    4571           0 :                                 if (is_active)
    4572           0 :                                         ++*pARcount;
    4573             :                                 else
    4574           0 :                                         ++*pHRcount;
    4575             :                         }
    4576             :                 }
    4577             :         }
    4578           0 : }
    4579             : 
    4580             : 
    4581             : /*
    4582             :  * For use by the "clear vnc prefixes" command
    4583             :  */
    4584             : /*------------------------------------------
    4585             :  * rfapiDeleteRemotePrefixes
    4586             :  *
    4587             :  * UI helper: For use by the "clear vnc prefixes" command
    4588             :  *
    4589             :  * input:
    4590             :  *      un                      if set, tunnel must match this prefix
    4591             :  *      vn                      if set, nexthop prefix must match this prefix
    4592             :  *      p                       if set, prefix must match this prefix
    4593             :  *      it                      if set, only look in this import table
    4594             :  *
    4595             :  * output
    4596             :  *      pARcount                number of active routes deleted
    4597             :  *      pAHcount                number of active nves deleted
    4598             :  *      pHRcount                number of holddown routes deleted
    4599             :  *      pHHcount                number of holddown nves deleted
    4600             :  *
    4601             :  * return value:
    4602             :  *      void
    4603             :  --------------------------------------------*/
    4604           0 : void rfapiDeleteRemotePrefixes(struct prefix *un, struct prefix *vn,
    4605             :                                struct prefix *p,
    4606             :                                struct rfapi_import_table *arg_it,
    4607             :                                int delete_active, int delete_holddown,
    4608             :                                uint32_t *pARcount, uint32_t *pAHcount,
    4609             :                                uint32_t *pHRcount, uint32_t *pHHcount)
    4610             : {
    4611           0 :         struct bgp *bgp;
    4612           0 :         struct rfapi *h;
    4613           0 :         struct rfapi_import_table *it;
    4614           0 :         uint32_t deleted_holddown_route_count = 0;
    4615           0 :         uint32_t deleted_active_route_count = 0;
    4616           0 :         uint32_t deleted_holddown_nve_count = 0;
    4617           0 :         uint32_t deleted_active_nve_count = 0;
    4618           0 :         struct skiplist *uniq_holddown_nves;
    4619           0 :         struct skiplist *uniq_active_nves;
    4620             : 
    4621           0 :         VNC_ITRCCK;
    4622             : 
    4623           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    4624             :         /* If no bgp instantiated yet, no vnc prefixes exist */
    4625           0 :         if (!bgp)
    4626           0 :                 return;
    4627             : 
    4628           0 :         h = bgp->rfapi;
    4629           0 :         assert(h);
    4630             : 
    4631           0 :         uniq_holddown_nves =
    4632           0 :                 skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
    4633           0 :         uniq_active_nves =
    4634           0 :                 skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
    4635             : 
    4636             :         /*
    4637             :          * Iterate over all import tables; do a filtered import
    4638             :          * for the afi/safi combination
    4639             :          */
    4640             : 
    4641           0 :         if (arg_it)
    4642           0 :                 it = arg_it;
    4643             :         else
    4644           0 :                 it = h->imports;
    4645           0 :         for (; it;) {
    4646             : 
    4647           0 :                 vnc_zlog_debug_verbose(
    4648             :                         "%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
    4649             :                         __func__, it);
    4650             : 
    4651           0 :                 rfapiDeleteRemotePrefixesIt(
    4652             :                         bgp, it, un, vn, p, delete_active, delete_holddown,
    4653             :                         &deleted_active_route_count, &deleted_active_nve_count,
    4654             :                         &deleted_holddown_route_count,
    4655             :                         &deleted_holddown_nve_count, uniq_active_nves,
    4656             :                         uniq_holddown_nves);
    4657             : 
    4658           0 :                 if (arg_it)
    4659           0 :                         it = NULL;
    4660             :                 else
    4661           0 :                         it = it->next;
    4662             :         }
    4663             : 
    4664             :         /*
    4665             :          * Now iterate over L2 import tables
    4666             :          */
    4667           0 :         if (h->import_mac && !(p && (p->family != AF_ETHERNET))) {
    4668             : 
    4669           0 :                 void *cursor = NULL;
    4670           0 :                 int rc;
    4671             : 
    4672           0 :                 for (cursor = NULL,
    4673           0 :                     rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    4674             :                                        &cursor);
    4675           0 :                      !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    4676             :                                              &cursor)) {
    4677             : 
    4678           0 :                         vnc_zlog_debug_verbose(
    4679             :                                 "%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
    4680             :                                 __func__, it);
    4681             : 
    4682           0 :                         rfapiDeleteRemotePrefixesIt(
    4683             :                                 bgp, it, un, vn, p, delete_active,
    4684             :                                 delete_holddown, &deleted_active_route_count,
    4685             :                                 &deleted_active_nve_count,
    4686             :                                 &deleted_holddown_route_count,
    4687             :                                 &deleted_holddown_nve_count, uniq_active_nves,
    4688             :                                 uniq_holddown_nves);
    4689             :                 }
    4690             :         }
    4691             : 
    4692             :         /*
    4693             :          * our custom element freeing function above counts as it deletes
    4694             :          */
    4695           0 :         skiplist_free(uniq_holddown_nves);
    4696           0 :         skiplist_free(uniq_active_nves);
    4697             : 
    4698           0 :         if (pARcount)
    4699           0 :                 *pARcount = deleted_active_route_count;
    4700           0 :         if (pAHcount)
    4701           0 :                 *pAHcount = deleted_active_nve_count;
    4702           0 :         if (pHRcount)
    4703           0 :                 *pHRcount = deleted_holddown_route_count;
    4704           0 :         if (pHHcount)
    4705           0 :                 *pHHcount = deleted_holddown_nve_count;
    4706             : 
    4707           0 :         VNC_ITRCCK;
    4708             : }
    4709             : 
    4710             : /*------------------------------------------
    4711             :  * rfapiCountRemoteRoutes
    4712             :  *
    4713             :  * UI helper: count VRF routes from BGP side
    4714             :  *
    4715             :  * input:
    4716             :  *
    4717             :  * output
    4718             :  *      pALRcount               count of active local routes
    4719             :  *      pARRcount               count of active remote routes
    4720             :  *      pHRcount                count of holddown routes
    4721             :  *      pIRcount                count of direct imported routes
    4722             :  *
    4723             :  * return value:
    4724             :  *      void
    4725             :  --------------------------------------------*/
    4726           0 : void rfapiCountAllItRoutes(int *pALRcount, /* active local routes */
    4727             :                            int *pARRcount, /* active remote routes */
    4728             :                            int *pHRcount,  /* holddown routes */
    4729             :                            int *pIRcount)  /* imported routes */
    4730             : {
    4731           0 :         struct bgp *bgp;
    4732           0 :         struct rfapi *h;
    4733           0 :         struct rfapi_import_table *it;
    4734           0 :         afi_t afi;
    4735             : 
    4736           0 :         int total_active_local = 0;
    4737           0 :         int total_active_remote = 0;
    4738           0 :         int total_holddown = 0;
    4739           0 :         int total_imported = 0;
    4740             : 
    4741           0 :         bgp = bgp_get_default(); /* assume 1 instance for now */
    4742           0 :         assert(bgp);
    4743             : 
    4744           0 :         h = bgp->rfapi;
    4745           0 :         assert(h);
    4746             : 
    4747             :         /*
    4748             :          * Iterate over all import tables; do a filtered import
    4749             :          * for the afi/safi combination
    4750             :          */
    4751             : 
    4752           0 :         for (it = h->imports; it; it = it->next) {
    4753             : 
    4754           0 :                 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
    4755             : 
    4756           0 :                         total_active_local += it->local_count[afi];
    4757           0 :                         total_active_remote += it->remote_count[afi];
    4758           0 :                         total_holddown += it->holddown_count[afi];
    4759           0 :                         total_imported += it->imported_count[afi];
    4760             :                 }
    4761             :         }
    4762             : 
    4763           0 :         void *cursor;
    4764           0 :         int rc;
    4765             : 
    4766           0 :         if (h->import_mac) {
    4767           0 :                 for (cursor = NULL,
    4768           0 :                     rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    4769             :                                        &cursor);
    4770           0 :                      !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
    4771             :                                              &cursor)) {
    4772             : 
    4773           0 :                         total_active_local += it->local_count[AFI_L2VPN];
    4774           0 :                         total_active_remote += it->remote_count[AFI_L2VPN];
    4775           0 :                         total_holddown += it->holddown_count[AFI_L2VPN];
    4776           0 :                         total_imported += it->imported_count[AFI_L2VPN];
    4777             :                 }
    4778             :         }
    4779             : 
    4780             : 
    4781           0 :         if (pALRcount) {
    4782           0 :                 *pALRcount = total_active_local;
    4783             :         }
    4784           0 :         if (pARRcount) {
    4785           0 :                 *pARRcount = total_active_remote;
    4786             :         }
    4787           0 :         if (pHRcount) {
    4788           0 :                 *pHRcount = total_holddown;
    4789             :         }
    4790           0 :         if (pIRcount) {
    4791           0 :                 *pIRcount = total_imported;
    4792             :         }
    4793           0 : }
    4794             : 
    4795             : /*------------------------------------------
    4796             :  * rfapiGetHolddownFromLifetime
    4797             :  *
    4798             :  * calculate holddown value based on lifetime
    4799             :  *
    4800             :  * input:
    4801             :  *     lifetime                lifetime
    4802             :  *
    4803             :  * return value:
    4804             :  *     Holddown value based on lifetime, holddown_factor,
    4805             :  *     and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
    4806             :  *
    4807             :  --------------------------------------------*/
    4808             : /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
    4809           0 : uint32_t rfapiGetHolddownFromLifetime(uint32_t lifetime)
    4810             : {
    4811           0 :         uint32_t factor;
    4812           0 :         struct bgp *bgp;
    4813             : 
    4814           0 :         bgp = bgp_get_default();
    4815           0 :         if (bgp && bgp->rfapi_cfg)
    4816           0 :                 factor = bgp->rfapi_cfg->rfp_cfg.holddown_factor;
    4817             :         else
    4818             :                 factor = RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR;
    4819             : 
    4820           0 :         if (factor < 100 || lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
    4821           0 :                 lifetime = lifetime * factor / 100;
    4822           0 :         if (lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
    4823             :                 return lifetime;
    4824             :         else
    4825           0 :                 return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY;
    4826             : }

Generated by: LCOV version v1.16-topotato