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