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