]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/rfapi_monitor.c
Merge pull request #10447 from ton31337/fix/json_with_whitespaces
[mirror_frr.git] / bgpd / rfapi / rfapi_monitor.c
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 void rfapiMonitorLoopCheck(struct rfapi_monitor_vpn *mchain)
101 {
102 struct rfapi_monitor_vpn *m;
103
104 for (m = mchain; m; m = m->next)
105 assert(m != m->next);
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 */
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 void rfapiMonitorCleanCheck(struct bgp *bgp)
153 {
154 struct listnode *hnode;
155 struct rfapi_descriptor *rfd;
156
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]);
160
161 struct agg_node *rn;
162
163 for (rn = agg_route_top(
164 rfd->import_table->imported_vpn[AFI_IP]);
165 rn; rn = agg_route_next(rn)) {
166
167 assert(!RFAPI_MONITOR_VPN(rn));
168 }
169 for (rn = agg_route_top(
170 rfd->import_table->imported_vpn[AFI_IP6]);
171 rn; rn = agg_route_next(rn)) {
172
173 assert(!RFAPI_MONITOR_VPN(rn));
174 }
175 }
176 }
177
178 /* debug */
179 void rfapiMonitorCheckAttachAllowed(void)
180 {
181 struct bgp *bgp = bgp_get_default();
182 assert(!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE));
183 }
184
185 void rfapiMonitorExtraFlush(safi_t safi, struct agg_node *rn)
186 {
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);
207 agg_unlock_node(rn);
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);
217 agg_unlock_node(rn);
218 }
219 hie->u.vpn.v = NULL;
220 if (hie->u.vpn.e.source) {
221 while (!skiplist_delete_first(hie->u.vpn.e.source)) {
222 agg_unlock_node(rn);
223 }
224 skiplist_free(hie->u.vpn.e.source);
225 hie->u.vpn.e.source = NULL;
226 agg_unlock_node(rn);
227 }
228 if (hie->u.vpn.idx_rd) {
229 /* looping through bpi->extra->vnc.import.rd is tbd */
230 while (!skiplist_delete_first(hie->u.vpn.idx_rd)) {
231 agg_unlock_node(rn);
232 }
233 skiplist_free(hie->u.vpn.idx_rd);
234 hie->u.vpn.idx_rd = NULL;
235 agg_unlock_node(rn);
236 }
237 if (hie->u.vpn.mon_eth) {
238 while (!skiplist_delete_first(hie->u.vpn.mon_eth)) {
239 agg_unlock_node(rn);
240 }
241 skiplist_free(hie->u.vpn.mon_eth);
242 hie->u.vpn.mon_eth = NULL;
243 agg_unlock_node(rn);
244 }
245 break;
246
247 default:
248 assert(0);
249 }
250 XFREE(MTYPE_RFAPI_IT_EXTRA, hie);
251 rn->aggregate = NULL;
252 agg_unlock_node(rn);
253 }
254
255 /*
256 * If the child lists are empty, release the rfapi_it_extra struct
257 */
258 void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn)
259 {
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;
284 agg_unlock_node(rn); /* uncount skiplist */
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;
291 agg_unlock_node(rn);
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;
298 agg_unlock_node(rn);
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;
305 agg_unlock_node(rn);
306 }
307 break;
308
309 default:
310 assert(0);
311 }
312 XFREE(MTYPE_RFAPI_IT_EXTRA, hie);
313 rn->aggregate = NULL;
314 agg_unlock_node(rn);
315 }
316
317 /*
318 * returns locked node
319 */
320 struct agg_node *rfapiMonitorGetAttachNode(struct rfapi_descriptor *rfd,
321 struct prefix *p)
322 {
323 afi_t afi;
324 struct agg_node *rn;
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 */
346 for (rn = agg_node_match(rfd->import_table->imported_vpn[afi], p);
347 rn;) {
348
349 struct bgp_path_info *bpi;
350 struct prefix pfx_dummy;
351
352 /* TBD update this code to use new valid_interior_count */
353 for (bpi = rn->info; bpi; bpi = bpi->next) {
354 /*
355 * If there is a cached ENCAP UN address, it's a usable
356 * VPN route
357 */
358 if (bpi->extra && bpi->extra->vnc.import.un_family) {
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 */
367 if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_dummy)) {
368 break;
369 }
370 }
371 if (bpi)
372 break;
373
374 agg_unlock_node(rn);
375 if ((rn = agg_node_parent(rn))) {
376 agg_lock_node(rn);
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 */
388 rn = agg_node_get(rfd->import_table->imported_vpn[afi],
389 &pfx_default);
390 }
391
392 return rn;
393 }
394
395 /*
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 */
401 static struct agg_node *rfapiMonitorAttachImport(struct rfapi_descriptor *rfd,
402 struct rfapi_monitor_vpn *m)
403 {
404 struct agg_node *rn;
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;
435 }
436
437
438 /*
439 * reattach monitors for this HD to import table
440 */
441 void rfapiMonitorAttachImportHd(struct rfapi_descriptor *rfd)
442 {
443 struct agg_node *mrn;
444
445 if (!rfd->mon) {
446 /*
447 * No monitors for this HD
448 */
449 return;
450 }
451
452 for (mrn = agg_route_top(rfd->mon); mrn; mrn = agg_route_next(mrn)) {
453
454 if (!mrn->info)
455 continue;
456
457 (void)rfapiMonitorAttachImport(
458 rfd, (struct rfapi_monitor_vpn *)(mrn->info));
459 }
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 */
472 struct agg_node *rfapiMonitorAdd(struct bgp *bgp, struct rfapi_descriptor *rfd,
473 struct prefix *p)
474 {
475 struct rfapi_monitor_vpn *m;
476 struct agg_node *rn;
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) {
485 rfd->mon = agg_table_init();
486 }
487 rn = agg_node_get(rfd->mon, p);
488 if (rn->info) {
489 /*
490 * received this query before, no further action needed
491 */
492 rfapiMonitorTimerRestart((struct rfapi_monitor_vpn *)rn->info);
493 agg_unlock_node(rn);
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);
523 }
524
525 /*
526 * returns monitor pointer if found, NULL if not
527 */
528 static struct rfapi_monitor_vpn *
529 rfapiMonitorDetachImport(struct rfapi_monitor_vpn *m)
530 {
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);
580 agg_unlock_node(m->node);
581 }
582 m->node = NULL;
583 }
584 }
585 return this;
586 }
587
588
589 void rfapiMonitorDetachImportHd(struct rfapi_descriptor *rfd)
590 {
591 struct agg_node *rn;
592
593 if (!rfd->mon)
594 return;
595
596 for (rn = agg_route_top(rfd->mon); rn; rn = agg_route_next(rn)) {
597 if (rn->info) {
598 rfapiMonitorDetachImport(
599 (struct rfapi_monitor_vpn *)(rn->info));
600 }
601 }
602 }
603
604 void rfapiMonitorDel(struct bgp *bgp, struct rfapi_descriptor *rfd,
605 struct prefix *p)
606 {
607 struct agg_node *rn;
608 struct rfapi_monitor_vpn *m;
609
610 assert(rfd->mon);
611 rn = agg_node_get(rfd->mon, p); /* locks node */
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
623 thread_cancel(&m->timer);
624
625 /*
626 * remove from rfd list
627 */
628 XFREE(MTYPE_RFAPI_MONITOR, m);
629 rn->info = NULL;
630 agg_unlock_node(rn); /* undo original lock when created */
631 agg_unlock_node(rn); /* undo lock in agg_node_get */
632
633 --rfd->monitor_count;
634 --bgp->rfapi->monitor_count;
635 }
636
637 /*
638 * returns count of monitors deleted
639 */
640 int rfapiMonitorDelHd(struct rfapi_descriptor *rfd)
641 {
642 struct agg_node *rn;
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) {
651 for (rn = agg_route_top(rfd->mon); rn;
652 rn = agg_route_next(rn)) {
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
660 thread_cancel(&m->timer);
661
662 XFREE(MTYPE_RFAPI_MONITOR, m);
663 rn->info = NULL;
664 agg_unlock_node(rn); /* undo original lock
665 when created */
666 ++count;
667 --rfd->monitor_count;
668 --bgp->rfapi->monitor_count;
669 }
670 }
671 agg_table_finish(rfd->mon);
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 {
687 #if DEBUG_L2_EXTRA
688 vnc_zlog_debug_verbose(
689 "%s: callbacks disabled, not attempting to detach mon_eth %p",
690 __func__, mon_eth);
691 #endif
692 }
693
694 thread_cancel(&mon_eth->timer);
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;
715 }
716
717 void rfapiMonitorResponseRemovalOff(struct bgp *bgp)
718 {
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;
723 }
724
725 void rfapiMonitorResponseRemovalOn(struct bgp *bgp)
726 {
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;
732 }
733
734 static void rfapiMonitorTimerExpire(struct thread *t)
735 {
736 struct rfapi_monitor_vpn *m = t->arg;
737
738 /* forget reference to thread, it's gone */
739 m->timer = NULL;
740
741 /* delete the monitor */
742 rfapiMonitorDel(bgp_get_default(), m->rfd, &m->p);
743 }
744
745 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m)
746 {
747 if (m->timer) {
748 unsigned long remain = thread_timer_remain_second(m->timer);
749
750 /* unexpected case, but avoid wraparound problems below */
751 if (remain > m->rfd->response_lifetime)
752 return;
753
754 /* don't restart if we just restarted recently */
755 if (m->rfd->response_lifetime - remain < 2)
756 return;
757
758 thread_cancel(&m->timer);
759 }
760
761 {
762 char buf[BUFSIZ];
763
764 vnc_zlog_debug_verbose(
765 "%s: target %s life %u", __func__,
766 rfapi_ntop(m->p.family, m->p.u.val, buf, BUFSIZ),
767 m->rfd->response_lifetime);
768 }
769 m->timer = NULL;
770 thread_add_timer(bm->master, rfapiMonitorTimerExpire, m,
771 m->rfd->response_lifetime, &m->timer);
772 }
773
774 /*
775 * called when an updated response is sent to the NVE. Per
776 * ticket 255, restart timers for any monitors that could have
777 * been responsible for the response, i.e., any monitors for
778 * the exact prefix or a parent of it.
779 */
780 void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd,
781 const struct prefix *p)
782 {
783 struct agg_node *rn;
784
785 if (AF_ETHERNET == p->family) {
786 struct rfapi_monitor_eth *mon_eth;
787 int rc;
788 void *cursor;
789
790 /*
791 * XXX match any LNI
792 */
793 for (cursor = NULL,
794 rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon_eth,
795 &cursor);
796 rc == 0; rc = skiplist_next(rfd->mon_eth, NULL,
797 (void **)&mon_eth, &cursor)) {
798
799 if (!memcmp(mon_eth->macaddr.octet,
800 p->u.prefix_eth.octet, ETH_ALEN)) {
801
802 rfapiMonitorEthTimerRestart(mon_eth);
803 }
804 }
805
806 } else {
807 for (rn = agg_route_top(rfd->mon); rn;
808 rn = agg_route_next(rn)) {
809 struct rfapi_monitor_vpn *m;
810 const struct prefix *p_node;
811
812 if (!((m = rn->info)))
813 continue;
814
815 p_node = agg_node_get_prefix(m->node);
816 /* NB order of test is significant ! */
817 if (!m->node || prefix_match(p_node, p)) {
818 rfapiMonitorTimerRestart(m);
819 }
820 }
821 }
822 }
823
824 /*
825 * Find monitors at this node and all its parents. Call
826 * rfapiRibUpdatePendingNode with this node and all corresponding NVEs.
827 */
828 void rfapiMonitorItNodeChanged(
829 struct rfapi_import_table *import_table, struct agg_node *it_node,
830 struct rfapi_monitor_vpn *monitor_list) /* for base it node, NULL=all */
831 {
832 struct skiplist *nves_seen;
833 struct agg_node *rn = it_node;
834 struct bgp *bgp = bgp_get_default();
835 const struct prefix *p = agg_node_get_prefix(rn);
836 afi_t afi = family2afi(p->family);
837
838 assert(bgp);
839 assert(import_table);
840
841 nves_seen = skiplist_new(0, NULL, NULL);
842
843 #if DEBUG_L2_EXTRA
844 vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%pFX",
845 __func__, import_table, it_node, &it_node->p);
846 #endif
847
848 if (AFI_L2VPN == afi) {
849 struct rfapi_monitor_eth *m;
850 struct skiplist *sl;
851 void *cursor;
852 int rc;
853
854 if ((sl = RFAPI_MONITOR_ETH(rn))) {
855
856 for (cursor = NULL,
857 rc = skiplist_next(sl, NULL, (void **)&m, &cursor);
858 !rc; rc = skiplist_next(sl, NULL, (void **)&m,
859 &cursor)) {
860
861 if (skiplist_search(nves_seen, m->rfd, NULL)) {
862 /*
863 * Haven't done this NVE yet. Add to
864 * "seen" list.
865 */
866 assert(!skiplist_insert(nves_seen,
867 m->rfd, NULL));
868
869 /*
870 * update its RIB
871 */
872 rfapiRibUpdatePendingNode(
873 bgp, m->rfd, import_table,
874 it_node,
875 m->rfd->response_lifetime);
876 }
877 }
878 }
879
880 } else {
881
882 struct rfapi_monitor_vpn *m;
883
884 if (monitor_list) {
885 m = monitor_list;
886 } else {
887 m = RFAPI_MONITOR_VPN(rn);
888 }
889
890 do {
891 /*
892 * If we have reached the root node (parent==NULL) and
893 * there
894 * are no routes here (info==NULL), and the IT node that
895 * changed was not the root node (it_node->parent !=
896 * NULL),
897 * then any monitors at this node are here because they
898 * had
899 * no match at all. Therefore, do not send route updates
900 * to them
901 * because we haven't sent them an initial route.
902 */
903 if (!agg_node_parent(rn) && !rn->info
904 && it_node->parent)
905 break;
906
907 for (; m; m = m->next) {
908
909 if (RFAPI_0_PREFIX(&m->p)) {
910 /* shouldn't happen, but be safe */
911 continue;
912 }
913 if (skiplist_search(nves_seen, m->rfd, NULL)) {
914 /*
915 * Haven't done this NVE yet. Add to
916 * "seen" list.
917 */
918 assert(!skiplist_insert(nves_seen,
919 m->rfd, NULL));
920
921 vnc_zlog_debug_verbose(
922 "%s: update rfd %p attached to pfx %pRN (targ=%pFX)",
923 __func__, m->rfd, m->node,
924 &m->p);
925
926 /*
927 * update its RIB
928 */
929 rfapiRibUpdatePendingNode(
930 bgp, m->rfd, import_table,
931 it_node,
932 m->rfd->response_lifetime);
933 }
934 }
935 rn = agg_node_parent(rn);
936 if (rn)
937 m = RFAPI_MONITOR_VPN(rn);
938 } while (rn);
939 }
940
941 /*
942 * All-routes L2 monitors
943 */
944 if (AFI_L2VPN == afi) {
945 struct rfapi_monitor_eth *e;
946
947 #if DEBUG_L2_EXTRA
948 vnc_zlog_debug_verbose("%s: checking L2 all-routes monitors",
949 __func__);
950 #endif
951
952 for (e = import_table->eth0_queries; e; e = e->next) {
953 #if DEBUG_L2_EXTRA
954 vnc_zlog_debug_verbose("%s: checking eth0 mon=%p",
955 __func__, e);
956 #endif
957 if (skiplist_search(nves_seen, e->rfd, NULL)) {
958 /*
959 * Haven't done this NVE yet. Add to "seen"
960 * list.
961 */
962 assert(!skiplist_insert(nves_seen, e->rfd,
963 NULL));
964
965 /*
966 * update its RIB
967 */
968 #if DEBUG_L2_EXTRA
969 vnc_zlog_debug_verbose(
970 "%s: found L2 all-routes monitor %p",
971 __func__, e);
972 #endif
973 rfapiRibUpdatePendingNode(
974 bgp, e->rfd, import_table, it_node,
975 e->rfd->response_lifetime);
976 }
977 }
978 } else {
979 struct rfapi_monitor_vpn *m;
980
981 /*
982 * All-routes IPv4. IPv6 monitors
983 */
984 for (m = import_table->vpn0_queries[afi]; m; m = m->next) {
985 if (skiplist_search(nves_seen, m->rfd, NULL)) {
986 /*
987 * Haven't done this NVE yet. Add to "seen"
988 * list.
989 */
990 assert(!skiplist_insert(nves_seen, m->rfd,
991 NULL));
992
993 /*
994 * update its RIB
995 */
996 rfapiRibUpdatePendingNode(
997 bgp, m->rfd, import_table, it_node,
998 m->rfd->response_lifetime);
999 }
1000 }
1001 }
1002
1003 skiplist_free(nves_seen);
1004 }
1005
1006 /*
1007 * For the listed monitors, update new node and its subtree, but
1008 * omit old node and its subtree
1009 */
1010 void rfapiMonitorMovedUp(struct rfapi_import_table *import_table,
1011 struct agg_node *old_node, struct agg_node *new_node,
1012 struct rfapi_monitor_vpn *monitor_list)
1013 {
1014 struct bgp *bgp = bgp_get_default();
1015 struct rfapi_monitor_vpn *m;
1016
1017 assert(new_node);
1018 assert(old_node);
1019 assert(new_node != old_node);
1020
1021 /*
1022 * If new node is 0/0 and there is no route there, don't
1023 * generate an update because it will not contain any
1024 * routes including the target.
1025 */
1026 if (!new_node->parent && !new_node->info) {
1027 vnc_zlog_debug_verbose(
1028 "%s: new monitor at 0/0 and no routes, no updates",
1029 __func__);
1030 return;
1031 }
1032
1033 for (m = monitor_list; m; m = m->next) {
1034 rfapiRibUpdatePendingNode(bgp, m->rfd, import_table, new_node,
1035 m->rfd->response_lifetime);
1036 rfapiRibUpdatePendingNodeSubtree(bgp, m->rfd, import_table,
1037 new_node, old_node,
1038 m->rfd->response_lifetime);
1039 }
1040 }
1041
1042 static void rfapiMonitorEthTimerExpire(struct thread *t)
1043 {
1044 struct rfapi_monitor_eth *m = t->arg;
1045
1046 /* forget reference to thread, it's gone */
1047 m->timer = NULL;
1048
1049 /* delete the monitor */
1050 rfapiMonitorEthDel(bgp_get_default(), m->rfd, &m->macaddr,
1051 m->logical_net_id);
1052
1053 }
1054
1055 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m)
1056 {
1057 if (m->timer) {
1058 unsigned long remain = thread_timer_remain_second(m->timer);
1059
1060 /* unexpected case, but avoid wraparound problems below */
1061 if (remain > m->rfd->response_lifetime)
1062 return;
1063
1064 /* don't restart if we just restarted recently */
1065 if (m->rfd->response_lifetime - remain < 2)
1066 return;
1067
1068 thread_cancel(&m->timer);
1069 }
1070
1071 {
1072 char buf[BUFSIZ];
1073
1074 vnc_zlog_debug_verbose(
1075 "%s: target %s life %u", __func__,
1076 rfapiEthAddr2Str(&m->macaddr, buf, BUFSIZ),
1077 m->rfd->response_lifetime);
1078 }
1079 m->timer = NULL;
1080 thread_add_timer(bm->master, rfapiMonitorEthTimerExpire, m,
1081 m->rfd->response_lifetime, &m->timer);
1082 }
1083
1084 static int mon_eth_cmp(const void *a, const void *b)
1085 {
1086 const struct rfapi_monitor_eth *m1;
1087 const struct rfapi_monitor_eth *m2;
1088
1089 int i;
1090
1091 m1 = (struct rfapi_monitor_eth *)a;
1092 m2 = (struct rfapi_monitor_eth *)b;
1093
1094 /*
1095 * compare ethernet addresses
1096 */
1097 for (i = 0; i < ETH_ALEN; ++i) {
1098 if (m1->macaddr.octet[i] != m2->macaddr.octet[i])
1099 return (m1->macaddr.octet[i] - m2->macaddr.octet[i]);
1100 }
1101
1102 /*
1103 * compare LNIs
1104 */
1105 return (m1->logical_net_id - m2->logical_net_id);
1106 }
1107
1108 static void rfapiMonitorEthAttachImport(
1109 struct rfapi_import_table *it,
1110 struct agg_node *rn, /* it node attach point if non-0 */
1111 struct rfapi_monitor_eth *mon) /* monitor struct to attach */
1112 {
1113 struct skiplist *sl;
1114 int rc;
1115
1116 vnc_zlog_debug_verbose("%s: it=%p", __func__, it);
1117
1118 rfapiMonitorCheckAttachAllowed();
1119
1120 if (RFAPI_0_ETHERADDR(&mon->macaddr)) {
1121 /*
1122 * These go on a different list
1123 */
1124 mon->next = it->eth0_queries;
1125 it->eth0_queries = mon;
1126 #if DEBUG_L2_EXTRA
1127 vnc_zlog_debug_verbose("%s: attached monitor %p to eth0 list",
1128 __func__, mon);
1129 #endif
1130 return;
1131 }
1132
1133 if (rn == NULL) {
1134 #if DEBUG_L2_EXTRA
1135 vnc_zlog_debug_verbose("%s: rn is null!", __func__);
1136 #endif
1137 return;
1138 }
1139
1140 /*
1141 * Get sl to attach to
1142 */
1143 sl = RFAPI_MONITOR_ETH_W_ALLOC(rn);
1144 if (!sl) {
1145 sl = RFAPI_MONITOR_ETH_W_ALLOC(rn) =
1146 skiplist_new(0, NULL, NULL);
1147 agg_lock_node(rn); /* count skiplist mon_eth */
1148 }
1149
1150 #if DEBUG_L2_EXTRA
1151 vnc_zlog_debug_verbose(
1152 "%s: rn=%p, rn->lock=%d, sl=%p, attaching eth mon %p", __func__,
1153 rn, rn->lock, sl, mon);
1154 #endif
1155
1156 rc = skiplist_insert(sl, (void *)mon, (void *)mon);
1157 assert(!rc);
1158
1159 /* count eth monitor */
1160 agg_lock_node(rn);
1161 }
1162
1163 /*
1164 * reattach monitors for this HD to import table
1165 */
1166 static void rfapiMonitorEthAttachImportHd(struct bgp *bgp,
1167 struct rfapi_descriptor *rfd)
1168 {
1169 void *cursor;
1170 struct rfapi_monitor_eth *mon;
1171 int rc;
1172
1173 if (!rfd->mon_eth) {
1174 /*
1175 * No monitors for this HD
1176 */
1177 return;
1178 }
1179
1180 for (cursor = NULL,
1181 rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon, &cursor);
1182 rc == 0;
1183 rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon, &cursor)) {
1184
1185 struct rfapi_import_table *it;
1186 struct prefix pfx_mac_buf;
1187 struct agg_node *rn;
1188
1189 it = rfapiMacImportTableGet(bgp, mon->logical_net_id);
1190 assert(it);
1191
1192 memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
1193 pfx_mac_buf.family = AF_ETHERNET;
1194 pfx_mac_buf.prefixlen = 48;
1195 pfx_mac_buf.u.prefix_eth = mon->macaddr;
1196
1197 rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
1198 assert(rn);
1199
1200 (void)rfapiMonitorEthAttachImport(it, rn, mon);
1201 }
1202 }
1203
1204 static void rfapiMonitorEthDetachImport(
1205 struct bgp *bgp,
1206 struct rfapi_monitor_eth *mon) /* monitor struct to detach */
1207 {
1208 struct rfapi_import_table *it;
1209 struct prefix pfx_mac_buf;
1210 struct skiplist *sl;
1211 struct agg_node *rn;
1212 int rc;
1213
1214 it = rfapiMacImportTableGet(bgp, mon->logical_net_id);
1215 assert(it);
1216
1217 if (RFAPI_0_ETHERADDR(&mon->macaddr)) {
1218 struct rfapi_monitor_eth *prev;
1219 struct rfapi_monitor_eth *this = NULL;
1220
1221 for (prev = NULL, this = it->eth0_queries; this;
1222 prev = this, this = this->next) {
1223
1224 if (this == mon)
1225 break;
1226 }
1227 if (this) {
1228 if (!prev) {
1229 it->eth0_queries = this->next;
1230 } else {
1231 prev->next = this->next;
1232 }
1233 }
1234 #if DEBUG_L2_EXTRA
1235 vnc_zlog_debug_verbose(
1236 "%s: it=%p, LNI=%d, detached eth0 mon %p", __func__, it,
1237 mon->logical_net_id, mon);
1238 #endif
1239 return;
1240 }
1241
1242 memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
1243 pfx_mac_buf.family = AF_ETHERNET;
1244 pfx_mac_buf.prefixlen = 48;
1245 pfx_mac_buf.u.prefix_eth = mon->macaddr;
1246
1247 rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
1248 assert(rn);
1249
1250 /*
1251 * Get sl to detach from
1252 */
1253 sl = RFAPI_MONITOR_ETH(rn);
1254 #if DEBUG_L2_EXTRA
1255 vnc_zlog_debug_verbose(
1256 "%s: it=%p, rn=%p, rn->lock=%d, sl=%p, pfx=%pFX, LNI=%d, detaching eth mon %p",
1257 __func__, it, rn, rn->lock, sl, agg_node_get_prefix(rn),
1258 mon->logical_net_id, mon);
1259 #endif
1260 assert(sl);
1261
1262
1263 rc = skiplist_delete(sl, (void *)mon, (void *)mon);
1264 assert(!rc);
1265
1266 /* uncount eth monitor */
1267 agg_unlock_node(rn);
1268 }
1269
1270 struct agg_node *rfapiMonitorEthAdd(struct bgp *bgp,
1271 struct rfapi_descriptor *rfd,
1272 struct ethaddr *macaddr,
1273 uint32_t logical_net_id)
1274 {
1275 int rc;
1276 struct rfapi_monitor_eth mon_buf;
1277 struct rfapi_monitor_eth *val;
1278 struct rfapi_import_table *it;
1279 struct agg_node *rn = NULL;
1280 struct prefix pfx_mac_buf;
1281
1282 if (!rfd->mon_eth) {
1283 rfd->mon_eth = skiplist_new(0, mon_eth_cmp, NULL);
1284 }
1285
1286 it = rfapiMacImportTableGet(bgp, logical_net_id);
1287 assert(it);
1288
1289 /*
1290 * Get route node in import table. Here is where we attach the
1291 * monitor.
1292 *
1293 * Look it up now because we return it to caller regardless of
1294 * whether we create a new monitor or not.
1295 */
1296 memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
1297 pfx_mac_buf.family = AF_ETHERNET;
1298 pfx_mac_buf.prefixlen = 48;
1299 pfx_mac_buf.u.prefix_eth = *macaddr;
1300
1301 if (!RFAPI_0_ETHERADDR(macaddr)) {
1302 rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
1303 assert(rn);
1304 }
1305
1306 memset((void *)&mon_buf, 0, sizeof(mon_buf));
1307 mon_buf.rfd = rfd;
1308 mon_buf.macaddr = *macaddr;
1309 mon_buf.logical_net_id = logical_net_id;
1310
1311 {
1312 char buf[BUFSIZ];
1313
1314 vnc_zlog_debug_verbose(
1315 "%s: LNI=%d: rfd=%p, pfx=%s", __func__, logical_net_id,
1316 rfd, rfapi_ntop(pfx_mac_buf.family, pfx_mac_buf.u.val,
1317 buf, BUFSIZ));
1318 }
1319
1320
1321 /*
1322 * look up query
1323 */
1324 rc = skiplist_search(rfd->mon_eth, (void *)&mon_buf, (void **)&val);
1325 if (!rc) {
1326 /*
1327 * Found monitor - we have seen this query before
1328 * restart timer
1329 */
1330 vnc_zlog_debug_verbose(
1331 "%s: already present in rfd->mon_eth, not adding",
1332 __func__);
1333 rfapiMonitorEthTimerRestart(val);
1334 return rn;
1335 }
1336
1337 /*
1338 * New query
1339 */
1340 val = XCALLOC(MTYPE_RFAPI_MONITOR_ETH,
1341 sizeof(struct rfapi_monitor_eth));
1342 assert(val);
1343 *val = mon_buf;
1344
1345 ++rfd->monitor_count;
1346 ++bgp->rfapi->monitor_count;
1347
1348 rc = skiplist_insert(rfd->mon_eth, val, val);
1349
1350 #if DEBUG_L2_EXTRA
1351 vnc_zlog_debug_verbose("%s: inserted rfd=%p mon_eth=%p, rc=%d",
1352 __func__, rfd, val, rc);
1353 #else
1354 (void)rc;
1355 #endif
1356
1357 /*
1358 * start timer
1359 */
1360 rfapiMonitorEthTimerRestart(val);
1361
1362 if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
1363 /*
1364 * callbacks turned off, so don't attach monitor to import table
1365 */
1366 #if DEBUG_L2_EXTRA
1367 vnc_zlog_debug_verbose(
1368 "%s: callbacks turned off, not attaching mon_eth %p to import table",
1369 __func__, val);
1370 #endif
1371 return rn;
1372 }
1373
1374 /*
1375 * attach to import table
1376 */
1377 rfapiMonitorEthAttachImport(it, rn, val);
1378
1379 return rn;
1380 }
1381
1382 void rfapiMonitorEthDel(struct bgp *bgp, struct rfapi_descriptor *rfd,
1383 struct ethaddr *macaddr, uint32_t logical_net_id)
1384 {
1385 struct rfapi_monitor_eth *val;
1386 struct rfapi_monitor_eth mon_buf;
1387 int rc;
1388
1389 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__, rfd);
1390
1391 assert(rfd->mon_eth);
1392
1393 memset((void *)&mon_buf, 0, sizeof(mon_buf));
1394 mon_buf.macaddr = *macaddr;
1395 mon_buf.logical_net_id = logical_net_id;
1396
1397 rc = skiplist_search(rfd->mon_eth, (void *)&mon_buf, (void **)&val);
1398 assert(!rc);
1399
1400 /*
1401 * remove from import table
1402 */
1403 if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
1404 rfapiMonitorEthDetachImport(bgp, val);
1405 }
1406
1407 thread_cancel(&val->timer);
1408
1409 /*
1410 * remove from rfd list
1411 */
1412 rc = skiplist_delete(rfd->mon_eth, val, val);
1413 assert(!rc);
1414
1415 #if DEBUG_L2_EXTRA
1416 vnc_zlog_debug_verbose("%s: freeing mon_eth %p", __func__, val);
1417 #endif
1418 XFREE(MTYPE_RFAPI_MONITOR_ETH, val);
1419
1420 --rfd->monitor_count;
1421 --bgp->rfapi->monitor_count;
1422 }
1423
1424
1425 void rfapiMonitorCallbacksOff(struct bgp *bgp)
1426 {
1427 struct rfapi_import_table *it;
1428 afi_t afi;
1429 struct agg_table *rt;
1430 struct agg_node *rn;
1431 void *cursor;
1432 int rc;
1433 struct rfapi *h = bgp->rfapi;
1434
1435 if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
1436 /*
1437 * Already off.
1438 */
1439 return;
1440 }
1441 bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_CALLBACK_DISABLE;
1442
1443 #if DEBUG_L2_EXTRA
1444 vnc_zlog_debug_verbose("%s: turned off callbacks", __func__);
1445 #endif
1446
1447 if (h == NULL)
1448 return;
1449 /*
1450 * detach monitors from import VPN tables. The monitors
1451 * will still be linked in per-nve monitor lists.
1452 */
1453 for (it = h->imports; it; it = it->next) {
1454 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
1455
1456 struct rfapi_monitor_vpn *m;
1457 struct rfapi_monitor_vpn *next;
1458
1459 rt = it->imported_vpn[afi];
1460
1461 for (rn = agg_route_top(rt); rn;
1462 rn = agg_route_next(rn)) {
1463 m = RFAPI_MONITOR_VPN(rn);
1464 if (RFAPI_MONITOR_VPN(rn))
1465 RFAPI_MONITOR_VPN_W_ALLOC(rn) = NULL;
1466 for (; m; m = next) {
1467 next = m->next;
1468 m->next =
1469 NULL; /* gratuitous safeness */
1470 m->node = NULL;
1471 agg_unlock_node(rn); /* uncount */
1472 }
1473 }
1474
1475 for (m = it->vpn0_queries[afi]; m; m = next) {
1476 next = m->next;
1477 m->next = NULL; /* gratuitous safeness */
1478 m->node = NULL;
1479 }
1480 it->vpn0_queries[afi] = NULL; /* detach first monitor */
1481 }
1482 }
1483
1484 /*
1485 * detach monitors from import Eth tables. The monitors
1486 * will still be linked in per-nve monitor lists.
1487 */
1488
1489 /*
1490 * Loop over ethernet import tables
1491 */
1492 for (cursor = NULL,
1493 rc = skiplist_next(h->import_mac, NULL, (void **)&it, &cursor);
1494 !rc;
1495 rc = skiplist_next(h->import_mac, NULL, (void **)&it, &cursor)) {
1496 struct rfapi_monitor_eth *e;
1497 struct rfapi_monitor_eth *enext;
1498
1499 /*
1500 * The actual route table
1501 */
1502 rt = it->imported_vpn[AFI_L2VPN];
1503
1504 /*
1505 * Find non-0 monitors (i.e., actual addresses, not FTD
1506 * monitors)
1507 */
1508 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1509 struct skiplist *sl;
1510
1511 sl = RFAPI_MONITOR_ETH(rn);
1512 while (!skiplist_delete_first(sl)) {
1513 agg_unlock_node(rn); /* uncount monitor */
1514 }
1515 }
1516
1517 /*
1518 * Find 0-monitors (FTD queries)
1519 */
1520 for (e = it->eth0_queries; e; e = enext) {
1521 #if DEBUG_L2_EXTRA
1522 vnc_zlog_debug_verbose("%s: detaching eth0 mon %p",
1523 __func__, e);
1524 #endif
1525 enext = e->next;
1526 e->next = NULL; /* gratuitous safeness */
1527 }
1528 it->eth0_queries = NULL; /* detach first monitor */
1529 }
1530 }
1531
1532 void rfapiMonitorCallbacksOn(struct bgp *bgp)
1533 {
1534 struct listnode *hnode;
1535 struct rfapi_descriptor *rfd;
1536
1537 if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
1538 /*
1539 * Already on. It's important that we don't try to reattach
1540 * monitors that are already attached because, in the interest
1541 * of performance, there is no checking at the lower level
1542 * whether a monitor is already attached. It leads to
1543 * corrupted chains (e.g., looped pointers)
1544 */
1545 return;
1546 }
1547 bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_CALLBACK_DISABLE;
1548 #if DEBUG_L2_EXTRA
1549 vnc_zlog_debug_verbose("%s: turned on callbacks", __func__);
1550 #endif
1551 if (bgp->rfapi == NULL)
1552 return;
1553
1554 /*
1555 * reattach monitors
1556 */
1557 for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, hnode, rfd)) {
1558
1559 rfapiMonitorAttachImportHd(rfd);
1560 rfapiMonitorEthAttachImportHd(bgp, rfd);
1561 }
1562 }