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