back to topotato report
topotato coverage report
Current view: top level - bgpd/rfapi - rfapi_monitor.c (source / functions) Hit Total Coverage
Test: test_exabgp_demo.py::ExaBGPDemo Lines: 0 588 0.0 %
Date: 2023-02-24 18:37:55 Functions: 0 30 0.0 %

          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_monitor.c
      23             :  */
      24             : 
      25             : /* TBD remove unneeded includes */
      26             : 
      27             : #include "lib/zebra.h"
      28             : #include "lib/prefix.h"
      29             : #include "lib/agg_table.h"
      30             : #include "lib/vty.h"
      31             : #include "lib/memory.h"
      32             : #include "lib/log.h"
      33             : #include "lib/table.h"
      34             : #include "lib/skiplist.h"
      35             : 
      36             : #include "bgpd/bgpd.h"
      37             : 
      38             : #include "bgpd/rfapi/bgp_rfapi_cfg.h"
      39             : #include "bgpd/rfapi/rfapi.h"
      40             : #include "bgpd/rfapi/rfapi_backend.h"
      41             : 
      42             : #include "bgpd/rfapi/rfapi.h"
      43             : #include "bgpd/rfapi/rfapi_import.h"
      44             : #include "bgpd/rfapi/vnc_import_bgp.h"
      45             : #include "bgpd/rfapi/rfapi_private.h"
      46             : #include "bgpd/rfapi/rfapi_monitor.h"
      47             : #include "bgpd/rfapi/rfapi_vty.h"
      48             : #include "bgpd/rfapi/rfapi_rib.h"
      49             : #include "bgpd/rfapi/vnc_debug.h"
      50             : 
      51             : #define DEBUG_L2_EXTRA 0
      52             : #define DEBUG_DUP_CHECK 0
      53             : #define DEBUG_ETH_SL 0
      54             : 
      55             : static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m);
      56             : 
      57             : static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m);
      58             : 
      59             : /*
      60             :  * Forward declarations
      61             :  */
      62             : static void rfapiMonitorEthDetachImport(struct bgp *bgp,
      63             :                                         struct rfapi_monitor_eth *mon);
      64             : 
      65             : #if DEBUG_ETH_SL
      66             : /*
      67             :  * Debug function, special case
      68             :  */
      69             : void rfapiMonitorEthSlCheck(struct agg_node *rn, const char *tag1,
      70             :                             const char *tag2)
      71             : {
      72             :         struct agg_node *rn_saved = NULL;
      73             :         static struct skiplist *sl_saved = NULL;
      74             :         struct skiplist *sl;
      75             : 
      76             :         if (!rn)
      77             :                 return;
      78             : 
      79             :         if (rn_saved && (rn != rn_saved))
      80             :                 return;
      81             : 
      82             :         if (!rn_saved)
      83             :                 rn_saved = rn;
      84             : 
      85             :         sl = RFAPI_MONITOR_ETH(rn);
      86             :         if (sl || sl_saved) {
      87             :                 vnc_zlog_debug_verbose(
      88             :                         "%s[%s%s]: rn=%p, rn->lock=%d, old sl=%p, new sl=%p",
      89             :                         __func__, (tag1 ? tag1 : ""), (tag2 ? tag2 : ""), rn,
      90             :                         rn->lock, sl_saved, sl);
      91             :                 sl_saved = sl;
      92             :         }
      93             : }
      94             : #endif
      95             : 
      96             : /*
      97             :  * Debugging function that aborts when it finds monitors whose
      98             :  * "next" pointer * references themselves
      99             :  */
     100           0 : void rfapiMonitorLoopCheck(struct rfapi_monitor_vpn *mchain)
     101             : {
     102           0 :         struct rfapi_monitor_vpn *m;
     103             : 
     104           0 :         for (m = mchain; m; m = m->next)
     105           0 :                 assert(m != m->next);
     106           0 : }
     107             : 
     108             : #if DEBUG_DUP_CHECK
     109             : /*
     110             :  * Debugging code: see if a monitor is mentioned more than once
     111             :  * in a HD's monitor list
     112             :  */
     113             : void rfapiMonitorDupCheck(struct bgp *bgp)
     114             : {
     115             :         struct listnode *hnode;
     116             :         struct rfapi_descriptor *rfd;
     117             : 
     118             :         for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, hnode, rfd)) {
     119             :                 struct agg_node *mrn;
     120             : 
     121             :                 if (!rfd->mon)
     122             :                         continue;
     123             : 
     124             :                 for (mrn = agg_route_top(rfd->mon); mrn;
     125             :                      mrn = agg_route_next(mrn)) {
     126             :                         struct rfapi_monitor_vpn *m;
     127             :                         for (m = (struct rfapi_monitor_vpn *)(mrn->info); m;
     128             :                              m = m->next)
     129             :                                 m->dcount = 0;
     130             :                 }
     131             :         }
     132             : 
     133             :         for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, hnode, rfd)) {
     134             :                 struct agg_node *mrn;
     135             : 
     136             :                 if (!rfd->mon)
     137             :                         continue;
     138             : 
     139             :                 for (mrn = agg_route_top(rfd->mon); mrn;
     140             :                      mrn = agg_route_next(mrn)) {
     141             :                         struct rfapi_monitor_vpn *m;
     142             : 
     143             :                         for (m = (struct rfapi_monitor_vpn *)(mrn->info); m;
     144             :                              m = m->next)
     145             :                                 assert(++m->dcount == 1);
     146             :                 }
     147             :         }
     148             : }
     149             : #endif
     150             : 
     151             : /* debug */
     152           0 : void rfapiMonitorCleanCheck(struct bgp *bgp)
     153             : {
     154           0 :         struct listnode *hnode;
     155           0 :         struct rfapi_descriptor *rfd;
     156             : 
     157           0 :         for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, hnode, rfd)) {
     158           0 :                 assert(!rfd->import_table->vpn0_queries[AFI_IP]);
     159           0 :                 assert(!rfd->import_table->vpn0_queries[AFI_IP6]);
     160             : 
     161           0 :                 struct agg_node *rn;
     162             : 
     163           0 :                 for (rn = agg_route_top(
     164             :                              rfd->import_table->imported_vpn[AFI_IP]);
     165           0 :                      rn; rn = agg_route_next(rn)) {
     166             : 
     167           0 :                         assert(!RFAPI_MONITOR_VPN(rn));
     168             :                 }
     169           0 :                 for (rn = agg_route_top(
     170           0 :                              rfd->import_table->imported_vpn[AFI_IP6]);
     171           0 :                      rn; rn = agg_route_next(rn)) {
     172             : 
     173           0 :                         assert(!RFAPI_MONITOR_VPN(rn));
     174             :                 }
     175             :         }
     176           0 : }
     177             : 
     178             : /* debug */
     179           0 : void rfapiMonitorCheckAttachAllowed(void)
     180             : {
     181           0 :         struct bgp *bgp = bgp_get_default();
     182           0 :         assert(!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE));
     183           0 : }
     184             : 
     185           0 : void rfapiMonitorExtraFlush(safi_t safi, struct agg_node *rn)
     186             : {
     187           0 :         struct rfapi_it_extra *hie;
     188           0 :         struct rfapi_monitor_vpn *v;
     189           0 :         struct rfapi_monitor_vpn *v_next;
     190           0 :         struct rfapi_monitor_encap *e = NULL;
     191           0 :         struct rfapi_monitor_encap *e_next = NULL;
     192             : 
     193           0 :         if (!rn)
     194             :                 return;
     195             : 
     196           0 :         if (!rn->aggregate)
     197             :                 return;
     198             : 
     199           0 :         hie = (struct rfapi_it_extra *)(rn->aggregate);
     200             : 
     201           0 :         switch (safi) {
     202           0 :         case SAFI_ENCAP:
     203           0 :                 for (e = hie->u.encap.e; e; e = e_next) {
     204           0 :                         e_next = e->next;
     205           0 :                         e->next = NULL;
     206           0 :                         XFREE(MTYPE_RFAPI_MONITOR_ENCAP, e);
     207           0 :                         agg_unlock_node(rn);
     208             :                 }
     209           0 :                 hie->u.encap.e = NULL;
     210           0 :                 break;
     211             : 
     212           0 :         case SAFI_MPLS_VPN:
     213           0 :                 for (v = hie->u.vpn.v; v; v = v_next) {
     214           0 :                         v_next = v->next;
     215           0 :                         v->next = NULL;
     216           0 :                         XFREE(MTYPE_RFAPI_MONITOR, e);
     217           0 :                         agg_unlock_node(rn);
     218             :                 }
     219           0 :                 hie->u.vpn.v = NULL;
     220           0 :                 if (hie->u.vpn.e.source) {
     221           0 :                         while (!skiplist_delete_first(hie->u.vpn.e.source)) {
     222           0 :                                 agg_unlock_node(rn);
     223             :                         }
     224           0 :                         skiplist_free(hie->u.vpn.e.source);
     225           0 :                         hie->u.vpn.e.source = NULL;
     226           0 :                         agg_unlock_node(rn);
     227             :                 }
     228           0 :                 if (hie->u.vpn.idx_rd) {
     229             :                         /* looping through bpi->extra->vnc.import.rd is tbd */
     230           0 :                         while (!skiplist_delete_first(hie->u.vpn.idx_rd)) {
     231           0 :                                 agg_unlock_node(rn);
     232             :                         }
     233           0 :                         skiplist_free(hie->u.vpn.idx_rd);
     234           0 :                         hie->u.vpn.idx_rd = NULL;
     235           0 :                         agg_unlock_node(rn);
     236             :                 }
     237           0 :                 if (hie->u.vpn.mon_eth) {
     238           0 :                         while (!skiplist_delete_first(hie->u.vpn.mon_eth)) {
     239           0 :                                 agg_unlock_node(rn);
     240             :                         }
     241           0 :                         skiplist_free(hie->u.vpn.mon_eth);
     242           0 :                         hie->u.vpn.mon_eth = NULL;
     243           0 :                         agg_unlock_node(rn);
     244             :                 }
     245             :                 break;
     246             : 
     247             :         case SAFI_UNSPEC:
     248             :         case SAFI_UNICAST:
     249             :         case SAFI_MULTICAST:
     250             :         case SAFI_EVPN:
     251             :         case SAFI_LABELED_UNICAST:
     252             :         case SAFI_FLOWSPEC:
     253             :         case SAFI_MAX:
     254           0 :                 assert(0);
     255             :         }
     256           0 :         XFREE(MTYPE_RFAPI_IT_EXTRA, hie);
     257           0 :         rn->aggregate = NULL;
     258           0 :         agg_unlock_node(rn);
     259             : }
     260             : 
     261             : /*
     262             :  * If the child lists are empty, release the rfapi_it_extra struct
     263             :  */
     264           0 : void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn)
     265             : {
     266           0 :         struct rfapi_it_extra *hie;
     267             : 
     268           0 :         if (!rn)
     269             :                 return;
     270             : 
     271           0 :         if (!rn->aggregate)
     272             :                 return;
     273             : 
     274           0 :         hie = (struct rfapi_it_extra *)(rn->aggregate);
     275             : 
     276           0 :         switch (safi) {
     277           0 :         case SAFI_ENCAP:
     278           0 :                 if (hie->u.encap.e)
     279             :                         return;
     280             :                 break;
     281             : 
     282           0 :         case SAFI_MPLS_VPN:
     283           0 :                 if (hie->u.vpn.v)
     284             :                         return;
     285           0 :                 if (hie->u.vpn.mon_eth) {
     286           0 :                         if (skiplist_count(hie->u.vpn.mon_eth))
     287             :                                 return;
     288           0 :                         skiplist_free(hie->u.vpn.mon_eth);
     289           0 :                         hie->u.vpn.mon_eth = NULL;
     290           0 :                         agg_unlock_node(rn); /* uncount skiplist */
     291             :                 }
     292           0 :                 if (hie->u.vpn.e.source) {
     293           0 :                         if (skiplist_count(hie->u.vpn.e.source))
     294             :                                 return;
     295           0 :                         skiplist_free(hie->u.vpn.e.source);
     296           0 :                         hie->u.vpn.e.source = NULL;
     297           0 :                         agg_unlock_node(rn);
     298             :                 }
     299           0 :                 if (hie->u.vpn.idx_rd) {
     300           0 :                         if (skiplist_count(hie->u.vpn.idx_rd))
     301             :                                 return;
     302           0 :                         skiplist_free(hie->u.vpn.idx_rd);
     303           0 :                         hie->u.vpn.idx_rd = NULL;
     304           0 :                         agg_unlock_node(rn);
     305             :                 }
     306           0 :                 if (hie->u.vpn.mon_eth) {
     307           0 :                         if (skiplist_count(hie->u.vpn.mon_eth))
     308             :                                 return;
     309           0 :                         skiplist_free(hie->u.vpn.mon_eth);
     310           0 :                         hie->u.vpn.mon_eth = NULL;
     311           0 :                         agg_unlock_node(rn);
     312             :                 }
     313             :                 break;
     314             : 
     315             :         case SAFI_UNSPEC:
     316             :         case SAFI_UNICAST:
     317             :         case SAFI_MULTICAST:
     318             :         case SAFI_EVPN:
     319             :         case SAFI_LABELED_UNICAST:
     320             :         case SAFI_FLOWSPEC:
     321             :         case SAFI_MAX:
     322           0 :                 assert(0);
     323             :         }
     324           0 :         XFREE(MTYPE_RFAPI_IT_EXTRA, hie);
     325           0 :         rn->aggregate = NULL;
     326           0 :         agg_unlock_node(rn);
     327             : }
     328             : 
     329             : /*
     330             :  * returns locked node
     331             :  */
     332           0 : struct agg_node *rfapiMonitorGetAttachNode(struct rfapi_descriptor *rfd,
     333             :                                            struct prefix *p)
     334             : {
     335           0 :         afi_t afi;
     336           0 :         struct agg_node *rn;
     337             : 
     338           0 :         if (RFAPI_0_PREFIX(p)) {
     339             :                 assert(1);
     340             :         }
     341             : 
     342           0 :         afi = family2afi(p->family);
     343           0 :         assert(afi);
     344             : 
     345             :         /*
     346             :          * It's possible that even though there is a route at this node,
     347             :          * there are no routes with valid UN addresses (i.e,. with no
     348             :          * valid tunnel routes). Check for that and walk back up the
     349             :          * tree if necessary.
     350             :          *
     351             :          * When the outer loop completes, the matched node, if any, is
     352             :          * locked (i.e., its reference count has been incremented) to
     353             :          * account for the VPN monitor we are about to attach.
     354             :          *
     355             :          * if a monitor is moved to another node, there must be
     356             :          * corresponding unlock/locks
     357             :          */
     358           0 :         for (rn = agg_node_match(rfd->import_table->imported_vpn[afi], p);
     359           0 :              rn;) {
     360             : 
     361           0 :                 struct bgp_path_info *bpi;
     362           0 :                 struct prefix pfx_dummy;
     363             : 
     364             :                 /* TBD update this code to use new valid_interior_count */
     365           0 :                 for (bpi = rn->info; bpi; bpi = bpi->next) {
     366             :                         /*
     367             :                          * If there is a cached ENCAP UN address, it's a usable
     368             :                          * VPN route
     369             :                          */
     370           0 :                         if (bpi->extra && bpi->extra->vnc.import.un_family) {
     371             :                                 break;
     372             :                         }
     373             : 
     374             :                         /*
     375             :                          * Or if there is a valid Encap Attribute tunnel subtlv
     376             :                          * address,
     377             :                          * it's a usable VPN route.
     378             :                          */
     379           0 :                         if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_dummy)) {
     380             :                                 break;
     381             :                         }
     382             :                 }
     383           0 :                 if (bpi)
     384             :                         break;
     385             : 
     386           0 :                 agg_unlock_node(rn);
     387           0 :                 if ((rn = agg_node_parent(rn))) {
     388           0 :                         agg_lock_node(rn);
     389             :                 }
     390             :         }
     391             : 
     392           0 :         if (!rn) {
     393           0 :                 struct prefix pfx_default;
     394             : 
     395           0 :                 memset(&pfx_default, 0, sizeof(pfx_default));
     396           0 :                 pfx_default.family = p->family;
     397             : 
     398             :                 /* creates default node if none exists, and increments ref count
     399             :                  */
     400           0 :                 rn = agg_node_get(rfd->import_table->imported_vpn[afi],
     401             :                                   &pfx_default);
     402             :         }
     403             : 
     404           0 :         return rn;
     405             : }
     406             : 
     407             : /*
     408             :  * If this function happens to attach the monitor to a radix tree
     409             :  * node (as opposed to the 0-prefix list), the node pointer is
     410             :  * returned (for the benefit of caller which might like to use it
     411             :  * to generate an immediate query response).
     412             :  */
     413           0 : static struct agg_node *rfapiMonitorAttachImport(struct rfapi_descriptor *rfd,
     414             :                                                  struct rfapi_monitor_vpn *m)
     415             : {
     416           0 :         struct agg_node *rn;
     417             : 
     418           0 :         rfapiMonitorCheckAttachAllowed();
     419             : 
     420           0 :         if (RFAPI_0_PREFIX(&m->p)) {
     421             :                 /*
     422             :                  * Add new monitor entry to vpn0 list
     423             :                  */
     424           0 :                 afi_t afi;
     425             : 
     426           0 :                 afi = family2afi(m->p.family);
     427           0 :                 assert(afi);
     428             : 
     429           0 :                 m->next = rfd->import_table->vpn0_queries[afi];
     430           0 :                 rfd->import_table->vpn0_queries[afi] = m;
     431           0 :                 vnc_zlog_debug_verbose("%s: attached monitor %p to vpn0 list",
     432             :                                        __func__, m);
     433           0 :                 return NULL;
     434             :         }
     435             : 
     436             :         /*
     437             :          * Attach new monitor entry to import table node
     438             :          */
     439           0 :         rn = rfapiMonitorGetAttachNode(rfd, &m->p); /* returns locked rn */
     440           0 :         m->node = rn;
     441           0 :         m->next = RFAPI_MONITOR_VPN(rn);
     442           0 :         RFAPI_MONITOR_VPN_W_ALLOC(rn) = m;
     443           0 :         RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 0);
     444           0 :         vnc_zlog_debug_verbose("%s: attached monitor %p to rn %p", __func__, m,
     445             :                                rn);
     446             :         return rn;
     447             : }
     448             : 
     449             : 
     450             : /*
     451             :  * reattach monitors for this HD to import table
     452             :  */
     453           0 : void rfapiMonitorAttachImportHd(struct rfapi_descriptor *rfd)
     454             : {
     455           0 :         struct agg_node *mrn;
     456             : 
     457           0 :         if (!rfd->mon) {
     458             :                 /*
     459             :                  * No monitors for this HD
     460             :                  */
     461             :                 return;
     462             :         }
     463             : 
     464           0 :         for (mrn = agg_route_top(rfd->mon); mrn; mrn = agg_route_next(mrn)) {
     465             : 
     466           0 :                 if (!mrn->info)
     467           0 :                         continue;
     468             : 
     469           0 :                 (void)rfapiMonitorAttachImport(
     470             :                         rfd, (struct rfapi_monitor_vpn *)(mrn->info));
     471             :         }
     472             : }
     473             : 
     474             : /*
     475             :  * Adds a monitor for a query to the NVE descriptor's list
     476             :  * and, if callbacks are enabled, attaches it to the import table.
     477             :  *
     478             :  * If we happened to locate the import table radix tree attachment
     479             :  * point, return it so the caller can use it to generate a query
     480             :  * response without repeating the lookup. Note that when callbacks
     481             :  * are disabled, this function will not perform a lookup, and the
     482             :  * caller will have to do its own lookup.
     483             :  */
     484           0 : struct agg_node *rfapiMonitorAdd(struct bgp *bgp, struct rfapi_descriptor *rfd,
     485             :                                  struct prefix *p)
     486             : {
     487           0 :         struct rfapi_monitor_vpn *m;
     488           0 :         struct agg_node *rn;
     489             : 
     490             :         /*
     491             :          * Initialize nve's monitor list if needed
     492             :          * NB use the same radix tree for IPv4 and IPv6 targets.
     493             :          * The prefix will always have full-length mask (/32, /128)
     494             :          * or be 0/0 so they won't get mixed up.
     495             :          */
     496           0 :         if (!rfd->mon) {
     497           0 :                 rfd->mon = agg_table_init();
     498             :         }
     499           0 :         rn = agg_node_get(rfd->mon, p);
     500           0 :         if (rn->info) {
     501             :                 /*
     502             :                  * received this query before, no further action needed
     503             :                  */
     504           0 :                 rfapiMonitorTimerRestart((struct rfapi_monitor_vpn *)rn->info);
     505           0 :                 agg_unlock_node(rn);
     506           0 :                 return NULL;
     507             :         }
     508             : 
     509             :         /*
     510             :          * New query for this nve, record it in the HD
     511             :          */
     512           0 :         rn->info =
     513           0 :                 XCALLOC(MTYPE_RFAPI_MONITOR, sizeof(struct rfapi_monitor_vpn));
     514           0 :         m = (struct rfapi_monitor_vpn *)(rn->info);
     515           0 :         m->rfd = rfd;
     516           0 :         prefix_copy(&m->p, p);
     517             : 
     518           0 :         ++rfd->monitor_count;
     519           0 :         ++bgp->rfapi->monitor_count;
     520             : 
     521           0 :         rfapiMonitorTimerRestart(m);
     522             : 
     523           0 :         if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
     524             :                 /*
     525             :                  * callbacks turned off, so don't attach monitor to import table
     526             :                  */
     527             :                 return NULL;
     528             :         }
     529             : 
     530             : 
     531             :         /*
     532             :          * attach to import table
     533             :          */
     534           0 :         return rfapiMonitorAttachImport(rfd, m);
     535             : }
     536             : 
     537             : /*
     538             :  * returns monitor pointer if found, NULL if not
     539             :  */
     540             : static struct rfapi_monitor_vpn *
     541           0 : rfapiMonitorDetachImport(struct rfapi_monitor_vpn *m)
     542             : {
     543           0 :         struct rfapi_monitor_vpn *prev;
     544           0 :         struct rfapi_monitor_vpn *this = NULL;
     545             : 
     546           0 :         if (RFAPI_0_PREFIX(&m->p)) {
     547           0 :                 afi_t afi;
     548             : 
     549             :                 /*
     550             :                  * 0-prefix monitors are stored in a special list and not
     551             :                  * in the import VPN tree
     552             :                  */
     553             : 
     554           0 :                 afi = family2afi(m->p.family);
     555           0 :                 assert(afi);
     556             : 
     557           0 :                 if (m->rfd->import_table) {
     558           0 :                         for (prev = NULL,
     559           0 :                             this = m->rfd->import_table->vpn0_queries[afi];
     560           0 :                              this; prev = this, this = this->next) {
     561             : 
     562           0 :                                 if (this == m)
     563             :                                         break;
     564             :                         }
     565           0 :                         if (this) {
     566           0 :                                 if (!prev) {
     567           0 :                                         m->rfd->import_table
     568           0 :                                                 ->vpn0_queries[afi] =
     569           0 :                                                 this->next;
     570             :                                 } else {
     571           0 :                                         prev->next = this->next;
     572             :                                 }
     573             :                         }
     574             :                 }
     575             :         } else {
     576             : 
     577           0 :                 if (m->node) {
     578           0 :                         for (prev = NULL, this = RFAPI_MONITOR_VPN(m->node);
     579           0 :                              this; prev = this, this = this->next) {
     580             : 
     581           0 :                                 if (this == m)
     582             :                                         break;
     583             :                         }
     584           0 :                         if (this) {
     585           0 :                                 if (prev) {
     586           0 :                                         prev->next = this->next;
     587             :                                 } else {
     588           0 :                                         RFAPI_MONITOR_VPN_W_ALLOC(m->node) =
     589           0 :                                                 this->next;
     590             :                                 }
     591           0 :                                 RFAPI_CHECK_REFCOUNT(m->node, SAFI_MPLS_VPN, 1);
     592           0 :                                 agg_unlock_node(m->node);
     593             :                         }
     594           0 :                         m->node = NULL;
     595             :                 }
     596             :         }
     597           0 :         return this;
     598             : }
     599             : 
     600             : 
     601           0 : void rfapiMonitorDetachImportHd(struct rfapi_descriptor *rfd)
     602             : {
     603           0 :         struct agg_node *rn;
     604             : 
     605           0 :         if (!rfd->mon)
     606             :                 return;
     607             : 
     608           0 :         for (rn = agg_route_top(rfd->mon); rn; rn = agg_route_next(rn)) {
     609           0 :                 if (rn->info) {
     610           0 :                         rfapiMonitorDetachImport(
     611             :                                 (struct rfapi_monitor_vpn *)(rn->info));
     612             :                 }
     613             :         }
     614             : }
     615             : 
     616           0 : void rfapiMonitorDel(struct bgp *bgp, struct rfapi_descriptor *rfd,
     617             :                      struct prefix *p)
     618             : {
     619           0 :         struct agg_node *rn;
     620           0 :         struct rfapi_monitor_vpn *m;
     621             : 
     622           0 :         assert(rfd->mon);
     623           0 :         rn = agg_node_get(rfd->mon, p); /* locks node */
     624           0 :         m = rn->info;
     625             : 
     626           0 :         assert(m);
     627             : 
     628             :         /*
     629             :          * remove from import table
     630             :          */
     631           0 :         if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
     632           0 :                 rfapiMonitorDetachImport(m);
     633             :         }
     634             : 
     635           0 :         THREAD_OFF(m->timer);
     636             : 
     637             :         /*
     638             :          * remove from rfd list
     639             :          */
     640           0 :         XFREE(MTYPE_RFAPI_MONITOR, m);
     641           0 :         rn->info = NULL;
     642           0 :         agg_unlock_node(rn); /* undo original lock when created */
     643           0 :         agg_unlock_node(rn); /* undo lock in agg_node_get */
     644             : 
     645           0 :         --rfd->monitor_count;
     646           0 :         --bgp->rfapi->monitor_count;
     647           0 : }
     648             : 
     649             : /*
     650             :  * returns count of monitors deleted
     651             :  */
     652           0 : int rfapiMonitorDelHd(struct rfapi_descriptor *rfd)
     653             : {
     654           0 :         struct agg_node *rn;
     655           0 :         struct bgp *bgp;
     656           0 :         int count = 0;
     657             : 
     658           0 :         vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__, rfd);
     659             : 
     660           0 :         bgp = bgp_get_default();
     661             : 
     662           0 :         if (rfd->mon) {
     663           0 :                 for (rn = agg_route_top(rfd->mon); rn;
     664           0 :                      rn = agg_route_next(rn)) {
     665           0 :                         struct rfapi_monitor_vpn *m;
     666           0 :                         if ((m = rn->info)) {
     667           0 :                                 if (!(bgp->rfapi_cfg->flags
     668           0 :                                       & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
     669           0 :                                         rfapiMonitorDetachImport(m);
     670             :                                 }
     671             : 
     672           0 :                                 THREAD_OFF(m->timer);
     673             : 
     674           0 :                                 XFREE(MTYPE_RFAPI_MONITOR, m);
     675           0 :                                 rn->info = NULL;
     676           0 :                                 agg_unlock_node(rn); /* undo original lock
     677             :                                                           when created */
     678           0 :                                 ++count;
     679           0 :                                 --rfd->monitor_count;
     680           0 :                                 --bgp->rfapi->monitor_count;
     681             :                         }
     682             :                 }
     683           0 :                 agg_table_finish(rfd->mon);
     684           0 :                 rfd->mon = NULL;
     685             :         }
     686             : 
     687           0 :         if (rfd->mon_eth) {
     688             : 
     689             :                 struct rfapi_monitor_eth *mon_eth;
     690             : 
     691           0 :                 while (!skiplist_first(rfd->mon_eth, NULL, (void **)&mon_eth)) {
     692             : 
     693           0 :                         int rc;
     694             : 
     695           0 :                         if (!(bgp->rfapi_cfg->flags
     696           0 :                               & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
     697           0 :                                 rfapiMonitorEthDetachImport(bgp, mon_eth);
     698             :                         } else {
     699             : #if DEBUG_L2_EXTRA
     700             :                                 vnc_zlog_debug_verbose(
     701             :                                         "%s: callbacks disabled, not attempting to detach mon_eth %p",
     702             :                                         __func__, mon_eth);
     703             : #endif
     704           0 :                         }
     705             : 
     706           0 :                         THREAD_OFF(mon_eth->timer);
     707             : 
     708             :                         /*
     709             :                          * remove from rfd list
     710             :                          */
     711           0 :                         rc = skiplist_delete(rfd->mon_eth, mon_eth, mon_eth);
     712           0 :                         assert(!rc);
     713             : 
     714           0 :                         vnc_zlog_debug_verbose("%s: freeing mon_eth %p",
     715             :                                                __func__, mon_eth);
     716           0 :                         XFREE(MTYPE_RFAPI_MONITOR_ETH, mon_eth);
     717             : 
     718           0 :                         ++count;
     719           0 :                         --rfd->monitor_count;
     720           0 :                         --bgp->rfapi->monitor_count;
     721             :                 }
     722           0 :                 skiplist_free(rfd->mon_eth);
     723           0 :                 rfd->mon_eth = NULL;
     724             :         }
     725             : 
     726           0 :         return count;
     727             : }
     728             : 
     729           0 : void rfapiMonitorResponseRemovalOff(struct bgp *bgp)
     730             : {
     731           0 :         if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE) {
     732             :                 return;
     733             :         }
     734           0 :         bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE;
     735             : }
     736             : 
     737           0 : void rfapiMonitorResponseRemovalOn(struct bgp *bgp)
     738             : {
     739           0 :         if (!(bgp->rfapi_cfg->flags
     740           0 :               & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) {
     741             :                 return;
     742             :         }
     743           0 :         bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE;
     744             : }
     745             : 
     746           0 : static void rfapiMonitorTimerExpire(struct thread *t)
     747             : {
     748           0 :         struct rfapi_monitor_vpn *m = THREAD_ARG(t);
     749             : 
     750             :         /* forget reference to thread, it's gone */
     751           0 :         m->timer = NULL;
     752             : 
     753             :         /* delete the monitor */
     754           0 :         rfapiMonitorDel(bgp_get_default(), m->rfd, &m->p);
     755           0 : }
     756             : 
     757           0 : static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m)
     758             : {
     759           0 :         unsigned long remain = thread_timer_remain_second(m->timer);
     760             : 
     761             :         /* unexpected case, but avoid wraparound problems below */
     762           0 :         if (remain > m->rfd->response_lifetime)
     763             :                 return;
     764             : 
     765             :         /* don't restart if we just restarted recently */
     766           0 :         if (m->rfd->response_lifetime - remain < 2)
     767             :                 return;
     768             : 
     769           0 :         THREAD_OFF(m->timer);
     770             : 
     771             :         {
     772           0 :                 char buf[BUFSIZ];
     773             : 
     774           0 :                 vnc_zlog_debug_verbose(
     775             :                         "%s: target %s life %u", __func__,
     776             :                         rfapi_ntop(m->p.family, m->p.u.val, buf, BUFSIZ),
     777             :                         m->rfd->response_lifetime);
     778             :         }
     779             : 
     780           0 :         thread_add_timer(bm->master, rfapiMonitorTimerExpire, m,
     781             :                          m->rfd->response_lifetime, &m->timer);
     782             : }
     783             : 
     784             : /*
     785             :  * called when an updated response is sent to the NVE. Per
     786             :  * ticket 255, restart timers for any monitors that could have
     787             :  * been responsible for the response, i.e., any monitors for
     788             :  * the exact prefix or a parent of it.
     789             :  */
     790           0 : void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd,
     791             :                                const struct prefix *p)
     792             : {
     793           0 :         struct agg_node *rn;
     794             : 
     795           0 :         if (AF_ETHERNET == p->family) {
     796           0 :                 struct rfapi_monitor_eth *mon_eth;
     797           0 :                 int rc;
     798           0 :                 void *cursor;
     799             : 
     800             :                 /*
     801             :                  * XXX match any LNI
     802             :                  */
     803           0 :                 for (cursor = NULL,
     804           0 :                     rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon_eth,
     805             :                                        &cursor);
     806           0 :                      rc == 0; rc = skiplist_next(rfd->mon_eth, NULL,
     807             :                                                  (void **)&mon_eth, &cursor)) {
     808             : 
     809           0 :                         if (!memcmp(mon_eth->macaddr.octet,
     810           0 :                                     p->u.prefix_eth.octet, ETH_ALEN)) {
     811             : 
     812           0 :                                 rfapiMonitorEthTimerRestart(mon_eth);
     813             :                         }
     814             :                 }
     815             : 
     816             :         } else {
     817           0 :                 for (rn = agg_route_top(rfd->mon); rn;
     818           0 :                      rn = agg_route_next(rn)) {
     819           0 :                         struct rfapi_monitor_vpn *m;
     820           0 :                         const struct prefix *p_node;
     821             : 
     822           0 :                         if (!((m = rn->info)))
     823           0 :                                 continue;
     824             : 
     825           0 :                         p_node = agg_node_get_prefix(m->node);
     826             :                         /* NB order of test is significant ! */
     827           0 :                         if (!m->node || prefix_match(p_node, p)) {
     828           0 :                                 rfapiMonitorTimerRestart(m);
     829             :                         }
     830             :                 }
     831             :         }
     832           0 : }
     833             : 
     834             : /*
     835             :  * Find monitors at this node and all its parents. Call
     836             :  * rfapiRibUpdatePendingNode with this node and all corresponding NVEs.
     837             :  */
     838           0 : void rfapiMonitorItNodeChanged(
     839             :         struct rfapi_import_table *import_table, struct agg_node *it_node,
     840             :         struct rfapi_monitor_vpn *monitor_list) /* for base it node, NULL=all */
     841             : {
     842           0 :         struct skiplist *nves_seen;
     843           0 :         struct agg_node *rn = it_node;
     844           0 :         struct bgp *bgp = bgp_get_default();
     845           0 :         const struct prefix *p = agg_node_get_prefix(rn);
     846           0 :         afi_t afi = family2afi(p->family);
     847             : 
     848           0 :         assert(bgp);
     849           0 :         assert(import_table);
     850             : 
     851           0 :         nves_seen = skiplist_new(0, NULL, NULL);
     852             : 
     853             : #if DEBUG_L2_EXTRA
     854             :         vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%pFX",
     855             :                                __func__, import_table, it_node, &it_node->p);
     856             : #endif
     857             : 
     858           0 :         if (AFI_L2VPN == afi) {
     859           0 :                 struct rfapi_monitor_eth *m;
     860           0 :                 struct skiplist *sl;
     861           0 :                 void *cursor;
     862           0 :                 int rc;
     863             : 
     864           0 :                 if ((sl = RFAPI_MONITOR_ETH(rn))) {
     865             : 
     866           0 :                         for (cursor = NULL,
     867           0 :                             rc = skiplist_next(sl, NULL, (void **)&m, &cursor);
     868           0 :                              !rc; rc = skiplist_next(sl, NULL, (void **)&m,
     869             :                                                      &cursor)) {
     870             : 
     871           0 :                                 if (skiplist_search(nves_seen, m->rfd, NULL)) {
     872             :                                         /*
     873             :                                          * Haven't done this NVE yet. Add to
     874             :                                          * "seen" list.
     875             :                                          */
     876           0 :                                         assert(!skiplist_insert(nves_seen,
     877             :                                                                 m->rfd, NULL));
     878             : 
     879             :                                         /*
     880             :                                          * update its RIB
     881             :                                          */
     882           0 :                                         rfapiRibUpdatePendingNode(
     883             :                                                 bgp, m->rfd, import_table,
     884             :                                                 it_node,
     885           0 :                                                 m->rfd->response_lifetime);
     886             :                                 }
     887             :                         }
     888             :                 }
     889             : 
     890             :         } else {
     891             : 
     892           0 :                 struct rfapi_monitor_vpn *m;
     893             : 
     894           0 :                 if (monitor_list) {
     895             :                         m = monitor_list;
     896             :                 } else {
     897           0 :                         m = RFAPI_MONITOR_VPN(rn);
     898             :                 }
     899             : 
     900           0 :                 do {
     901             :                         /*
     902             :                          * If we have reached the root node (parent==NULL) and
     903             :                          * there
     904             :                          * are no routes here (info==NULL), and the IT node that
     905             :                          * changed was not the root node (it_node->parent !=
     906             :                          * NULL),
     907             :                          * then any monitors at this node are here because they
     908             :                          * had
     909             :                          * no match at all. Therefore, do not send route updates
     910             :                          * to them
     911             :                          * because we haven't sent them an initial route.
     912             :                          */
     913           0 :                         if (!agg_node_parent(rn) && !rn->info
     914           0 :                             && it_node->parent)
     915             :                                 break;
     916             : 
     917           0 :                         for (; m; m = m->next) {
     918             : 
     919           0 :                                 if (RFAPI_0_PREFIX(&m->p)) {
     920             :                                         /* shouldn't happen, but be safe */
     921           0 :                                         continue;
     922             :                                 }
     923           0 :                                 if (skiplist_search(nves_seen, m->rfd, NULL)) {
     924             :                                         /*
     925             :                                          * Haven't done this NVE yet. Add to
     926             :                                          * "seen" list.
     927             :                                          */
     928           0 :                                         assert(!skiplist_insert(nves_seen,
     929             :                                                                 m->rfd, NULL));
     930             : 
     931           0 :                                         vnc_zlog_debug_verbose(
     932             :                                                 "%s: update rfd %p attached to pfx %pRN (targ=%pFX)",
     933             :                                                 __func__, m->rfd, m->node,
     934             :                                                 &m->p);
     935             : 
     936             :                                         /*
     937             :                                          * update its RIB
     938             :                                          */
     939           0 :                                         rfapiRibUpdatePendingNode(
     940             :                                                 bgp, m->rfd, import_table,
     941             :                                                 it_node,
     942           0 :                                                 m->rfd->response_lifetime);
     943             :                                 }
     944             :                         }
     945           0 :                         rn = agg_node_parent(rn);
     946           0 :                         if (rn)
     947           0 :                                 m = RFAPI_MONITOR_VPN(rn);
     948           0 :                 } while (rn);
     949             :         }
     950             : 
     951             :         /*
     952             :          * All-routes L2 monitors
     953             :          */
     954           0 :         if (AFI_L2VPN == afi) {
     955           0 :                 struct rfapi_monitor_eth *e;
     956             : 
     957             : #if DEBUG_L2_EXTRA
     958             :                 vnc_zlog_debug_verbose("%s: checking L2 all-routes monitors",
     959             :                                        __func__);
     960             : #endif
     961             : 
     962           0 :                 for (e = import_table->eth0_queries; e; e = e->next) {
     963             : #if DEBUG_L2_EXTRA
     964             :                         vnc_zlog_debug_verbose("%s: checking eth0 mon=%p",
     965             :                                                __func__, e);
     966             : #endif
     967           0 :                         if (skiplist_search(nves_seen, e->rfd, NULL)) {
     968             :                                 /*
     969             :                                  * Haven't done this NVE yet. Add to "seen"
     970             :                                  * list.
     971             :                                  */
     972           0 :                                 assert(!skiplist_insert(nves_seen, e->rfd,
     973             :                                                         NULL));
     974             : 
     975             : /*
     976             :  * update its RIB
     977             :  */
     978             : #if DEBUG_L2_EXTRA
     979             :                                 vnc_zlog_debug_verbose(
     980             :                                         "%s: found L2 all-routes monitor %p",
     981             :                                         __func__, e);
     982             : #endif
     983           0 :                                 rfapiRibUpdatePendingNode(
     984             :                                         bgp, e->rfd, import_table, it_node,
     985           0 :                                         e->rfd->response_lifetime);
     986             :                         }
     987             :                 }
     988             :         } else {
     989           0 :                 struct rfapi_monitor_vpn *m;
     990             : 
     991             :                 /*
     992             :                  * All-routes IPv4. IPv6 monitors
     993             :                  */
     994           0 :                 for (m = import_table->vpn0_queries[afi]; m; m = m->next) {
     995           0 :                         if (skiplist_search(nves_seen, m->rfd, NULL)) {
     996             :                                 /*
     997             :                                  * Haven't done this NVE yet. Add to "seen"
     998             :                                  * list.
     999             :                                  */
    1000           0 :                                 assert(!skiplist_insert(nves_seen, m->rfd,
    1001             :                                                         NULL));
    1002             : 
    1003             :                                 /*
    1004             :                                  * update its RIB
    1005             :                                  */
    1006           0 :                                 rfapiRibUpdatePendingNode(
    1007             :                                         bgp, m->rfd, import_table, it_node,
    1008           0 :                                         m->rfd->response_lifetime);
    1009             :                         }
    1010             :                 }
    1011             :         }
    1012             : 
    1013           0 :         skiplist_free(nves_seen);
    1014           0 : }
    1015             : 
    1016             : /*
    1017             :  * For the listed monitors, update new node and its subtree, but
    1018             :  * omit old node and its subtree
    1019             :  */
    1020           0 : void rfapiMonitorMovedUp(struct rfapi_import_table *import_table,
    1021             :                          struct agg_node *old_node, struct agg_node *new_node,
    1022             :                          struct rfapi_monitor_vpn *monitor_list)
    1023             : {
    1024           0 :         struct bgp *bgp = bgp_get_default();
    1025           0 :         struct rfapi_monitor_vpn *m;
    1026             : 
    1027           0 :         assert(new_node);
    1028           0 :         assert(old_node);
    1029           0 :         assert(new_node != old_node);
    1030             : 
    1031             :         /*
    1032             :          * If new node is 0/0 and there is no route there, don't
    1033             :          * generate an update because it will not contain any
    1034             :          * routes including the target.
    1035             :          */
    1036           0 :         if (!new_node->parent && !new_node->info) {
    1037           0 :                 vnc_zlog_debug_verbose(
    1038             :                         "%s: new monitor at 0/0 and no routes, no updates",
    1039             :                         __func__);
    1040           0 :                 return;
    1041             :         }
    1042             : 
    1043           0 :         for (m = monitor_list; m; m = m->next) {
    1044           0 :                 rfapiRibUpdatePendingNode(bgp, m->rfd, import_table, new_node,
    1045           0 :                                           m->rfd->response_lifetime);
    1046           0 :                 rfapiRibUpdatePendingNodeSubtree(bgp, m->rfd, import_table,
    1047             :                                                  new_node, old_node,
    1048           0 :                                                  m->rfd->response_lifetime);
    1049             :         }
    1050             : }
    1051             : 
    1052           0 : static void rfapiMonitorEthTimerExpire(struct thread *t)
    1053             : {
    1054           0 :         struct rfapi_monitor_eth *m = THREAD_ARG(t);
    1055             : 
    1056             :         /* forget reference to thread, it's gone */
    1057           0 :         m->timer = NULL;
    1058             : 
    1059             :         /* delete the monitor */
    1060           0 :         rfapiMonitorEthDel(bgp_get_default(), m->rfd, &m->macaddr,
    1061             :                            m->logical_net_id);
    1062             : 
    1063           0 : }
    1064             : 
    1065           0 : static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m)
    1066             : {
    1067           0 :         unsigned long remain = thread_timer_remain_second(m->timer);
    1068             : 
    1069             :         /* unexpected case, but avoid wraparound problems below */
    1070           0 :         if (remain > m->rfd->response_lifetime)
    1071             :                 return;
    1072             : 
    1073             :         /* don't restart if we just restarted recently */
    1074           0 :         if (m->rfd->response_lifetime - remain < 2)
    1075             :                 return;
    1076             : 
    1077           0 :         THREAD_OFF(m->timer);
    1078             : 
    1079             :         {
    1080           0 :                 char buf[BUFSIZ];
    1081             : 
    1082           0 :                 vnc_zlog_debug_verbose(
    1083             :                         "%s: target %s life %u", __func__,
    1084             :                         rfapiEthAddr2Str(&m->macaddr, buf, BUFSIZ),
    1085             :                         m->rfd->response_lifetime);
    1086             :         }
    1087             : 
    1088           0 :         thread_add_timer(bm->master, rfapiMonitorEthTimerExpire, m,
    1089             :                          m->rfd->response_lifetime, &m->timer);
    1090             : }
    1091             : 
    1092           0 : static int mon_eth_cmp(const void *a, const void *b)
    1093             : {
    1094           0 :         const struct rfapi_monitor_eth *m1;
    1095           0 :         const struct rfapi_monitor_eth *m2;
    1096             : 
    1097           0 :         int i;
    1098             : 
    1099           0 :         m1 = (struct rfapi_monitor_eth *)a;
    1100           0 :         m2 = (struct rfapi_monitor_eth *)b;
    1101             : 
    1102             :         /*
    1103             :          * compare ethernet addresses
    1104             :          */
    1105           0 :         for (i = 0; i < ETH_ALEN; ++i) {
    1106           0 :                 if (m1->macaddr.octet[i] != m2->macaddr.octet[i])
    1107           0 :                         return (m1->macaddr.octet[i] - m2->macaddr.octet[i]);
    1108             :         }
    1109             : 
    1110             :         /*
    1111             :          * compare LNIs
    1112             :          */
    1113           0 :         return (m1->logical_net_id - m2->logical_net_id);
    1114             : }
    1115             : 
    1116           0 : static void rfapiMonitorEthAttachImport(
    1117             :         struct rfapi_import_table *it,
    1118             :         struct agg_node *rn,       /* it node attach point if non-0 */
    1119             :         struct rfapi_monitor_eth *mon) /* monitor struct to attach */
    1120             : {
    1121           0 :         struct skiplist *sl;
    1122           0 :         int rc;
    1123             : 
    1124           0 :         vnc_zlog_debug_verbose("%s: it=%p", __func__, it);
    1125             : 
    1126           0 :         rfapiMonitorCheckAttachAllowed();
    1127             : 
    1128           0 :         if (RFAPI_0_ETHERADDR(&mon->macaddr)) {
    1129             :                 /*
    1130             :                  * These go on a different list
    1131             :                  */
    1132           0 :                 mon->next = it->eth0_queries;
    1133           0 :                 it->eth0_queries = mon;
    1134             : #if DEBUG_L2_EXTRA
    1135             :                 vnc_zlog_debug_verbose("%s: attached monitor %p to eth0 list",
    1136             :                                        __func__, mon);
    1137             : #endif
    1138           0 :                 return;
    1139             :         }
    1140             : 
    1141           0 :         if (rn == NULL) {
    1142             : #if DEBUG_L2_EXTRA
    1143             :                 vnc_zlog_debug_verbose("%s: rn is null!", __func__);
    1144             : #endif
    1145             :                 return;
    1146             :         }
    1147             : 
    1148             :         /*
    1149             :          * Get sl to attach to
    1150             :          */
    1151           0 :         sl = RFAPI_MONITOR_ETH_W_ALLOC(rn);
    1152           0 :         if (!sl) {
    1153           0 :                 sl = RFAPI_MONITOR_ETH_W_ALLOC(rn) =
    1154           0 :                         skiplist_new(0, NULL, NULL);
    1155           0 :                 agg_lock_node(rn); /* count skiplist mon_eth */
    1156             :         }
    1157             : 
    1158             : #if DEBUG_L2_EXTRA
    1159             :         vnc_zlog_debug_verbose(
    1160             :                 "%s: rn=%p, rn->lock=%d, sl=%p, attaching eth mon %p", __func__,
    1161             :                 rn, rn->lock, sl, mon);
    1162             : #endif
    1163             : 
    1164           0 :         rc = skiplist_insert(sl, (void *)mon, (void *)mon);
    1165           0 :         assert(!rc);
    1166             : 
    1167             :         /* count eth monitor */
    1168           0 :         agg_lock_node(rn);
    1169             : }
    1170             : 
    1171             : /*
    1172             :  * reattach monitors for this HD to import table
    1173             :  */
    1174           0 : static void rfapiMonitorEthAttachImportHd(struct bgp *bgp,
    1175             :                                           struct rfapi_descriptor *rfd)
    1176             : {
    1177           0 :         void *cursor;
    1178           0 :         struct rfapi_monitor_eth *mon;
    1179           0 :         int rc;
    1180             : 
    1181           0 :         if (!rfd->mon_eth) {
    1182             :                 /*
    1183             :                  * No monitors for this HD
    1184             :                  */
    1185           0 :                 return;
    1186             :         }
    1187             : 
    1188           0 :         for (cursor = NULL,
    1189           0 :             rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon, &cursor);
    1190           0 :              rc == 0;
    1191           0 :              rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon, &cursor)) {
    1192             : 
    1193           0 :                 struct rfapi_import_table *it;
    1194           0 :                 struct prefix pfx_mac_buf;
    1195           0 :                 struct agg_node *rn;
    1196             : 
    1197           0 :                 it = rfapiMacImportTableGet(bgp, mon->logical_net_id);
    1198           0 :                 assert(it);
    1199             : 
    1200           0 :                 memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
    1201           0 :                 pfx_mac_buf.family = AF_ETHERNET;
    1202           0 :                 pfx_mac_buf.prefixlen = 48;
    1203           0 :                 pfx_mac_buf.u.prefix_eth = mon->macaddr;
    1204             : 
    1205           0 :                 rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
    1206           0 :                 assert(rn);
    1207             : 
    1208           0 :                 (void)rfapiMonitorEthAttachImport(it, rn, mon);
    1209             :         }
    1210             : }
    1211             : 
    1212           0 : static void rfapiMonitorEthDetachImport(
    1213             :         struct bgp *bgp,
    1214             :         struct rfapi_monitor_eth *mon) /* monitor struct to detach */
    1215             : {
    1216           0 :         struct rfapi_import_table *it;
    1217           0 :         struct prefix pfx_mac_buf;
    1218           0 :         struct skiplist *sl;
    1219           0 :         struct agg_node *rn;
    1220           0 :         int rc;
    1221             : 
    1222           0 :         it = rfapiMacImportTableGet(bgp, mon->logical_net_id);
    1223           0 :         assert(it);
    1224             : 
    1225           0 :         if (RFAPI_0_ETHERADDR(&mon->macaddr)) {
    1226           0 :                 struct rfapi_monitor_eth *prev;
    1227           0 :                 struct rfapi_monitor_eth *this = NULL;
    1228             : 
    1229           0 :                 for (prev = NULL, this = it->eth0_queries; this;
    1230           0 :                      prev = this, this = this->next) {
    1231             : 
    1232           0 :                         if (this == mon)
    1233             :                                 break;
    1234             :                 }
    1235           0 :                 if (this) {
    1236           0 :                         if (!prev) {
    1237           0 :                                 it->eth0_queries = this->next;
    1238             :                         } else {
    1239           0 :                                 prev->next = this->next;
    1240             :                         }
    1241             :                 }
    1242             : #if DEBUG_L2_EXTRA
    1243             :                 vnc_zlog_debug_verbose(
    1244             :                         "%s: it=%p, LNI=%d, detached eth0 mon %p", __func__, it,
    1245             :                         mon->logical_net_id, mon);
    1246             : #endif
    1247           0 :                 return;
    1248             :         }
    1249             : 
    1250           0 :         memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
    1251           0 :         pfx_mac_buf.family = AF_ETHERNET;
    1252           0 :         pfx_mac_buf.prefixlen = 48;
    1253           0 :         pfx_mac_buf.u.prefix_eth = mon->macaddr;
    1254             : 
    1255           0 :         rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
    1256           0 :         assert(rn);
    1257             : 
    1258             :         /*
    1259             :          * Get sl to detach from
    1260             :          */
    1261           0 :         sl = RFAPI_MONITOR_ETH(rn);
    1262             : #if DEBUG_L2_EXTRA
    1263             :         vnc_zlog_debug_verbose(
    1264             :                 "%s: it=%p, rn=%p, rn->lock=%d, sl=%p, pfx=%pFX, LNI=%d, detaching eth mon %p",
    1265             :                 __func__, it, rn, rn->lock, sl, agg_node_get_prefix(rn),
    1266             :                 mon->logical_net_id, mon);
    1267             : #endif
    1268           0 :         assert(sl);
    1269             : 
    1270             : 
    1271           0 :         rc = skiplist_delete(sl, (void *)mon, (void *)mon);
    1272           0 :         assert(!rc);
    1273             : 
    1274             :         /* uncount eth monitor */
    1275           0 :         agg_unlock_node(rn);
    1276             : }
    1277             : 
    1278           0 : struct agg_node *rfapiMonitorEthAdd(struct bgp *bgp,
    1279             :                                     struct rfapi_descriptor *rfd,
    1280             :                                     struct ethaddr *macaddr,
    1281             :                                     uint32_t logical_net_id)
    1282             : {
    1283           0 :         int rc;
    1284           0 :         struct rfapi_monitor_eth mon_buf;
    1285           0 :         struct rfapi_monitor_eth *val;
    1286           0 :         struct rfapi_import_table *it;
    1287           0 :         struct agg_node *rn = NULL;
    1288           0 :         struct prefix pfx_mac_buf;
    1289             : 
    1290           0 :         if (!rfd->mon_eth) {
    1291           0 :                 rfd->mon_eth = skiplist_new(0, mon_eth_cmp, NULL);
    1292             :         }
    1293             : 
    1294           0 :         it = rfapiMacImportTableGet(bgp, logical_net_id);
    1295           0 :         assert(it);
    1296             : 
    1297             :         /*
    1298             :          * Get route node in import table. Here is where we attach the
    1299             :          * monitor.
    1300             :          *
    1301             :          * Look it up now because we return it to caller regardless of
    1302             :          * whether we create a new monitor or not.
    1303             :          */
    1304           0 :         memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
    1305           0 :         pfx_mac_buf.family = AF_ETHERNET;
    1306           0 :         pfx_mac_buf.prefixlen = 48;
    1307           0 :         pfx_mac_buf.u.prefix_eth = *macaddr;
    1308             : 
    1309           0 :         if (!RFAPI_0_ETHERADDR(macaddr)) {
    1310           0 :                 rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
    1311           0 :                 assert(rn);
    1312             :         }
    1313             : 
    1314           0 :         memset((void *)&mon_buf, 0, sizeof(mon_buf));
    1315           0 :         mon_buf.rfd = rfd;
    1316           0 :         mon_buf.macaddr = *macaddr;
    1317           0 :         mon_buf.logical_net_id = logical_net_id;
    1318             : 
    1319             :         {
    1320           0 :                 char buf[BUFSIZ];
    1321             : 
    1322           0 :                 vnc_zlog_debug_verbose(
    1323             :                         "%s: LNI=%d: rfd=%p, pfx=%s", __func__, logical_net_id,
    1324             :                         rfd, rfapi_ntop(pfx_mac_buf.family, pfx_mac_buf.u.val,
    1325             :                                         buf, BUFSIZ));
    1326             :         }
    1327             : 
    1328             : 
    1329             :         /*
    1330             :          * look up query
    1331             :          */
    1332           0 :         rc = skiplist_search(rfd->mon_eth, (void *)&mon_buf, (void **)&val);
    1333           0 :         if (!rc) {
    1334             :                 /*
    1335             :                  * Found monitor - we have seen this query before
    1336             :                  * restart timer
    1337             :                  */
    1338           0 :                 vnc_zlog_debug_verbose(
    1339             :                         "%s: already present in rfd->mon_eth, not adding",
    1340             :                         __func__);
    1341           0 :                 rfapiMonitorEthTimerRestart(val);
    1342           0 :                 return rn;
    1343             :         }
    1344             : 
    1345             :         /*
    1346             :          * New query
    1347             :          */
    1348           0 :         val = XCALLOC(MTYPE_RFAPI_MONITOR_ETH,
    1349             :                       sizeof(struct rfapi_monitor_eth));
    1350           0 :         assert(val);
    1351           0 :         *val = mon_buf;
    1352             : 
    1353           0 :         ++rfd->monitor_count;
    1354           0 :         ++bgp->rfapi->monitor_count;
    1355             : 
    1356           0 :         rc = skiplist_insert(rfd->mon_eth, val, val);
    1357             : 
    1358             : #if DEBUG_L2_EXTRA
    1359             :         vnc_zlog_debug_verbose("%s: inserted rfd=%p mon_eth=%p, rc=%d",
    1360             :                                __func__, rfd, val, rc);
    1361             : #else
    1362           0 :         (void)rc;
    1363             : #endif
    1364             : 
    1365             :         /*
    1366             :          * start timer
    1367             :          */
    1368           0 :         rfapiMonitorEthTimerRestart(val);
    1369             : 
    1370           0 :         if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
    1371             : /*
    1372             :  * callbacks turned off, so don't attach monitor to import table
    1373             :  */
    1374             : #if DEBUG_L2_EXTRA
    1375             :                 vnc_zlog_debug_verbose(
    1376             :                         "%s: callbacks turned off, not attaching mon_eth %p to import table",
    1377             :                         __func__, val);
    1378             : #endif
    1379             :                 return rn;
    1380             :         }
    1381             : 
    1382             :         /*
    1383             :          * attach to import table
    1384             :          */
    1385           0 :         rfapiMonitorEthAttachImport(it, rn, val);
    1386             : 
    1387           0 :         return rn;
    1388             : }
    1389             : 
    1390           0 : void rfapiMonitorEthDel(struct bgp *bgp, struct rfapi_descriptor *rfd,
    1391             :                         struct ethaddr *macaddr, uint32_t logical_net_id)
    1392             : {
    1393           0 :         struct rfapi_monitor_eth *val;
    1394           0 :         struct rfapi_monitor_eth mon_buf;
    1395           0 :         int rc;
    1396             : 
    1397           0 :         vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__, rfd);
    1398             : 
    1399           0 :         assert(rfd->mon_eth);
    1400             : 
    1401           0 :         memset((void *)&mon_buf, 0, sizeof(mon_buf));
    1402           0 :         mon_buf.macaddr = *macaddr;
    1403           0 :         mon_buf.logical_net_id = logical_net_id;
    1404             : 
    1405           0 :         rc = skiplist_search(rfd->mon_eth, (void *)&mon_buf, (void **)&val);
    1406           0 :         assert(!rc);
    1407             : 
    1408             :         /*
    1409             :          * remove from import table
    1410             :          */
    1411           0 :         if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
    1412           0 :                 rfapiMonitorEthDetachImport(bgp, val);
    1413             :         }
    1414             : 
    1415           0 :         THREAD_OFF(val->timer);
    1416             : 
    1417             :         /*
    1418             :          * remove from rfd list
    1419             :          */
    1420           0 :         rc = skiplist_delete(rfd->mon_eth, val, val);
    1421           0 :         assert(!rc);
    1422             : 
    1423             : #if DEBUG_L2_EXTRA
    1424             :         vnc_zlog_debug_verbose("%s: freeing mon_eth %p", __func__, val);
    1425             : #endif
    1426           0 :         XFREE(MTYPE_RFAPI_MONITOR_ETH, val);
    1427             : 
    1428           0 :         --rfd->monitor_count;
    1429           0 :         --bgp->rfapi->monitor_count;
    1430           0 : }
    1431             : 
    1432             : 
    1433           0 : void rfapiMonitorCallbacksOff(struct bgp *bgp)
    1434             : {
    1435           0 :         struct rfapi_import_table *it;
    1436           0 :         afi_t afi;
    1437           0 :         struct agg_table *rt;
    1438           0 :         struct agg_node *rn;
    1439           0 :         void *cursor;
    1440           0 :         int rc;
    1441           0 :         struct rfapi *h = bgp->rfapi;
    1442             : 
    1443           0 :         if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
    1444             :                 /*
    1445             :                  * Already off.
    1446             :                  */
    1447           0 :                 return;
    1448             :         }
    1449           0 :         bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_CALLBACK_DISABLE;
    1450             : 
    1451             : #if DEBUG_L2_EXTRA
    1452             :         vnc_zlog_debug_verbose("%s: turned off callbacks", __func__);
    1453             : #endif
    1454             : 
    1455           0 :         if (h == NULL)
    1456             :                 return;
    1457             :         /*
    1458             :          * detach monitors from import VPN tables. The monitors
    1459             :          * will still be linked in per-nve monitor lists.
    1460             :          */
    1461           0 :         for (it = h->imports; it; it = it->next) {
    1462           0 :                 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
    1463             : 
    1464           0 :                         struct rfapi_monitor_vpn *m;
    1465           0 :                         struct rfapi_monitor_vpn *next;
    1466             : 
    1467           0 :                         rt = it->imported_vpn[afi];
    1468             : 
    1469           0 :                         for (rn = agg_route_top(rt); rn;
    1470           0 :                              rn = agg_route_next(rn)) {
    1471           0 :                                 m = RFAPI_MONITOR_VPN(rn);
    1472           0 :                                 if (RFAPI_MONITOR_VPN(rn))
    1473           0 :                                         RFAPI_MONITOR_VPN_W_ALLOC(rn) = NULL;
    1474           0 :                                 for (; m; m = next) {
    1475           0 :                                         next = m->next;
    1476           0 :                                         m->next =
    1477             :                                                 NULL; /* gratuitous safeness */
    1478           0 :                                         m->node = NULL;
    1479           0 :                                         agg_unlock_node(rn); /* uncount */
    1480             :                                 }
    1481             :                         }
    1482             : 
    1483           0 :                         for (m = it->vpn0_queries[afi]; m; m = next) {
    1484           0 :                                 next = m->next;
    1485           0 :                                 m->next = NULL; /* gratuitous safeness */
    1486           0 :                                 m->node = NULL;
    1487             :                         }
    1488           0 :                         it->vpn0_queries[afi] = NULL; /* detach first monitor */
    1489             :                 }
    1490             :         }
    1491             : 
    1492             :         /*
    1493             :          * detach monitors from import Eth tables. The monitors
    1494             :          * will still be linked in per-nve monitor lists.
    1495             :          */
    1496             : 
    1497             :         /*
    1498             :          * Loop over ethernet import tables
    1499             :          */
    1500           0 :         for (cursor = NULL,
    1501           0 :             rc = skiplist_next(h->import_mac, NULL, (void **)&it, &cursor);
    1502           0 :              !rc;
    1503           0 :              rc = skiplist_next(h->import_mac, NULL, (void **)&it, &cursor)) {
    1504           0 :                 struct rfapi_monitor_eth *e;
    1505           0 :                 struct rfapi_monitor_eth *enext;
    1506             : 
    1507             :                 /*
    1508             :                  * The actual route table
    1509             :                  */
    1510           0 :                 rt = it->imported_vpn[AFI_L2VPN];
    1511             : 
    1512             :                 /*
    1513             :                  * Find non-0 monitors (i.e., actual addresses, not FTD
    1514             :                  * monitors)
    1515             :                  */
    1516           0 :                 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
    1517           0 :                         struct skiplist *sl;
    1518             : 
    1519           0 :                         sl = RFAPI_MONITOR_ETH(rn);
    1520           0 :                         while (!skiplist_delete_first(sl)) {
    1521           0 :                                 agg_unlock_node(rn); /* uncount monitor */
    1522             :                         }
    1523             :                 }
    1524             : 
    1525             :                 /*
    1526             :                  * Find 0-monitors (FTD queries)
    1527             :                  */
    1528           0 :                 for (e = it->eth0_queries; e; e = enext) {
    1529             : #if DEBUG_L2_EXTRA
    1530             :                         vnc_zlog_debug_verbose("%s: detaching eth0 mon %p",
    1531             :                                                __func__, e);
    1532             : #endif
    1533           0 :                         enext = e->next;
    1534           0 :                         e->next = NULL; /* gratuitous safeness */
    1535             :                 }
    1536           0 :                 it->eth0_queries = NULL; /* detach first monitor */
    1537             :         }
    1538             : }
    1539             : 
    1540           0 : void rfapiMonitorCallbacksOn(struct bgp *bgp)
    1541             : {
    1542           0 :         struct listnode *hnode;
    1543           0 :         struct rfapi_descriptor *rfd;
    1544             : 
    1545           0 :         if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
    1546             :                 /*
    1547             :                  * Already on. It's important that we don't try to reattach
    1548             :                  * monitors that are already attached because, in the interest
    1549             :                  * of performance, there is no checking at the lower level
    1550             :                  * whether a monitor is already attached. It leads to
    1551             :                  * corrupted chains (e.g., looped pointers)
    1552             :                  */
    1553             :                 return;
    1554             :         }
    1555           0 :         bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_CALLBACK_DISABLE;
    1556             : #if DEBUG_L2_EXTRA
    1557             :         vnc_zlog_debug_verbose("%s: turned on callbacks", __func__);
    1558             : #endif
    1559           0 :         if (bgp->rfapi == NULL)
    1560             :                 return;
    1561             : 
    1562             :         /*
    1563             :          * reattach monitors
    1564             :          */
    1565           0 :         for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, hnode, rfd)) {
    1566             : 
    1567           0 :                 rfapiMonitorAttachImportHd(rfd);
    1568           0 :                 rfapiMonitorEthAttachImportHd(bgp, rfd);
    1569             :         }
    1570             : }

Generated by: LCOV version v1.16-topotato