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  */
rfapiMonitorEthSlCheck(struct agg_node * rn,const char * tag1,const char * tag2)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  */
rfapiMonitorLoopCheck(struct rfapi_monitor_vpn * mchain)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  */
rfapiMonitorDupCheck(struct bgp * bgp)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 */
rfapiMonitorCleanCheck(struct bgp * bgp)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 */
rfapiMonitorCheckAttachAllowed(void)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 
rfapiMonitorExtraFlush(safi_t safi,struct agg_node * rn)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  */
rfapiMonitorExtraPrune(safi_t safi,struct agg_node * rn)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  */
rfapiMonitorGetAttachNode(struct rfapi_descriptor * rfd,struct prefix * p)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  */
rfapiMonitorAttachImport(struct rfapi_descriptor * rfd,struct rfapi_monitor_vpn * m)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  */
rfapiMonitorAttachImportHd(struct rfapi_descriptor * rfd)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  */
rfapiMonitorAdd(struct bgp * bgp,struct rfapi_descriptor * rfd,struct prefix * p)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 *
rfapiMonitorDetachImport(struct rfapi_monitor_vpn * m)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 
rfapiMonitorDetachImportHd(struct rfapi_descriptor * rfd)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 
rfapiMonitorDel(struct bgp * bgp,struct rfapi_descriptor * rfd,struct prefix * p)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 	if (m->timer) {
624 		thread_cancel(m->timer);
625 		m->timer = NULL;
626 	}
627 
628 	/*
629 	 * remove from rfd list
630 	 */
631 	XFREE(MTYPE_RFAPI_MONITOR, m);
632 	rn->info = NULL;
633 	agg_unlock_node(rn); /* undo original lock when created */
634 	agg_unlock_node(rn); /* undo lock in agg_node_get */
635 
636 	--rfd->monitor_count;
637 	--bgp->rfapi->monitor_count;
638 }
639 
640 /*
641  * returns count of monitors deleted
642  */
rfapiMonitorDelHd(struct rfapi_descriptor * rfd)643 int rfapiMonitorDelHd(struct rfapi_descriptor *rfd)
644 {
645 	struct agg_node *rn;
646 	struct bgp *bgp;
647 	int count = 0;
648 
649 	vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__, rfd);
650 
651 	bgp = bgp_get_default();
652 
653 	if (rfd->mon) {
654 		for (rn = agg_route_top(rfd->mon); rn;
655 		     rn = agg_route_next(rn)) {
656 			struct rfapi_monitor_vpn *m;
657 			if ((m = rn->info)) {
658 				if (!(bgp->rfapi_cfg->flags
659 				      & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
660 					rfapiMonitorDetachImport(m);
661 				}
662 
663 				if (m->timer) {
664 					thread_cancel(m->timer);
665 					m->timer = NULL;
666 				}
667 
668 				XFREE(MTYPE_RFAPI_MONITOR, m);
669 				rn->info = NULL;
670 				agg_unlock_node(rn); /* undo original lock
671 							  when created */
672 				++count;
673 				--rfd->monitor_count;
674 				--bgp->rfapi->monitor_count;
675 			}
676 		}
677 		agg_table_finish(rfd->mon);
678 		rfd->mon = NULL;
679 	}
680 
681 	if (rfd->mon_eth) {
682 
683 		struct rfapi_monitor_eth *mon_eth;
684 
685 		while (!skiplist_first(rfd->mon_eth, NULL, (void **)&mon_eth)) {
686 
687 			int rc;
688 
689 			if (!(bgp->rfapi_cfg->flags
690 			      & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
691 				rfapiMonitorEthDetachImport(bgp, mon_eth);
692 			} else {
693 #if DEBUG_L2_EXTRA
694 				vnc_zlog_debug_verbose(
695 					"%s: callbacks disabled, not attempting to detach mon_eth %p",
696 					__func__, mon_eth);
697 #endif
698 			}
699 
700 			if (mon_eth->timer) {
701 				thread_cancel(mon_eth->timer);
702 				mon_eth->timer = NULL;
703 			}
704 
705 			/*
706 			 * remove from rfd list
707 			 */
708 			rc = skiplist_delete(rfd->mon_eth, mon_eth, mon_eth);
709 			assert(!rc);
710 
711 			vnc_zlog_debug_verbose("%s: freeing mon_eth %p",
712 					       __func__, mon_eth);
713 			XFREE(MTYPE_RFAPI_MONITOR_ETH, mon_eth);
714 
715 			++count;
716 			--rfd->monitor_count;
717 			--bgp->rfapi->monitor_count;
718 		}
719 		skiplist_free(rfd->mon_eth);
720 		rfd->mon_eth = NULL;
721 	}
722 
723 	return count;
724 }
725 
rfapiMonitorResponseRemovalOff(struct bgp * bgp)726 void rfapiMonitorResponseRemovalOff(struct bgp *bgp)
727 {
728 	if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE) {
729 		return;
730 	}
731 	bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE;
732 }
733 
rfapiMonitorResponseRemovalOn(struct bgp * bgp)734 void rfapiMonitorResponseRemovalOn(struct bgp *bgp)
735 {
736 	if (!(bgp->rfapi_cfg->flags
737 	      & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) {
738 		return;
739 	}
740 	bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE;
741 }
742 
rfapiMonitorTimerExpire(struct thread * t)743 static int rfapiMonitorTimerExpire(struct thread *t)
744 {
745 	struct rfapi_monitor_vpn *m = t->arg;
746 
747 	/* forget reference to thread, it's gone */
748 	m->timer = NULL;
749 
750 	/* delete the monitor */
751 	rfapiMonitorDel(bgp_get_default(), m->rfd, &m->p);
752 
753 	return 0;
754 }
755 
rfapiMonitorTimerRestart(struct rfapi_monitor_vpn * m)756 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m)
757 {
758 	if (m->timer) {
759 		unsigned long remain = thread_timer_remain_second(m->timer);
760 
761 		/* unexpected case, but avoid wraparound problems below */
762 		if (remain > m->rfd->response_lifetime)
763 			return;
764 
765 		/* don't restart if we just restarted recently */
766 		if (m->rfd->response_lifetime - remain < 2)
767 			return;
768 
769 		thread_cancel(m->timer);
770 		m->timer = NULL;
771 	}
772 
773 	{
774 		char buf[BUFSIZ];
775 
776 		vnc_zlog_debug_verbose(
777 			"%s: target %s life %u", __func__,
778 			rfapi_ntop(m->p.family, m->p.u.val, buf, BUFSIZ),
779 			m->rfd->response_lifetime);
780 	}
781 	m->timer = NULL;
782 	thread_add_timer(bm->master, rfapiMonitorTimerExpire, m,
783 			 m->rfd->response_lifetime, &m->timer);
784 }
785 
786 /*
787  * called when an updated response is sent to the NVE. Per
788  * ticket 255, restart timers for any monitors that could have
789  * been responsible for the response, i.e., any monitors for
790  * the exact prefix or a parent of it.
791  */
rfapiMonitorTimersRestart(struct rfapi_descriptor * rfd,const struct prefix * p)792 void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd,
793 			       const struct prefix *p)
794 {
795 	struct agg_node *rn;
796 
797 	if (AF_ETHERNET == p->family) {
798 		struct rfapi_monitor_eth *mon_eth;
799 		int rc;
800 		void *cursor;
801 
802 		/*
803 		 * XXX match any LNI
804 		 */
805 		for (cursor = NULL,
806 		    rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon_eth,
807 				       &cursor);
808 		     rc == 0; rc = skiplist_next(rfd->mon_eth, NULL,
809 						 (void **)&mon_eth, &cursor)) {
810 
811 			if (!memcmp(mon_eth->macaddr.octet,
812 				    p->u.prefix_eth.octet, ETH_ALEN)) {
813 
814 				rfapiMonitorEthTimerRestart(mon_eth);
815 			}
816 		}
817 
818 	} else {
819 		for (rn = agg_route_top(rfd->mon); rn;
820 		     rn = agg_route_next(rn)) {
821 			struct rfapi_monitor_vpn *m;
822 			const struct prefix *p_node;
823 
824 			if (!((m = rn->info)))
825 				continue;
826 
827 			p_node = agg_node_get_prefix(m->node);
828 			/* NB order of test is significant ! */
829 			if (!m->node || prefix_match(p_node, p)) {
830 				rfapiMonitorTimerRestart(m);
831 			}
832 		}
833 	}
834 }
835 
836 /*
837  * Find monitors at this node and all its parents. Call
838  * rfapiRibUpdatePendingNode with this node and all corresponding NVEs.
839  */
rfapiMonitorItNodeChanged(struct rfapi_import_table * import_table,struct agg_node * it_node,struct rfapi_monitor_vpn * monitor_list)840 void rfapiMonitorItNodeChanged(
841 	struct rfapi_import_table *import_table, struct agg_node *it_node,
842 	struct rfapi_monitor_vpn *monitor_list) /* for base it node, NULL=all */
843 {
844 	struct skiplist *nves_seen;
845 	struct agg_node *rn = it_node;
846 	struct bgp *bgp = bgp_get_default();
847 	const struct prefix *p = agg_node_get_prefix(rn);
848 	afi_t afi = family2afi(p->family);
849 #if DEBUG_L2_EXTRA
850 	char buf_prefix[PREFIX_STRLEN];
851 #endif
852 
853 	assert(bgp);
854 	assert(import_table);
855 
856 	nves_seen = skiplist_new(0, NULL, NULL);
857 
858 #if DEBUG_L2_EXTRA
859 	prefix2str(&it_node->p, buf_prefix, sizeof(buf_prefix));
860 	vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%s",
861 			       __func__, import_table, it_node, buf_prefix);
862 #endif
863 
864 	if (AFI_L2VPN == afi) {
865 		struct rfapi_monitor_eth *m;
866 		struct skiplist *sl;
867 		void *cursor;
868 		int rc;
869 
870 		if ((sl = RFAPI_MONITOR_ETH(rn))) {
871 
872 			for (cursor = NULL,
873 			    rc = skiplist_next(sl, NULL, (void **)&m, &cursor);
874 			     !rc; rc = skiplist_next(sl, NULL, (void **)&m,
875 						     &cursor)) {
876 
877 				if (skiplist_search(nves_seen, m->rfd, NULL)) {
878 					/*
879 					 * Haven't done this NVE yet. Add to
880 					 * "seen" list.
881 					 */
882 					assert(!skiplist_insert(nves_seen,
883 								m->rfd, NULL));
884 
885 					/*
886 					 * update its RIB
887 					 */
888 					rfapiRibUpdatePendingNode(
889 						bgp, m->rfd, import_table,
890 						it_node,
891 						m->rfd->response_lifetime);
892 				}
893 			}
894 		}
895 
896 	} else {
897 
898 		struct rfapi_monitor_vpn *m;
899 
900 		if (monitor_list) {
901 			m = monitor_list;
902 		} else {
903 			m = RFAPI_MONITOR_VPN(rn);
904 		}
905 
906 		do {
907 			/*
908 			 * If we have reached the root node (parent==NULL) and
909 			 * there
910 			 * are no routes here (info==NULL), and the IT node that
911 			 * changed was not the root node (it_node->parent !=
912 			 * NULL),
913 			 * then any monitors at this node are here because they
914 			 * had
915 			 * no match at all. Therefore, do not send route updates
916 			 * to them
917 			 * because we haven't sent them an initial route.
918 			 */
919 			if (!agg_node_parent(rn) && !rn->info
920 			    && it_node->parent)
921 				break;
922 
923 			for (; m; m = m->next) {
924 
925 				if (RFAPI_0_PREFIX(&m->p)) {
926 					/* shouldn't happen, but be safe */
927 					continue;
928 				}
929 				if (skiplist_search(nves_seen, m->rfd, NULL)) {
930 					/*
931 					 * Haven't done this NVE yet. Add to
932 					 * "seen" list.
933 					 */
934 					assert(!skiplist_insert(nves_seen,
935 								m->rfd, NULL));
936 
937 					char buf_target_pfx[PREFIX_STRLEN];
938 
939 					prefix2str(&m->p, buf_target_pfx,
940 						   sizeof(buf_target_pfx));
941 					vnc_zlog_debug_verbose(
942 						"%s: update rfd %p attached to pfx %pRN (targ=%s)",
943 						__func__, m->rfd, m->node,
944 						buf_target_pfx);
945 
946 					/*
947 					 * update its RIB
948 					 */
949 					rfapiRibUpdatePendingNode(
950 						bgp, m->rfd, import_table,
951 						it_node,
952 						m->rfd->response_lifetime);
953 				}
954 			}
955 			rn = agg_node_parent(rn);
956 			if (rn)
957 				m = RFAPI_MONITOR_VPN(rn);
958 		} while (rn);
959 	}
960 
961 	/*
962 	 * All-routes L2 monitors
963 	 */
964 	if (AFI_L2VPN == afi) {
965 		struct rfapi_monitor_eth *e;
966 
967 #if DEBUG_L2_EXTRA
968 		vnc_zlog_debug_verbose("%s: checking L2 all-routes monitors",
969 				       __func__);
970 #endif
971 
972 		for (e = import_table->eth0_queries; e; e = e->next) {
973 #if DEBUG_L2_EXTRA
974 			vnc_zlog_debug_verbose("%s: checking eth0 mon=%p",
975 					       __func__, e);
976 #endif
977 			if (skiplist_search(nves_seen, e->rfd, NULL)) {
978 				/*
979 				 * Haven't done this NVE yet. Add to "seen"
980 				 * list.
981 				 */
982 				assert(!skiplist_insert(nves_seen, e->rfd,
983 							NULL));
984 
985 /*
986  * update its RIB
987  */
988 #if DEBUG_L2_EXTRA
989 				vnc_zlog_debug_verbose(
990 					"%s: found L2 all-routes monitor %p",
991 					__func__, e);
992 #endif
993 				rfapiRibUpdatePendingNode(
994 					bgp, e->rfd, import_table, it_node,
995 					e->rfd->response_lifetime);
996 			}
997 		}
998 	} else {
999 		struct rfapi_monitor_vpn *m;
1000 
1001 		/*
1002 		 * All-routes IPv4. IPv6 monitors
1003 		 */
1004 		for (m = import_table->vpn0_queries[afi]; m; m = m->next) {
1005 			if (skiplist_search(nves_seen, m->rfd, NULL)) {
1006 				/*
1007 				 * Haven't done this NVE yet. Add to "seen"
1008 				 * list.
1009 				 */
1010 				assert(!skiplist_insert(nves_seen, m->rfd,
1011 							NULL));
1012 
1013 				/*
1014 				 * update its RIB
1015 				 */
1016 				rfapiRibUpdatePendingNode(
1017 					bgp, m->rfd, import_table, it_node,
1018 					m->rfd->response_lifetime);
1019 			}
1020 		}
1021 	}
1022 
1023 	skiplist_free(nves_seen);
1024 }
1025 
1026 /*
1027  * For the listed monitors, update new node and its subtree, but
1028  * omit old node and its subtree
1029  */
rfapiMonitorMovedUp(struct rfapi_import_table * import_table,struct agg_node * old_node,struct agg_node * new_node,struct rfapi_monitor_vpn * monitor_list)1030 void rfapiMonitorMovedUp(struct rfapi_import_table *import_table,
1031 			 struct agg_node *old_node, struct agg_node *new_node,
1032 			 struct rfapi_monitor_vpn *monitor_list)
1033 {
1034 	struct bgp *bgp = bgp_get_default();
1035 	struct rfapi_monitor_vpn *m;
1036 
1037 	assert(new_node);
1038 	assert(old_node);
1039 	assert(new_node != old_node);
1040 
1041 	/*
1042 	 * If new node is 0/0 and there is no route there, don't
1043 	 * generate an update because it will not contain any
1044 	 * routes including the target.
1045 	 */
1046 	if (!new_node->parent && !new_node->info) {
1047 		vnc_zlog_debug_verbose(
1048 			"%s: new monitor at 0/0 and no routes, no updates",
1049 			__func__);
1050 		return;
1051 	}
1052 
1053 	for (m = monitor_list; m; m = m->next) {
1054 		rfapiRibUpdatePendingNode(bgp, m->rfd, import_table, new_node,
1055 					  m->rfd->response_lifetime);
1056 		rfapiRibUpdatePendingNodeSubtree(bgp, m->rfd, import_table,
1057 						 new_node, old_node,
1058 						 m->rfd->response_lifetime);
1059 	}
1060 }
1061 
rfapiMonitorEthTimerExpire(struct thread * t)1062 static int rfapiMonitorEthTimerExpire(struct thread *t)
1063 {
1064 	struct rfapi_monitor_eth *m = t->arg;
1065 
1066 	/* forget reference to thread, it's gone */
1067 	m->timer = NULL;
1068 
1069 	/* delete the monitor */
1070 	rfapiMonitorEthDel(bgp_get_default(), m->rfd, &m->macaddr,
1071 			   m->logical_net_id);
1072 
1073 	return 0;
1074 }
1075 
rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth * m)1076 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m)
1077 {
1078 	if (m->timer) {
1079 		unsigned long remain = thread_timer_remain_second(m->timer);
1080 
1081 		/* unexpected case, but avoid wraparound problems below */
1082 		if (remain > m->rfd->response_lifetime)
1083 			return;
1084 
1085 		/* don't restart if we just restarted recently */
1086 		if (m->rfd->response_lifetime - remain < 2)
1087 			return;
1088 
1089 		thread_cancel(m->timer);
1090 		m->timer = NULL;
1091 	}
1092 
1093 	{
1094 		char buf[BUFSIZ];
1095 
1096 		vnc_zlog_debug_verbose(
1097 			"%s: target %s life %u", __func__,
1098 			rfapiEthAddr2Str(&m->macaddr, buf, BUFSIZ),
1099 			m->rfd->response_lifetime);
1100 	}
1101 	m->timer = NULL;
1102 	thread_add_timer(bm->master, rfapiMonitorEthTimerExpire, m,
1103 			 m->rfd->response_lifetime, &m->timer);
1104 }
1105 
mon_eth_cmp(const void * a,const void * b)1106 static int mon_eth_cmp(const void *a, const void *b)
1107 {
1108 	const struct rfapi_monitor_eth *m1;
1109 	const struct rfapi_monitor_eth *m2;
1110 
1111 	int i;
1112 
1113 	m1 = (struct rfapi_monitor_eth *)a;
1114 	m2 = (struct rfapi_monitor_eth *)b;
1115 
1116 	/*
1117 	 * compare ethernet addresses
1118 	 */
1119 	for (i = 0; i < ETH_ALEN; ++i) {
1120 		if (m1->macaddr.octet[i] != m2->macaddr.octet[i])
1121 			return (m1->macaddr.octet[i] - m2->macaddr.octet[i]);
1122 	}
1123 
1124 	/*
1125 	 * compare LNIs
1126 	 */
1127 	return (m1->logical_net_id - m2->logical_net_id);
1128 }
1129 
rfapiMonitorEthAttachImport(struct rfapi_import_table * it,struct agg_node * rn,struct rfapi_monitor_eth * mon)1130 static void rfapiMonitorEthAttachImport(
1131 	struct rfapi_import_table *it,
1132 	struct agg_node *rn,	   /* it node attach point if non-0 */
1133 	struct rfapi_monitor_eth *mon) /* monitor struct to attach */
1134 {
1135 	struct skiplist *sl;
1136 	int rc;
1137 
1138 	vnc_zlog_debug_verbose("%s: it=%p", __func__, it);
1139 
1140 	rfapiMonitorCheckAttachAllowed();
1141 
1142 	if (RFAPI_0_ETHERADDR(&mon->macaddr)) {
1143 		/*
1144 		 * These go on a different list
1145 		 */
1146 		mon->next = it->eth0_queries;
1147 		it->eth0_queries = mon;
1148 #if DEBUG_L2_EXTRA
1149 		vnc_zlog_debug_verbose("%s: attached monitor %p to eth0 list",
1150 				       __func__, mon);
1151 #endif
1152 		return;
1153 	}
1154 
1155 	if (rn == NULL) {
1156 #if DEBUG_L2_EXTRA
1157 		vnc_zlog_debug_verbose("%s: rn is null!", __func__);
1158 #endif
1159 		return;
1160 	}
1161 
1162 	/*
1163 	 * Get sl to attach to
1164 	 */
1165 	sl = RFAPI_MONITOR_ETH_W_ALLOC(rn);
1166 	if (!sl) {
1167 		sl = RFAPI_MONITOR_ETH_W_ALLOC(rn) =
1168 			skiplist_new(0, NULL, NULL);
1169 		agg_lock_node(rn); /* count skiplist mon_eth */
1170 	}
1171 
1172 #if DEBUG_L2_EXTRA
1173 	vnc_zlog_debug_verbose(
1174 		"%s: rn=%p, rn->lock=%d, sl=%p, attaching eth mon %p", __func__,
1175 		rn, rn->lock, sl, mon);
1176 #endif
1177 
1178 	rc = skiplist_insert(sl, (void *)mon, (void *)mon);
1179 	assert(!rc);
1180 
1181 	/* count eth monitor */
1182 	agg_lock_node(rn);
1183 }
1184 
1185 /*
1186  * reattach monitors for this HD to import table
1187  */
rfapiMonitorEthAttachImportHd(struct bgp * bgp,struct rfapi_descriptor * rfd)1188 static void rfapiMonitorEthAttachImportHd(struct bgp *bgp,
1189 					  struct rfapi_descriptor *rfd)
1190 {
1191 	void *cursor;
1192 	struct rfapi_monitor_eth *mon;
1193 	int rc;
1194 
1195 	if (!rfd->mon_eth) {
1196 		/*
1197 		 * No monitors for this HD
1198 		 */
1199 		return;
1200 	}
1201 
1202 	for (cursor = NULL,
1203 	    rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon, &cursor);
1204 	     rc == 0;
1205 	     rc = skiplist_next(rfd->mon_eth, NULL, (void **)&mon, &cursor)) {
1206 
1207 		struct rfapi_import_table *it;
1208 		struct prefix pfx_mac_buf;
1209 		struct agg_node *rn;
1210 
1211 		it = rfapiMacImportTableGet(bgp, mon->logical_net_id);
1212 		assert(it);
1213 
1214 		memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
1215 		pfx_mac_buf.family = AF_ETHERNET;
1216 		pfx_mac_buf.prefixlen = 48;
1217 		pfx_mac_buf.u.prefix_eth = mon->macaddr;
1218 
1219 		rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
1220 		assert(rn);
1221 
1222 		(void)rfapiMonitorEthAttachImport(it, rn, mon);
1223 	}
1224 }
1225 
rfapiMonitorEthDetachImport(struct bgp * bgp,struct rfapi_monitor_eth * mon)1226 static void rfapiMonitorEthDetachImport(
1227 	struct bgp *bgp,
1228 	struct rfapi_monitor_eth *mon) /* monitor struct to detach */
1229 {
1230 	struct rfapi_import_table *it;
1231 	struct prefix pfx_mac_buf;
1232 	struct skiplist *sl;
1233 	struct agg_node *rn;
1234 	int rc;
1235 
1236 	it = rfapiMacImportTableGet(bgp, mon->logical_net_id);
1237 	assert(it);
1238 
1239 	if (RFAPI_0_ETHERADDR(&mon->macaddr)) {
1240 		struct rfapi_monitor_eth *prev;
1241 		struct rfapi_monitor_eth *this = NULL;
1242 
1243 		for (prev = NULL, this = it->eth0_queries; this;
1244 		     prev = this, this = this->next) {
1245 
1246 			if (this == mon)
1247 				break;
1248 		}
1249 		if (this) {
1250 			if (!prev) {
1251 				it->eth0_queries = this->next;
1252 			} else {
1253 				prev->next = this->next;
1254 			}
1255 		}
1256 #if DEBUG_L2_EXTRA
1257 		vnc_zlog_debug_verbose(
1258 			"%s: it=%p, LNI=%d, detached eth0 mon %p", __func__, it,
1259 			mon->logical_net_id, mon);
1260 #endif
1261 		return;
1262 	}
1263 
1264 	memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
1265 	pfx_mac_buf.family = AF_ETHERNET;
1266 	pfx_mac_buf.prefixlen = 48;
1267 	pfx_mac_buf.u.prefix_eth = mon->macaddr;
1268 
1269 	rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
1270 	assert(rn);
1271 
1272 #if DEBUG_L2_EXTRA
1273 	char buf_prefix[PREFIX_STRLEN];
1274 
1275 	prefix2str(agg_node_get_prefix(rn), buf_prefix, sizeof(buf_prefix));
1276 #endif
1277 
1278 	/*
1279 	 * Get sl to detach from
1280 	 */
1281 	sl = RFAPI_MONITOR_ETH(rn);
1282 #if DEBUG_L2_EXTRA
1283 	vnc_zlog_debug_verbose(
1284 		"%s: it=%p, rn=%p, rn->lock=%d, sl=%p, pfx=%s, LNI=%d, detaching eth mon %p",
1285 		__func__, it, rn, rn->lock, sl, buf_prefix, mon->logical_net_id,
1286 		mon);
1287 #endif
1288 	assert(sl);
1289 
1290 
1291 	rc = skiplist_delete(sl, (void *)mon, (void *)mon);
1292 	assert(!rc);
1293 
1294 	/* uncount eth monitor */
1295 	agg_unlock_node(rn);
1296 }
1297 
rfapiMonitorEthAdd(struct bgp * bgp,struct rfapi_descriptor * rfd,struct ethaddr * macaddr,uint32_t logical_net_id)1298 struct agg_node *rfapiMonitorEthAdd(struct bgp *bgp,
1299 				    struct rfapi_descriptor *rfd,
1300 				    struct ethaddr *macaddr,
1301 				    uint32_t logical_net_id)
1302 {
1303 	int rc;
1304 	struct rfapi_monitor_eth mon_buf;
1305 	struct rfapi_monitor_eth *val;
1306 	struct rfapi_import_table *it;
1307 	struct agg_node *rn = NULL;
1308 	struct prefix pfx_mac_buf;
1309 
1310 	if (!rfd->mon_eth) {
1311 		rfd->mon_eth = skiplist_new(0, mon_eth_cmp, NULL);
1312 	}
1313 
1314 	it = rfapiMacImportTableGet(bgp, logical_net_id);
1315 	assert(it);
1316 
1317 	/*
1318 	 * Get route node in import table. Here is where we attach the
1319 	 * monitor.
1320 	 *
1321 	 * Look it up now because we return it to caller regardless of
1322 	 * whether we create a new monitor or not.
1323 	 */
1324 	memset((void *)&pfx_mac_buf, 0, sizeof(struct prefix));
1325 	pfx_mac_buf.family = AF_ETHERNET;
1326 	pfx_mac_buf.prefixlen = 48;
1327 	pfx_mac_buf.u.prefix_eth = *macaddr;
1328 
1329 	if (!RFAPI_0_ETHERADDR(macaddr)) {
1330 		rn = agg_node_get(it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
1331 		assert(rn);
1332 	}
1333 
1334 	memset((void *)&mon_buf, 0, sizeof(mon_buf));
1335 	mon_buf.rfd = rfd;
1336 	mon_buf.macaddr = *macaddr;
1337 	mon_buf.logical_net_id = logical_net_id;
1338 
1339 	{
1340 		char buf[BUFSIZ];
1341 
1342 		vnc_zlog_debug_verbose(
1343 			"%s: LNI=%d: rfd=%p, pfx=%s", __func__, logical_net_id,
1344 			rfd, rfapi_ntop(pfx_mac_buf.family, pfx_mac_buf.u.val,
1345 					buf, BUFSIZ));
1346 	}
1347 
1348 
1349 	/*
1350 	 * look up query
1351 	 */
1352 	rc = skiplist_search(rfd->mon_eth, (void *)&mon_buf, (void **)&val);
1353 	if (!rc) {
1354 		/*
1355 		 * Found monitor - we have seen this query before
1356 		 * restart timer
1357 		 */
1358 		vnc_zlog_debug_verbose(
1359 			"%s: already present in rfd->mon_eth, not adding",
1360 			__func__);
1361 		rfapiMonitorEthTimerRestart(val);
1362 		return rn;
1363 	}
1364 
1365 	/*
1366 	 * New query
1367 	 */
1368 	val = XCALLOC(MTYPE_RFAPI_MONITOR_ETH,
1369 		      sizeof(struct rfapi_monitor_eth));
1370 	assert(val);
1371 	*val = mon_buf;
1372 
1373 	++rfd->monitor_count;
1374 	++bgp->rfapi->monitor_count;
1375 
1376 	rc = skiplist_insert(rfd->mon_eth, val, val);
1377 
1378 #if DEBUG_L2_EXTRA
1379 	vnc_zlog_debug_verbose("%s: inserted rfd=%p mon_eth=%p, rc=%d",
1380 			       __func__, rfd, val, rc);
1381 #else
1382 	(void)rc;
1383 #endif
1384 
1385 	/*
1386 	 * start timer
1387 	 */
1388 	rfapiMonitorEthTimerRestart(val);
1389 
1390 	if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
1391 /*
1392  * callbacks turned off, so don't attach monitor to import table
1393  */
1394 #if DEBUG_L2_EXTRA
1395 		vnc_zlog_debug_verbose(
1396 			"%s: callbacks turned off, not attaching mon_eth %p to import table",
1397 			__func__, val);
1398 #endif
1399 		return rn;
1400 	}
1401 
1402 	/*
1403 	 * attach to import table
1404 	 */
1405 	rfapiMonitorEthAttachImport(it, rn, val);
1406 
1407 	return rn;
1408 }
1409 
rfapiMonitorEthDel(struct bgp * bgp,struct rfapi_descriptor * rfd,struct ethaddr * macaddr,uint32_t logical_net_id)1410 void rfapiMonitorEthDel(struct bgp *bgp, struct rfapi_descriptor *rfd,
1411 			struct ethaddr *macaddr, uint32_t logical_net_id)
1412 {
1413 	struct rfapi_monitor_eth *val;
1414 	struct rfapi_monitor_eth mon_buf;
1415 	int rc;
1416 
1417 	vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__, rfd);
1418 
1419 	assert(rfd->mon_eth);
1420 
1421 	memset((void *)&mon_buf, 0, sizeof(mon_buf));
1422 	mon_buf.macaddr = *macaddr;
1423 	mon_buf.logical_net_id = logical_net_id;
1424 
1425 	rc = skiplist_search(rfd->mon_eth, (void *)&mon_buf, (void **)&val);
1426 	assert(!rc);
1427 
1428 	/*
1429 	 * remove from import table
1430 	 */
1431 	if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
1432 		rfapiMonitorEthDetachImport(bgp, val);
1433 	}
1434 
1435 	if (val->timer) {
1436 		thread_cancel(val->timer);
1437 		val->timer = NULL;
1438 	}
1439 
1440 	/*
1441 	 * remove from rfd list
1442 	 */
1443 	rc = skiplist_delete(rfd->mon_eth, val, val);
1444 	assert(!rc);
1445 
1446 #if DEBUG_L2_EXTRA
1447 	vnc_zlog_debug_verbose("%s: freeing mon_eth %p", __func__, val);
1448 #endif
1449 	XFREE(MTYPE_RFAPI_MONITOR_ETH, val);
1450 
1451 	--rfd->monitor_count;
1452 	--bgp->rfapi->monitor_count;
1453 }
1454 
1455 
rfapiMonitorCallbacksOff(struct bgp * bgp)1456 void rfapiMonitorCallbacksOff(struct bgp *bgp)
1457 {
1458 	struct rfapi_import_table *it;
1459 	afi_t afi;
1460 	struct agg_table *rt;
1461 	struct agg_node *rn;
1462 	void *cursor;
1463 	int rc;
1464 	struct rfapi *h = bgp->rfapi;
1465 
1466 	if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE) {
1467 		/*
1468 		 * Already off.
1469 		 */
1470 		return;
1471 	}
1472 	bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_CALLBACK_DISABLE;
1473 
1474 #if DEBUG_L2_EXTRA
1475 	vnc_zlog_debug_verbose("%s: turned off callbacks", __func__);
1476 #endif
1477 
1478 	if (h == NULL)
1479 		return;
1480 	/*
1481 	 * detach monitors from import VPN tables. The monitors
1482 	 * will still be linked in per-nve monitor lists.
1483 	 */
1484 	for (it = h->imports; it; it = it->next) {
1485 		for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
1486 
1487 			struct rfapi_monitor_vpn *m;
1488 			struct rfapi_monitor_vpn *next;
1489 
1490 			rt = it->imported_vpn[afi];
1491 
1492 			for (rn = agg_route_top(rt); rn;
1493 			     rn = agg_route_next(rn)) {
1494 				m = RFAPI_MONITOR_VPN(rn);
1495 				if (RFAPI_MONITOR_VPN(rn))
1496 					RFAPI_MONITOR_VPN_W_ALLOC(rn) = NULL;
1497 				for (; m; m = next) {
1498 					next = m->next;
1499 					m->next =
1500 						NULL; /* gratuitous safeness */
1501 					m->node = NULL;
1502 					agg_unlock_node(rn); /* uncount */
1503 				}
1504 			}
1505 
1506 			for (m = it->vpn0_queries[afi]; m; m = next) {
1507 				next = m->next;
1508 				m->next = NULL; /* gratuitous safeness */
1509 				m->node = NULL;
1510 			}
1511 			it->vpn0_queries[afi] = NULL; /* detach first monitor */
1512 		}
1513 	}
1514 
1515 	/*
1516 	 * detach monitors from import Eth tables. The monitors
1517 	 * will still be linked in per-nve monitor lists.
1518 	 */
1519 
1520 	/*
1521 	 * Loop over ethernet import tables
1522 	 */
1523 	for (cursor = NULL,
1524 	    rc = skiplist_next(h->import_mac, NULL, (void **)&it, &cursor);
1525 	     !rc;
1526 	     rc = skiplist_next(h->import_mac, NULL, (void **)&it, &cursor)) {
1527 		struct rfapi_monitor_eth *e;
1528 		struct rfapi_monitor_eth *enext;
1529 
1530 		/*
1531 		 * The actual route table
1532 		 */
1533 		rt = it->imported_vpn[AFI_L2VPN];
1534 
1535 		/*
1536 		 * Find non-0 monitors (i.e., actual addresses, not FTD
1537 		 * monitors)
1538 		 */
1539 		for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1540 			struct skiplist *sl;
1541 
1542 			sl = RFAPI_MONITOR_ETH(rn);
1543 			while (!skiplist_delete_first(sl)) {
1544 				agg_unlock_node(rn); /* uncount monitor */
1545 			}
1546 		}
1547 
1548 		/*
1549 		 * Find 0-monitors (FTD queries)
1550 		 */
1551 		for (e = it->eth0_queries; e; e = enext) {
1552 #if DEBUG_L2_EXTRA
1553 			vnc_zlog_debug_verbose("%s: detaching eth0 mon %p",
1554 					       __func__, e);
1555 #endif
1556 			enext = e->next;
1557 			e->next = NULL; /* gratuitous safeness */
1558 		}
1559 		it->eth0_queries = NULL; /* detach first monitor */
1560 	}
1561 }
1562 
rfapiMonitorCallbacksOn(struct bgp * bgp)1563 void rfapiMonitorCallbacksOn(struct bgp *bgp)
1564 {
1565 	struct listnode *hnode;
1566 	struct rfapi_descriptor *rfd;
1567 
1568 	if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
1569 		/*
1570 		 * Already on. It's important that we don't try to reattach
1571 		 * monitors that are already attached because, in the interest
1572 		 * of performance, there is no checking at the lower level
1573 		 * whether a monitor is already attached. It leads to
1574 		 * corrupted chains (e.g., looped pointers)
1575 		 */
1576 		return;
1577 	}
1578 	bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_CALLBACK_DISABLE;
1579 #if DEBUG_L2_EXTRA
1580 	vnc_zlog_debug_verbose("%s: turned on callbacks", __func__);
1581 #endif
1582 	if (bgp->rfapi == NULL)
1583 		return;
1584 
1585 	/*
1586 	 * reattach monitors
1587 	 */
1588 	for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, hnode, rfd)) {
1589 
1590 		rfapiMonitorAttachImportHd(rfd);
1591 		rfapiMonitorEthAttachImportHd(bgp, rfd);
1592 	}
1593 }
1594