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