Coverage Report

Created: 2025-12-05 06:31

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