]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
d62a17ae | 2 | /* |
65efcfce LB |
3 | * |
4 | * Copyright 2009-2016, LabN Consulting, L.L.C. | |
5 | * | |
65efcfce LB |
6 | */ |
7 | ||
8 | /* | |
9 | * File: rfapi_rib.c | |
10 | * Purpose: maintain per-nve ribs and generate change lists | |
11 | */ | |
12 | ||
f8b6f499 LB |
13 | #include "lib/zebra.h" |
14 | #include "lib/prefix.h" | |
fe08ba7e | 15 | #include "lib/agg_table.h" |
f8b6f499 LB |
16 | #include "lib/vty.h" |
17 | #include "lib/memory.h" | |
18 | #include "lib/log.h" | |
19 | #include "lib/skiplist.h" | |
20 | #include "lib/workqueue.h" | |
65efcfce | 21 | |
f8b6f499 LB |
22 | #include "bgpd/bgpd.h" |
23 | #include "bgpd/bgp_route.h" | |
24 | #include "bgpd/bgp_ecommunity.h" | |
25 | #include "bgpd/bgp_mplsvpn.h" | |
26 | #include "bgpd/bgp_vnc_types.h" | |
65efcfce | 27 | |
f8b6f499 LB |
28 | #include "bgpd/rfapi/rfapi.h" |
29 | #include "bgpd/rfapi/bgp_rfapi_cfg.h" | |
30 | #include "bgpd/rfapi/rfapi_import.h" | |
31 | #include "bgpd/rfapi/rfapi_private.h" | |
32 | #include "bgpd/rfapi/rfapi_vty.h" | |
33 | #include "bgpd/rfapi/vnc_import_bgp.h" | |
34 | #include "bgpd/rfapi/rfapi_rib.h" | |
35 | #include "bgpd/rfapi/rfapi_monitor.h" | |
36 | #include "bgpd/rfapi/rfapi_encap_tlv.h" | |
a3b55c25 | 37 | #include "bgpd/rfapi/vnc_debug.h" |
65efcfce LB |
38 | |
39 | #define DEBUG_PROCESS_PENDING_NODE 0 | |
40 | #define DEBUG_PENDING_DELETE_ROUTE 0 | |
41 | #define DEBUG_NHL 0 | |
42 | #define DEBUG_RIB_SL_RD 0 | |
43 | ||
44 | /* forward decl */ | |
45 | #if DEBUG_NHL | |
d62a17ae | 46 | static void rfapiRibShowRibSl(void *stream, struct prefix *pfx, |
47 | struct skiplist *sl); | |
65efcfce LB |
48 | #endif |
49 | ||
50 | /* | |
51 | * RIB | |
52 | * --- | |
53 | * Model of the set of routes currently in the NVE's RIB. | |
54 | * | |
55 | * node->info ptr to "struct skiplist". | |
56 | * MUST be NULL if there are no routes. | |
57 | * key = ptr to struct prefix {vn} | |
58 | * val = ptr to struct rfapi_info | |
59 | * skiplist.del = NULL | |
60 | * skiplist.cmp = vnc_prefix_cmp | |
61 | * | |
62 | * node->aggregate ptr to "struct skiplist". | |
63 | * key = ptr to struct prefix {vn} | |
64 | * val = ptr to struct rfapi_info | |
65 | * skiplist.del = rfapi_info_free | |
66 | * skiplist.cmp = vnc_prefix_cmp | |
67 | * | |
68 | * This skiplist at "aggregate" | |
69 | * contains the routes recently | |
70 | * deleted | |
71 | * | |
72 | * | |
73 | * Pending RIB | |
74 | * ----------- | |
75 | * Sparse list of prefixes that need to be updated. Each node | |
76 | * will have the complete set of routes for the prefix. | |
77 | * | |
78 | * node->info ptr to "struct list" (lib/linklist.h) | |
79 | * "Cost List" | |
80 | * List of routes sorted lowest cost first. | |
81 | * This list is how the new complete set | |
82 | * of routes should look. | |
83 | * Set if there are updates to the prefix; | |
84 | * MUST be NULL if there are no updates. | |
85 | * | |
86 | * .data = ptr to struct rfapi_info | |
87 | * list.cmp = NULL (sorted manually) | |
88 | * list.del = rfapi_info_free | |
89 | * | |
90 | * Special case: if node->info is 1, it means | |
91 | * "delete all routes at this prefix". | |
92 | * | |
93 | * node->aggregate ptr to struct skiplist | |
94 | * key = ptr to struct prefix {vn} (part of ri) | |
95 | * val = struct rfapi_info | |
96 | * skiplist.cmp = vnc_prefix_cmp | |
97 | * skiplist.del = NULL | |
98 | * | |
99 | * ptlist is rewritten anew each time | |
100 | * rfapiRibUpdatePendingNode() is called | |
101 | * | |
102 | * THE ptlist VALUES ARE REFERENCES TO THE | |
103 | * rfapi_info STRUCTS IN THE node->info LIST. | |
104 | */ | |
105 | ||
106 | /* | |
107 | * iterate over RIB to count responses, compare with running counters | |
108 | */ | |
d62a17ae | 109 | void rfapiRibCheckCounts( |
110 | int checkstats, /* validate rfd & global counts */ | |
111 | unsigned int offset) /* number of ri's held separately */ | |
65efcfce | 112 | { |
d62a17ae | 113 | struct rfapi_descriptor *rfd; |
114 | struct listnode *node; | |
115 | ||
116 | struct bgp *bgp = bgp_get_default(); | |
117 | ||
118 | uint32_t t_pfx_active = 0; | |
119 | uint32_t t_pfx_deleted = 0; | |
120 | ||
121 | uint32_t t_ri_active = 0; | |
122 | uint32_t t_ri_deleted = 0; | |
123 | uint32_t t_ri_pend = 0; | |
124 | ||
125 | unsigned int alloc_count; | |
126 | ||
127 | /* | |
128 | * loop over NVEs | |
129 | */ | |
130 | for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, node, rfd)) { | |
131 | ||
132 | afi_t afi; | |
133 | uint32_t pfx_active = 0; | |
134 | uint32_t pfx_deleted = 0; | |
135 | ||
136 | for (afi = AFI_IP; afi < AFI_MAX; ++afi) { | |
137 | ||
fe08ba7e | 138 | struct agg_node *rn; |
d62a17ae | 139 | |
fe08ba7e DS |
140 | for (rn = agg_route_top(rfd->rib[afi]); rn; |
141 | rn = agg_route_next(rn)) { | |
d62a17ae | 142 | |
143 | struct skiplist *sl = rn->info; | |
144 | struct skiplist *dsl = rn->aggregate; | |
145 | uint32_t ri_active = 0; | |
146 | uint32_t ri_deleted = 0; | |
147 | ||
148 | if (sl) { | |
149 | ri_active = skiplist_count(sl); | |
150 | assert(ri_active); | |
151 | t_ri_active += ri_active; | |
152 | ++pfx_active; | |
153 | ++t_pfx_active; | |
154 | } | |
155 | ||
156 | if (dsl) { | |
157 | ri_deleted = skiplist_count(dsl); | |
158 | t_ri_deleted += ri_deleted; | |
159 | ++pfx_deleted; | |
160 | ++t_pfx_deleted; | |
161 | } | |
162 | } | |
fe08ba7e DS |
163 | for (rn = agg_route_top(rfd->rib_pending[afi]); rn; |
164 | rn = agg_route_next(rn)) { | |
d62a17ae | 165 | |
166 | struct list *l = rn->info; /* sorted by cost */ | |
167 | struct skiplist *sl = rn->aggregate; | |
168 | uint32_t ri_pend_cost = 0; | |
169 | uint32_t ri_pend_uniq = 0; | |
170 | ||
171 | if (sl) { | |
172 | ri_pend_uniq = skiplist_count(sl); | |
173 | } | |
174 | ||
175 | if (l && (l != (void *)1)) { | |
176 | ri_pend_cost = l->count; | |
177 | t_ri_pend += l->count; | |
178 | } | |
179 | ||
180 | assert(ri_pend_uniq == ri_pend_cost); | |
181 | } | |
182 | } | |
183 | ||
184 | if (checkstats) { | |
185 | if (pfx_active != rfd->rib_prefix_count) { | |
186 | vnc_zlog_debug_verbose( | |
187 | "%s: rfd %p actual pfx count %u != running %u", | |
188 | __func__, rfd, pfx_active, | |
189 | rfd->rib_prefix_count); | |
190 | assert(0); | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
8cea9547 | 195 | if (checkstats && bgp->rfapi) { |
d62a17ae | 196 | if (t_pfx_active != bgp->rfapi->rib_prefix_count_total) { |
197 | vnc_zlog_debug_verbose( | |
198 | "%s: actual total pfx count %u != running %u", | |
199 | __func__, t_pfx_active, | |
200 | bgp->rfapi->rib_prefix_count_total); | |
201 | assert(0); | |
202 | } | |
203 | } | |
204 | ||
205 | /* | |
206 | * Check against memory allocation count | |
207 | */ | |
208 | alloc_count = mtype_stats_alloc(MTYPE_RFAPI_INFO); | |
209 | assert(t_ri_active + t_ri_deleted + t_ri_pend + offset == alloc_count); | |
65efcfce LB |
210 | } |
211 | ||
4d762f26 | 212 | static struct rfapi_info *rfapi_info_new(void) |
65efcfce | 213 | { |
d62a17ae | 214 | return XCALLOC(MTYPE_RFAPI_INFO, sizeof(struct rfapi_info)); |
65efcfce LB |
215 | } |
216 | ||
d62a17ae | 217 | void rfapiFreeRfapiUnOptionChain(struct rfapi_un_option *p) |
65efcfce | 218 | { |
d62a17ae | 219 | while (p) { |
220 | struct rfapi_un_option *next; | |
221 | ||
222 | next = p->next; | |
223 | XFREE(MTYPE_RFAPI_UN_OPTION, p); | |
224 | p = next; | |
225 | } | |
65efcfce LB |
226 | } |
227 | ||
d62a17ae | 228 | void rfapiFreeRfapiVnOptionChain(struct rfapi_vn_option *p) |
65efcfce | 229 | { |
d62a17ae | 230 | while (p) { |
231 | struct rfapi_vn_option *next; | |
232 | ||
233 | next = p->next; | |
234 | XFREE(MTYPE_RFAPI_VN_OPTION, p); | |
235 | p = next; | |
236 | } | |
65efcfce LB |
237 | } |
238 | ||
239 | ||
d62a17ae | 240 | static void rfapi_info_free(struct rfapi_info *goner) |
65efcfce | 241 | { |
d62a17ae | 242 | if (goner) { |
243 | if (goner->tea_options) { | |
244 | rfapiFreeBgpTeaOptionChain(goner->tea_options); | |
245 | goner->tea_options = NULL; | |
246 | } | |
247 | if (goner->un_options) { | |
248 | rfapiFreeRfapiUnOptionChain(goner->un_options); | |
249 | goner->un_options = NULL; | |
250 | } | |
251 | if (goner->vn_options) { | |
252 | rfapiFreeRfapiVnOptionChain(goner->vn_options); | |
253 | goner->vn_options = NULL; | |
254 | } | |
255 | if (goner->timer) { | |
256 | struct rfapi_rib_tcb *tcb; | |
257 | ||
c3aaa89a DS |
258 | tcb = THREAD_ARG(goner->timer); |
259 | THREAD_OFF(goner->timer); | |
d62a17ae | 260 | XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb); |
d62a17ae | 261 | } |
262 | XFREE(MTYPE_RFAPI_INFO, goner); | |
263 | } | |
65efcfce LB |
264 | } |
265 | ||
266 | /* | |
267 | * Timer control block for recently-deleted and expired routes | |
268 | */ | |
d62a17ae | 269 | struct rfapi_rib_tcb { |
270 | struct rfapi_descriptor *rfd; | |
271 | struct skiplist *sl; | |
272 | struct rfapi_info *ri; | |
fe08ba7e | 273 | struct agg_node *rn; |
d62a17ae | 274 | int flags; |
65efcfce LB |
275 | #define RFAPI_RIB_TCB_FLAG_DELETED 0x00000001 |
276 | }; | |
277 | ||
278 | /* | |
279 | * remove route from rib | |
280 | */ | |
cc9f21da | 281 | static void rfapiRibExpireTimer(struct thread *t) |
65efcfce | 282 | { |
c3aaa89a | 283 | struct rfapi_rib_tcb *tcb = THREAD_ARG(t); |
d62a17ae | 284 | |
285 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
286 | ||
287 | /* | |
288 | * Forget reference to thread. Otherwise rfapi_info_free() will | |
289 | * attempt to free thread pointer as an option chain | |
290 | */ | |
291 | tcb->ri->timer = NULL; | |
292 | ||
293 | /* "deleted" skiplist frees ri, "active" doesn't */ | |
294 | assert(!skiplist_delete(tcb->sl, &tcb->ri->rk, NULL)); | |
295 | if (!tcb->sl->del) { | |
296 | /* | |
297 | * XXX in this case, skiplist has no delete function: we must | |
298 | * therefore delete rfapi_info explicitly. | |
299 | */ | |
300 | rfapi_info_free(tcb->ri); | |
301 | } | |
302 | ||
303 | if (skiplist_empty(tcb->sl)) { | |
304 | if (CHECK_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED)) | |
305 | tcb->rn->aggregate = NULL; | |
306 | else { | |
307 | struct bgp *bgp = bgp_get_default(); | |
308 | tcb->rn->info = NULL; | |
309 | RFAPI_RIB_PREFIX_COUNT_DECR(tcb->rfd, bgp->rfapi); | |
310 | } | |
311 | skiplist_free(tcb->sl); | |
fe08ba7e | 312 | agg_unlock_node(tcb->rn); |
d62a17ae | 313 | } |
314 | ||
315 | XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb); | |
316 | ||
317 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
65efcfce LB |
318 | } |
319 | ||
fe08ba7e DS |
320 | static void rfapiRibStartTimer(struct rfapi_descriptor *rfd, |
321 | struct rfapi_info *ri, | |
322 | struct agg_node *rn, /* route node attached to */ | |
323 | int deleted) | |
65efcfce | 324 | { |
d62a17ae | 325 | struct rfapi_rib_tcb *tcb = NULL; |
d62a17ae | 326 | |
b3d6bc6e | 327 | if (ri->timer) { |
c3aaa89a DS |
328 | tcb = THREAD_ARG(ri->timer); |
329 | THREAD_OFF(ri->timer); | |
d62a17ae | 330 | } else { |
331 | tcb = XCALLOC(MTYPE_RFAPI_RECENT_DELETE, | |
332 | sizeof(struct rfapi_rib_tcb)); | |
333 | } | |
334 | tcb->rfd = rfd; | |
335 | tcb->ri = ri; | |
336 | tcb->rn = rn; | |
337 | if (deleted) { | |
338 | tcb->sl = (struct skiplist *)rn->aggregate; | |
339 | SET_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED); | |
340 | } else { | |
341 | tcb->sl = (struct skiplist *)rn->info; | |
342 | UNSET_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED); | |
343 | } | |
344 | ||
26a3ffd6 DS |
345 | vnc_zlog_debug_verbose("%s: rfd %p pfx %pRN life %u", __func__, rfd, rn, |
346 | ri->lifetime); | |
04fd828f | 347 | |
d62a17ae | 348 | thread_add_timer(bm->master, rfapiRibExpireTimer, tcb, ri->lifetime, |
349 | &ri->timer); | |
65efcfce LB |
350 | } |
351 | ||
d62a17ae | 352 | extern void rfapi_rib_key_init(struct prefix *prefix, /* may be NULL */ |
353 | struct prefix_rd *rd, /* may be NULL */ | |
354 | struct prefix *aux, /* may be NULL */ | |
355 | struct rfapi_rib_key *rk) | |
356 | ||
cedb5a71 | 357 | { |
d62a17ae | 358 | memset((void *)rk, 0, sizeof(struct rfapi_rib_key)); |
359 | if (prefix) | |
360 | rk->vn = *prefix; | |
361 | if (rd) | |
362 | rk->rd = *rd; | |
363 | if (aux) | |
364 | rk->aux_prefix = *aux; | |
cedb5a71 LB |
365 | } |
366 | ||
65efcfce LB |
367 | /* |
368 | * Compares two <struct rfapi_rib_key>s | |
369 | */ | |
1a4189d4 | 370 | int rfapi_rib_key_cmp(const void *k1, const void *k2) |
65efcfce | 371 | { |
1a4189d4 DS |
372 | const struct rfapi_rib_key *a = (struct rfapi_rib_key *)k1; |
373 | const struct rfapi_rib_key *b = (struct rfapi_rib_key *)k2; | |
d62a17ae | 374 | int ret; |
65efcfce | 375 | |
d62a17ae | 376 | if (!a || !b) |
377 | return (a - b); | |
65efcfce | 378 | |
d62a17ae | 379 | ret = vnc_prefix_cmp(&a->vn, &b->vn); |
380 | if (ret) | |
381 | return ret; | |
65efcfce | 382 | |
d62a17ae | 383 | ret = vnc_prefix_cmp(&a->rd, &b->rd); |
384 | if (ret) | |
385 | return ret; | |
65efcfce | 386 | |
d62a17ae | 387 | ret = vnc_prefix_cmp(&a->aux_prefix, &b->aux_prefix); |
65efcfce | 388 | |
d62a17ae | 389 | return ret; |
65efcfce LB |
390 | } |
391 | ||
392 | ||
393 | /* | |
394 | * Note: this function will claim that two option chains are | |
395 | * different unless their option items are in identical order. | |
396 | * The consequence is that RFP updated responses can be sent | |
397 | * unnecessarily, or that they might contain nexthop items | |
398 | * that are not strictly needed. | |
399 | * | |
400 | * This function could be modified to compare option chains more | |
401 | * thoroughly, but it's not clear that the extra compuation would | |
402 | * be worth it. | |
403 | */ | |
d62a17ae | 404 | static int bgp_tea_options_cmp(struct bgp_tea_options *a, |
405 | struct bgp_tea_options *b) | |
65efcfce | 406 | { |
d62a17ae | 407 | int rc; |
408 | ||
409 | if (!a || !b) { | |
410 | return (a - b); | |
411 | } | |
65efcfce | 412 | |
d62a17ae | 413 | if (a->type != b->type) |
414 | return (a->type - b->type); | |
415 | if (a->length != b->length) | |
416 | return (a->length = b->length); | |
417 | if ((rc = memcmp(a->value, b->value, a->length))) | |
418 | return rc; | |
419 | if (!a->next != !b->next) { /* logical xor */ | |
420 | return (a->next - b->next); | |
421 | } | |
422 | if (a->next) | |
423 | return bgp_tea_options_cmp(a->next, b->next); | |
424 | return 0; | |
65efcfce LB |
425 | } |
426 | ||
d62a17ae | 427 | static int rfapi_info_cmp(struct rfapi_info *a, struct rfapi_info *b) |
65efcfce | 428 | { |
d62a17ae | 429 | int rc; |
65efcfce | 430 | |
d62a17ae | 431 | if (!a || !b) |
432 | return (a - b); | |
65efcfce | 433 | |
d62a17ae | 434 | if ((rc = rfapi_rib_key_cmp(&a->rk, &b->rk))) |
435 | return rc; | |
65efcfce | 436 | |
d62a17ae | 437 | if ((rc = vnc_prefix_cmp(&a->un, &b->un))) |
438 | return rc; | |
65efcfce | 439 | |
d62a17ae | 440 | if (a->cost != b->cost) |
441 | return (a->cost - b->cost); | |
65efcfce | 442 | |
d62a17ae | 443 | if (a->lifetime != b->lifetime) |
444 | return (a->lifetime - b->lifetime); | |
65efcfce | 445 | |
d62a17ae | 446 | if ((rc = bgp_tea_options_cmp(a->tea_options, b->tea_options))) |
447 | return rc; | |
65efcfce | 448 | |
d62a17ae | 449 | return 0; |
65efcfce LB |
450 | } |
451 | ||
d62a17ae | 452 | void rfapiRibClear(struct rfapi_descriptor *rfd) |
65efcfce | 453 | { |
d62a17ae | 454 | struct bgp *bgp; |
455 | afi_t afi; | |
65efcfce | 456 | |
d62a17ae | 457 | if (rfd->bgp) |
458 | bgp = rfd->bgp; | |
459 | else | |
460 | bgp = bgp_get_default(); | |
1e20238a | 461 | #ifdef DEBUG_L2_EXTRA |
d62a17ae | 462 | vnc_zlog_debug_verbose("%s: rfd=%p", __func__, rfd); |
65efcfce LB |
463 | #endif |
464 | ||
d62a17ae | 465 | for (afi = AFI_IP; afi < AFI_MAX; ++afi) { |
fe08ba7e DS |
466 | struct agg_node *pn; |
467 | struct agg_node *rn; | |
d62a17ae | 468 | |
469 | if (rfd->rib_pending[afi]) { | |
fe08ba7e DS |
470 | for (pn = agg_route_top(rfd->rib_pending[afi]); pn; |
471 | pn = agg_route_next(pn)) { | |
d62a17ae | 472 | if (pn->aggregate) { |
473 | /* | |
474 | * free references into the rfapi_info | |
475 | * structures before | |
476 | * freeing the structures themselves | |
477 | */ | |
478 | skiplist_free( | |
479 | (struct skiplist | |
480 | *)(pn->aggregate)); | |
481 | pn->aggregate = NULL; | |
fe08ba7e | 482 | agg_unlock_node( |
d62a17ae | 483 | pn); /* skiplist deleted */ |
484 | } | |
485 | /* | |
486 | * free the rfapi_info structures | |
487 | */ | |
488 | if (pn->info) { | |
489 | if (pn->info != (void *)1) { | |
6a154c88 | 490 | list_delete( |
996c9314 LB |
491 | (struct list * |
492 | *)(&pn->info)); | |
d62a17ae | 493 | } |
494 | pn->info = NULL; | |
affe9e99 | 495 | /* linklist or 1 deleted */ |
fe08ba7e | 496 | agg_unlock_node(pn); |
d62a17ae | 497 | } |
498 | } | |
499 | } | |
500 | if (rfd->rib[afi]) { | |
fe08ba7e DS |
501 | for (rn = agg_route_top(rfd->rib[afi]); rn; |
502 | rn = agg_route_next(rn)) { | |
d62a17ae | 503 | if (rn->info) { |
504 | ||
505 | struct rfapi_info *ri; | |
506 | ||
9d303b37 DL |
507 | while (0 == skiplist_first( |
508 | (struct skiplist *) | |
509 | rn->info, | |
510 | NULL, | |
511 | (void **)&ri)) { | |
d62a17ae | 512 | |
513 | rfapi_info_free(ri); | |
514 | skiplist_delete_first( | |
515 | (struct skiplist *) | |
516 | rn->info); | |
517 | } | |
518 | skiplist_free( | |
519 | (struct skiplist *)rn->info); | |
520 | rn->info = NULL; | |
fe08ba7e | 521 | agg_unlock_node(rn); |
d62a17ae | 522 | RFAPI_RIB_PREFIX_COUNT_DECR(rfd, |
523 | bgp->rfapi); | |
524 | } | |
525 | if (rn->aggregate) { | |
526 | ||
527 | struct rfapi_info *ri_del; | |
528 | ||
529 | /* delete skiplist & contents */ | |
530 | while (!skiplist_first( | |
531 | (struct skiplist | |
532 | *)(rn->aggregate), | |
533 | NULL, (void **)&ri_del)) { | |
534 | ||
535 | /* sl->del takes care of ri_del | |
536 | */ | |
537 | skiplist_delete_first(( | |
538 | struct skiplist | |
539 | *)(rn->aggregate)); | |
540 | } | |
541 | skiplist_free( | |
542 | (struct skiplist | |
543 | *)(rn->aggregate)); | |
544 | ||
545 | rn->aggregate = NULL; | |
fe08ba7e | 546 | agg_unlock_node(rn); |
d62a17ae | 547 | } |
548 | } | |
549 | } | |
550 | } | |
e208c8f9 DS |
551 | if (rfd->updated_responses_queue) |
552 | work_queue_free_and_null(&rfd->updated_responses_queue); | |
65efcfce LB |
553 | } |
554 | ||
555 | /* | |
556 | * Release all dynamically-allocated memory that is part of an HD's RIB | |
557 | */ | |
d62a17ae | 558 | void rfapiRibFree(struct rfapi_descriptor *rfd) |
65efcfce | 559 | { |
d62a17ae | 560 | afi_t afi; |
65efcfce LB |
561 | |
562 | ||
d62a17ae | 563 | /* |
564 | * NB rfd is typically detached from master list, so is not included | |
565 | * in the count performed by RFAPI_RIB_CHECK_COUNTS | |
566 | */ | |
65efcfce | 567 | |
d62a17ae | 568 | /* |
569 | * Free routes attached to radix trees | |
570 | */ | |
571 | rfapiRibClear(rfd); | |
65efcfce | 572 | |
d62a17ae | 573 | /* Now the uncounted rfapi_info's are freed, so the check should succeed |
574 | */ | |
575 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
65efcfce | 576 | |
d62a17ae | 577 | /* |
578 | * Free radix trees | |
579 | */ | |
580 | for (afi = AFI_IP; afi < AFI_MAX; ++afi) { | |
fe08ba7e DS |
581 | if (rfd->rib_pending[afi]) |
582 | agg_table_finish(rfd->rib_pending[afi]); | |
d62a17ae | 583 | rfd->rib_pending[afi] = NULL; |
65efcfce | 584 | |
fe08ba7e DS |
585 | if (rfd->rib[afi]) |
586 | agg_table_finish(rfd->rib[afi]); | |
d62a17ae | 587 | rfd->rib[afi] = NULL; |
65efcfce | 588 | |
fe08ba7e | 589 | /* NB agg_table_finish frees only prefix nodes, not chained |
d62a17ae | 590 | * info */ |
fe08ba7e DS |
591 | if (rfd->rsp_times[afi]) |
592 | agg_table_finish(rfd->rsp_times[afi]); | |
d62a17ae | 593 | rfd->rib[afi] = NULL; |
594 | } | |
65efcfce LB |
595 | } |
596 | ||
597 | /* | |
4b7e6066 | 598 | * Copies struct bgp_path_info to struct rfapi_info, except for rk fields and un |
65efcfce | 599 | */ |
40381db7 | 600 | static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, |
d62a17ae | 601 | uint32_t lifetime) |
65efcfce | 602 | { |
d62a17ae | 603 | struct bgp_attr_encap_subtlv *pEncap; |
604 | ||
40381db7 | 605 | ri->cost = rfapiRfpCost(bpi->attr); |
d62a17ae | 606 | ri->lifetime = lifetime; |
607 | ||
608 | /* This loop based on rfapiRouteInfo2NextHopEntry() */ | |
91ebf12c DS |
609 | for (pEncap = bgp_attr_get_vnc_subtlvs(bpi->attr); pEncap; |
610 | pEncap = pEncap->next) { | |
d62a17ae | 611 | struct bgp_tea_options *hop; |
612 | ||
613 | switch (pEncap->type) { | |
614 | case BGP_VNC_SUBTLV_TYPE_LIFETIME: | |
615 | /* use configured lifetime, not attr lifetime */ | |
616 | break; | |
617 | ||
618 | case BGP_VNC_SUBTLV_TYPE_RFPOPTION: | |
619 | hop = XCALLOC(MTYPE_BGP_TEA_OPTIONS, | |
620 | sizeof(struct bgp_tea_options)); | |
621 | assert(hop); | |
622 | hop->type = pEncap->value[0]; | |
623 | hop->length = pEncap->value[1]; | |
624 | hop->value = XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE, | |
625 | pEncap->length - 2); | |
626 | assert(hop->value); | |
627 | memcpy(hop->value, pEncap->value + 2, | |
628 | pEncap->length - 2); | |
629 | if (hop->length > pEncap->length - 2) { | |
630 | zlog_warn( | |
3efd0893 | 631 | "%s: VNC subtlv length mismatch: RFP option says %d, attr says %d (shrinking)", |
d62a17ae | 632 | __func__, hop->length, |
633 | pEncap->length - 2); | |
634 | hop->length = pEncap->length - 2; | |
635 | } | |
636 | hop->next = ri->tea_options; | |
637 | ri->tea_options = hop; | |
638 | break; | |
639 | ||
640 | default: | |
641 | break; | |
642 | } | |
643 | } | |
644 | ||
645 | rfapi_un_options_free(ri->un_options); /* maybe free old version */ | |
40381db7 | 646 | ri->un_options = rfapi_encap_tlv_to_un_option(bpi->attr); |
d62a17ae | 647 | |
648 | /* | |
649 | * VN options | |
650 | */ | |
40381db7 DS |
651 | if (bpi->extra |
652 | && decode_rd_type(bpi->extra->vnc.import.rd.val) | |
d62a17ae | 653 | == RD_TYPE_VNC_ETH) { |
654 | /* ethernet route */ | |
655 | ||
656 | struct rfapi_vn_option *vo; | |
657 | ||
658 | vo = XCALLOC(MTYPE_RFAPI_VN_OPTION, | |
659 | sizeof(struct rfapi_vn_option)); | |
660 | assert(vo); | |
661 | ||
662 | vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR; | |
663 | ||
40381db7 | 664 | /* copy from RD already stored in bpi, so we don't need it_node |
d62a17ae | 665 | */ |
40381db7 | 666 | memcpy(&vo->v.l2addr.macaddr, bpi->extra->vnc.import.rd.val + 2, |
28328ea9 | 667 | ETH_ALEN); |
d62a17ae | 668 | |
b53e67a3 | 669 | (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr), |
8cea9547 | 670 | &vo->v.l2addr.logical_net_id); |
b53e67a3 DA |
671 | (void)rfapiEcommunityGetEthernetTag( |
672 | bgp_attr_get_ecommunity(bpi->attr), | |
673 | &vo->v.l2addr.tag_id); | |
d62a17ae | 674 | |
675 | /* local_nve_id comes from RD */ | |
40381db7 | 676 | vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; |
d62a17ae | 677 | |
678 | /* label comes from MP_REACH_NLRI label */ | |
40381db7 | 679 | vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); |
d62a17ae | 680 | |
681 | rfapi_vn_options_free( | |
682 | ri->vn_options); /* maybe free old version */ | |
683 | ri->vn_options = vo; | |
684 | } | |
685 | ||
686 | /* | |
687 | * If there is an auxiliary IP address (L2 can have it), copy it | |
688 | */ | |
40381db7 DS |
689 | if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { |
690 | ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; | |
d62a17ae | 691 | } |
65efcfce LB |
692 | } |
693 | ||
694 | /* | |
695 | * rfapiRibPreloadBi | |
696 | * | |
697 | * Install route into NVE RIB model so as to be consistent with | |
698 | * caller's response to rfapi_query(). | |
699 | * | |
700 | * Also: return indication to caller whether this specific route | |
701 | * should be included in the response to the NVE according to | |
702 | * the following tests: | |
703 | * | |
704 | * 1. If there were prior duplicates of this route in this same | |
705 | * query response, don't include the route. | |
706 | * | |
707 | * RETURN VALUE: | |
708 | * | |
709 | * 0 OK to include route in response | |
710 | * !0 do not include route in response | |
711 | */ | |
d62a17ae | 712 | int rfapiRibPreloadBi( |
fe08ba7e | 713 | struct agg_node *rfd_rib_node, /* NULL = don't preload or filter */ |
d62a17ae | 714 | struct prefix *pfx_vn, struct prefix *pfx_un, uint32_t lifetime, |
40381db7 | 715 | struct bgp_path_info *bpi) |
65efcfce | 716 | { |
d62a17ae | 717 | struct rfapi_descriptor *rfd; |
718 | struct skiplist *slRibPt = NULL; | |
719 | struct rfapi_info *ori = NULL; | |
720 | struct rfapi_rib_key rk; | |
fe08ba7e | 721 | struct agg_node *trn; |
d62a17ae | 722 | afi_t afi; |
26a3ffd6 | 723 | const struct prefix *p = agg_node_get_prefix(rfd_rib_node); |
d62a17ae | 724 | |
725 | if (!rfd_rib_node) | |
726 | return 0; | |
727 | ||
26a3ffd6 | 728 | afi = family2afi(p->family); |
d62a17ae | 729 | |
fe08ba7e | 730 | rfd = agg_get_table_info(agg_get_table(rfd_rib_node)); |
d62a17ae | 731 | |
732 | memset((void *)&rk, 0, sizeof(rk)); | |
733 | rk.vn = *pfx_vn; | |
40381db7 | 734 | rk.rd = bpi->extra->vnc.import.rd; |
d62a17ae | 735 | |
736 | /* | |
737 | * If there is an auxiliary IP address (L2 can have it), copy it | |
738 | */ | |
40381db7 DS |
739 | if (bpi->extra->vnc.import.aux_prefix.family) { |
740 | rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; | |
d62a17ae | 741 | } |
742 | ||
743 | /* | |
744 | * is this route already in NVE's RIB? | |
745 | */ | |
746 | slRibPt = (struct skiplist *)rfd_rib_node->info; | |
747 | ||
748 | if (slRibPt && !skiplist_search(slRibPt, &rk, (void **)&ori)) { | |
749 | ||
750 | if ((ori->rsp_counter == rfd->rsp_counter) | |
751 | && (ori->last_sent_time == rfd->rsp_time)) { | |
752 | return -1; /* duplicate in this response */ | |
753 | } | |
754 | ||
755 | /* found: update contents of existing route in RIB */ | |
756 | ori->un = *pfx_un; | |
40381db7 | 757 | rfapiRibBi2Ri(bpi, ori, lifetime); |
d62a17ae | 758 | } else { |
759 | /* not found: add new route to RIB */ | |
760 | ori = rfapi_info_new(); | |
761 | ori->rk = rk; | |
762 | ori->un = *pfx_un; | |
40381db7 | 763 | rfapiRibBi2Ri(bpi, ori, lifetime); |
d62a17ae | 764 | |
765 | if (!slRibPt) { | |
766 | slRibPt = skiplist_new(0, rfapi_rib_key_cmp, NULL); | |
767 | rfd_rib_node->info = slRibPt; | |
fe08ba7e | 768 | agg_lock_node(rfd_rib_node); |
d62a17ae | 769 | RFAPI_RIB_PREFIX_COUNT_INCR(rfd, rfd->bgp->rfapi); |
770 | } | |
771 | skiplist_insert(slRibPt, &ori->rk, ori); | |
65efcfce LB |
772 | } |
773 | ||
98b7e975 | 774 | ori->last_sent_time = monotime(NULL); |
d62a17ae | 775 | |
776 | /* | |
777 | * poke timer | |
778 | */ | |
779 | RFAPI_RIB_CHECK_COUNTS(0, 0); | |
780 | rfapiRibStartTimer(rfd, ori, rfd_rib_node, 0); | |
781 | RFAPI_RIB_CHECK_COUNTS(0, 0); | |
782 | ||
783 | /* | |
784 | * Update last sent time for prefix | |
785 | */ | |
26a3ffd6 | 786 | trn = agg_node_get(rfd->rsp_times[afi], p); /* locks trn */ |
083ec940 | 787 | trn->info = (void *)(uintptr_t)monotime(NULL); |
c10e14e9 | 788 | if (agg_node_get_lock_count(trn) > 1) |
fe08ba7e | 789 | agg_unlock_node(trn); |
d62a17ae | 790 | |
791 | return 0; | |
65efcfce LB |
792 | } |
793 | ||
794 | /* | |
795 | * Frees rfapi_info items at node | |
796 | * | |
797 | * Adjust 'rib' and 'rib_pending' as follows: | |
798 | * | |
799 | * If rib_pending node->info is 1 (magic value): | |
800 | * callback: NHL = RIB NHL with lifetime = withdraw_lifetime_value | |
801 | * RIB = remove all routes at the node | |
802 | * DONE | |
803 | * | |
804 | * For each item at rib node: | |
805 | * if not present in pending node, move RIB item to "delete list" | |
806 | * | |
807 | * For each item at pending rib node: | |
808 | * if present (same vn/un) in rib node with same lifetime & options, drop | |
809 | * matching item from pending node | |
810 | * | |
811 | * For each remaining item at pending rib node, add or replace item | |
812 | * at rib node. | |
813 | * | |
814 | * Construct NHL as concatenation of pending list + delete list | |
815 | * | |
816 | * Clear pending node | |
817 | */ | |
d62a17ae | 818 | static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd, |
819 | afi_t afi, | |
fe08ba7e | 820 | struct agg_node *pn, /* pending node */ |
d62a17ae | 821 | struct rfapi_next_hop_entry **head, |
822 | struct rfapi_next_hop_entry **tail) | |
65efcfce | 823 | { |
d62a17ae | 824 | struct listnode *node = NULL; |
825 | struct listnode *nnode = NULL; | |
826 | struct rfapi_info *ri = NULL; /* happy valgrind */ | |
827 | struct rfapi_ip_prefix hp = {0}; /* pfx to put in NHE */ | |
fe08ba7e | 828 | struct agg_node *rn = NULL; |
d62a17ae | 829 | struct skiplist *slRibPt = NULL; /* rib list */ |
830 | struct skiplist *slPendPt = NULL; | |
831 | struct list *lPendCost = NULL; | |
832 | struct list *delete_list = NULL; | |
833 | int printedprefix = 0; | |
d62a17ae | 834 | int rib_node_started_nonempty = 0; |
835 | int sendingsomeroutes = 0; | |
26a3ffd6 | 836 | const struct prefix *p; |
65efcfce | 837 | #if DEBUG_PROCESS_PENDING_NODE |
d62a17ae | 838 | unsigned int count_rib_initial = 0; |
839 | unsigned int count_pend_vn_initial = 0; | |
840 | unsigned int count_pend_cost_initial = 0; | |
65efcfce LB |
841 | #endif |
842 | ||
d62a17ae | 843 | assert(pn); |
26a3ffd6 DS |
844 | p = agg_node_get_prefix(pn); |
845 | vnc_zlog_debug_verbose("%s: afi=%d, %pRN pn->info=%p", __func__, afi, | |
846 | pn, pn->info); | |
65efcfce | 847 | |
d62a17ae | 848 | if (AFI_L2VPN != afi) { |
26a3ffd6 | 849 | rfapiQprefix2Rprefix(p, &hp); |
d62a17ae | 850 | } |
65efcfce | 851 | |
d62a17ae | 852 | RFAPI_RIB_CHECK_COUNTS(1, 0); |
65efcfce | 853 | |
d62a17ae | 854 | /* |
855 | * Find corresponding RIB node | |
856 | */ | |
26a3ffd6 | 857 | rn = agg_node_get(rfd->rib[afi], p); /* locks rn */ |
65efcfce | 858 | |
d62a17ae | 859 | /* |
860 | * RIB skiplist has key=rfapi_addr={vn,un}, val = rfapi_info, | |
861 | * skiplist.del = NULL | |
862 | */ | |
863 | slRibPt = (struct skiplist *)rn->info; | |
864 | if (slRibPt) | |
865 | rib_node_started_nonempty = 1; | |
65efcfce | 866 | |
d62a17ae | 867 | slPendPt = (struct skiplist *)(pn->aggregate); |
868 | lPendCost = (struct list *)(pn->info); | |
65efcfce LB |
869 | |
870 | #if DEBUG_PROCESS_PENDING_NODE | |
d62a17ae | 871 | /* debugging */ |
872 | if (slRibPt) | |
873 | count_rib_initial = skiplist_count(slRibPt); | |
65efcfce | 874 | |
d62a17ae | 875 | if (slPendPt) |
876 | count_pend_vn_initial = skiplist_count(slPendPt); | |
65efcfce | 877 | |
d62a17ae | 878 | if (lPendCost && lPendCost != (struct list *)1) |
879 | count_pend_cost_initial = lPendCost->count; | |
65efcfce LB |
880 | #endif |
881 | ||
882 | ||
d62a17ae | 883 | /* |
884 | * Handle special case: delete all routes at prefix | |
885 | */ | |
886 | if (lPendCost == (struct list *)1) { | |
887 | vnc_zlog_debug_verbose("%s: lPendCost=1 => delete all", | |
888 | __func__); | |
889 | if (slRibPt && !skiplist_empty(slRibPt)) { | |
890 | delete_list = list_new(); | |
891 | while (0 | |
892 | == skiplist_first(slRibPt, NULL, (void **)&ri)) { | |
d62a17ae | 893 | listnode_add(delete_list, ri); |
894 | vnc_zlog_debug_verbose( | |
895 | "%s: after listnode_add, delete_list->count=%d", | |
896 | __func__, delete_list->count); | |
897 | rfapiFreeBgpTeaOptionChain(ri->tea_options); | |
898 | ri->tea_options = NULL; | |
899 | ||
900 | if (ri->timer) { | |
901 | struct rfapi_rib_tcb *tcb; | |
902 | ||
c3aaa89a DS |
903 | tcb = THREAD_ARG(ri->timer); |
904 | THREAD_OFF(ri->timer); | |
d62a17ae | 905 | XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb); |
d62a17ae | 906 | } |
907 | ||
d62a17ae | 908 | vnc_zlog_debug_verbose( |
2dbe669b DA |
909 | "%s: put dl pfx=%pRN vn=%pFX un=%pFX cost=%d life=%d vn_options=%p", |
910 | __func__, pn, &ri->rk.vn, &ri->un, | |
911 | ri->cost, ri->lifetime, ri->vn_options); | |
d62a17ae | 912 | |
913 | skiplist_delete_first(slRibPt); | |
914 | } | |
915 | ||
916 | assert(skiplist_empty(slRibPt)); | |
917 | ||
918 | skiplist_free(slRibPt); | |
919 | rn->info = slRibPt = NULL; | |
fe08ba7e | 920 | agg_unlock_node(rn); |
d62a17ae | 921 | |
922 | lPendCost = pn->info = NULL; | |
fe08ba7e | 923 | agg_unlock_node(pn); |
d62a17ae | 924 | |
925 | goto callback; | |
926 | } | |
927 | if (slRibPt) { | |
928 | skiplist_free(slRibPt); | |
929 | rn->info = NULL; | |
fe08ba7e | 930 | agg_unlock_node(rn); |
d62a17ae | 931 | } |
932 | ||
933 | assert(!slPendPt); | |
934 | if (slPendPt) { /* TBD I think we can toss this block */ | |
935 | skiplist_free(slPendPt); | |
936 | pn->aggregate = NULL; | |
fe08ba7e | 937 | agg_unlock_node(pn); |
d62a17ae | 938 | } |
939 | ||
940 | pn->info = NULL; | |
fe08ba7e | 941 | agg_unlock_node(pn); |
d62a17ae | 942 | |
fe08ba7e | 943 | agg_unlock_node(rn); /* agg_node_get() */ |
d62a17ae | 944 | |
945 | if (rib_node_started_nonempty) { | |
946 | RFAPI_RIB_PREFIX_COUNT_DECR(rfd, bgp->rfapi); | |
947 | } | |
948 | ||
949 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
950 | ||
951 | return; | |
952 | } | |
953 | ||
954 | vnc_zlog_debug_verbose("%s: lPendCost->count=%d, slRibPt->count=%d", | |
955 | __func__, | |
956 | (lPendCost ? (int)lPendCost->count : -1), | |
957 | (slRibPt ? (int)slRibPt->count : -1)); | |
958 | ||
959 | /* | |
960 | * Iterate over routes at RIB Node. | |
961 | * If not found at Pending Node, delete from RIB Node and add to | |
962 | * deletelist | |
963 | * If found at Pending Node | |
964 | * If identical rfapi_info, delete from Pending Node | |
965 | */ | |
966 | if (slRibPt) { | |
967 | void *cursor = NULL; | |
968 | struct rfapi_info *ori; | |
969 | ||
970 | /* | |
971 | * Iterate over RIB List | |
972 | * | |
973 | */ | |
974 | while (!skiplist_next(slRibPt, NULL, (void **)&ori, &cursor)) { | |
975 | ||
976 | if (skiplist_search(slPendPt, &ori->rk, (void **)&ri)) { | |
977 | /* | |
978 | * Not in Pending list, so it should be deleted | |
979 | */ | |
980 | if (!delete_list) | |
981 | delete_list = list_new(); | |
982 | listnode_add(delete_list, ori); | |
983 | rfapiFreeBgpTeaOptionChain(ori->tea_options); | |
984 | ori->tea_options = NULL; | |
985 | if (ori->timer) { | |
986 | struct rfapi_rib_tcb *tcb; | |
987 | ||
c3aaa89a DS |
988 | tcb = THREAD_ARG(ori->timer); |
989 | THREAD_OFF(ori->timer); | |
d62a17ae | 990 | XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb); |
d62a17ae | 991 | } |
65efcfce LB |
992 | |
993 | #if DEBUG_PROCESS_PENDING_NODE | |
d62a17ae | 994 | /* deleted from slRibPt below, after we're done |
995 | * iterating */ | |
996 | vnc_zlog_debug_verbose( | |
997 | "%s: slRibPt ri %p not matched in pending list, delete", | |
998 | __func__, ori); | |
65efcfce LB |
999 | #endif |
1000 | ||
d62a17ae | 1001 | } else { |
1002 | /* | |
1003 | * Found in pending list. If same lifetime, | |
1004 | * cost, options, | |
1005 | * then remove from pending list because the | |
1006 | * route | |
1007 | * hasn't changed. | |
1008 | */ | |
1009 | if (!rfapi_info_cmp(ori, ri)) { | |
1010 | skiplist_delete(slPendPt, &ri->rk, | |
1011 | NULL); | |
1012 | assert(lPendCost); | |
1013 | if (lPendCost) { | |
1014 | /* linear walk: might need | |
1015 | * optimization */ | |
1016 | listnode_delete(lPendCost, | |
1017 | ri); /* XXX | |
1018 | doesn't | |
1019 | free | |
1020 | data! | |
1021 | bug? */ | |
1022 | rfapi_info_free( | |
1023 | ri); /* grr... */ | |
1024 | } | |
1025 | } | |
65efcfce | 1026 | #if DEBUG_PROCESS_PENDING_NODE |
d62a17ae | 1027 | vnc_zlog_debug_verbose( |
1028 | "%s: slRibPt ri %p matched in pending list, %s", | |
1029 | __func__, ori, | |
1030 | (same ? "same info" | |
1031 | : "different info")); | |
65efcfce | 1032 | #endif |
d62a17ae | 1033 | } |
1034 | } | |
1035 | /* | |
1036 | * Go back and delete items from RIB | |
1037 | */ | |
1038 | if (delete_list) { | |
1039 | for (ALL_LIST_ELEMENTS_RO(delete_list, node, ri)) { | |
1040 | vnc_zlog_debug_verbose( | |
1041 | "%s: deleting ri %p from slRibPt", | |
1042 | __func__, ri); | |
1043 | assert(!skiplist_delete(slRibPt, &ri->rk, | |
1044 | NULL)); | |
1045 | } | |
1046 | if (skiplist_empty(slRibPt)) { | |
1047 | skiplist_free(slRibPt); | |
1048 | slRibPt = rn->info = NULL; | |
fe08ba7e | 1049 | agg_unlock_node(rn); |
d62a17ae | 1050 | } |
1051 | } | |
1052 | } | |
1053 | ||
1054 | RFAPI_RIB_CHECK_COUNTS(0, (delete_list ? delete_list->count : 0)); | |
1055 | ||
1056 | /* | |
1057 | * Iterate over routes at Pending Node | |
1058 | * | |
1059 | * If {vn} found at RIB Node, update RIB Node route contents to match PN | |
1060 | * If {vn} NOT found at RIB Node, add copy to RIB Node | |
1061 | */ | |
1062 | if (lPendCost) { | |
1063 | for (ALL_LIST_ELEMENTS_RO(lPendCost, node, ri)) { | |
1064 | ||
1065 | struct rfapi_info *ori; | |
1066 | ||
1067 | if (slRibPt | |
1068 | && !skiplist_search(slRibPt, &ri->rk, | |
1069 | (void **)&ori)) { | |
1070 | ||
1071 | /* found: update contents of existing route in | |
1072 | * RIB */ | |
1073 | ori->un = ri->un; | |
1074 | ori->cost = ri->cost; | |
1075 | ori->lifetime = ri->lifetime; | |
1076 | rfapiFreeBgpTeaOptionChain(ori->tea_options); | |
1077 | ori->tea_options = | |
1078 | rfapiOptionsDup(ri->tea_options); | |
98b7e975 | 1079 | ori->last_sent_time = monotime(NULL); |
d62a17ae | 1080 | |
1081 | rfapiFreeRfapiVnOptionChain(ori->vn_options); | |
1082 | ori->vn_options = | |
1083 | rfapiVnOptionsDup(ri->vn_options); | |
1084 | ||
1085 | rfapiFreeRfapiUnOptionChain(ori->un_options); | |
1086 | ori->un_options = | |
1087 | rfapiUnOptionsDup(ri->un_options); | |
1088 | ||
1089 | vnc_zlog_debug_verbose( | |
1090 | "%s: matched lPendCost item %p in slRibPt, rewrote", | |
1091 | __func__, ri); | |
1092 | ||
1093 | } else { | |
d62a17ae | 1094 | /* not found: add new route to RIB */ |
1095 | ori = rfapi_info_new(); | |
1096 | ori->rk = ri->rk; | |
1097 | ori->un = ri->un; | |
1098 | ori->cost = ri->cost; | |
1099 | ori->lifetime = ri->lifetime; | |
1100 | ori->tea_options = | |
1101 | rfapiOptionsDup(ri->tea_options); | |
98b7e975 | 1102 | ori->last_sent_time = monotime(NULL); |
d62a17ae | 1103 | ori->vn_options = |
1104 | rfapiVnOptionsDup(ri->vn_options); | |
1105 | ori->un_options = | |
1106 | rfapiUnOptionsDup(ri->un_options); | |
1107 | ||
1108 | if (!slRibPt) { | |
1109 | slRibPt = skiplist_new( | |
1110 | 0, rfapi_rib_key_cmp, NULL); | |
1111 | rn->info = slRibPt; | |
fe08ba7e | 1112 | agg_lock_node(rn); |
d62a17ae | 1113 | } |
1114 | skiplist_insert(slRibPt, &ori->rk, ori); | |
65efcfce | 1115 | |
d62a17ae | 1116 | vnc_zlog_debug_verbose( |
4a8cd6ad | 1117 | "%s: nomatch lPendCost item %p in slRibPt, added (rd=%pRDP)", |
c4f64ea9 | 1118 | __func__, ri, &ori->rk.rd); |
d62a17ae | 1119 | } |
1120 | ||
1121 | /* | |
1122 | * poke timer | |
1123 | */ | |
1124 | RFAPI_RIB_CHECK_COUNTS( | |
1125 | 0, (delete_list ? delete_list->count : 0)); | |
1126 | rfapiRibStartTimer(rfd, ori, rn, 0); | |
1127 | RFAPI_RIB_CHECK_COUNTS( | |
1128 | 0, (delete_list ? delete_list->count : 0)); | |
1129 | } | |
1130 | } | |
65efcfce LB |
1131 | |
1132 | ||
1133 | callback: | |
d62a17ae | 1134 | /* |
1135 | * Construct NHL as concatenation of pending list + delete list | |
1136 | */ | |
1137 | ||
1138 | ||
1139 | RFAPI_RIB_CHECK_COUNTS(0, (delete_list ? delete_list->count : 0)); | |
1140 | ||
1141 | if (lPendCost) { | |
1142 | ||
1143 | char buf[BUFSIZ]; | |
1144 | char buf2[BUFSIZ]; | |
1145 | ||
1146 | vnc_zlog_debug_verbose("%s: lPendCost->count now %d", __func__, | |
1147 | lPendCost->count); | |
26a3ffd6 | 1148 | vnc_zlog_debug_verbose("%s: For prefix %pRN (a)", __func__, pn); |
d62a17ae | 1149 | printedprefix = 1; |
1150 | ||
1151 | for (ALL_LIST_ELEMENTS(lPendCost, node, nnode, ri)) { | |
1152 | ||
1153 | struct rfapi_next_hop_entry *new; | |
fe08ba7e | 1154 | struct agg_node *trn; |
d62a17ae | 1155 | |
1156 | new = XCALLOC(MTYPE_RFAPI_NEXTHOP, | |
1157 | sizeof(struct rfapi_next_hop_entry)); | |
d62a17ae | 1158 | |
1159 | if (ri->rk.aux_prefix.family) { | |
1160 | rfapiQprefix2Rprefix(&ri->rk.aux_prefix, | |
1161 | &new->prefix); | |
1162 | } else { | |
1163 | new->prefix = hp; | |
1164 | if (AFI_L2VPN == afi) { | |
1165 | /* hp is 0; need to set length to match | |
1166 | * AF of vn */ | |
1167 | new->prefix.length = | |
1168 | (ri->rk.vn.family == AF_INET) | |
1169 | ? 32 | |
1170 | : 128; | |
1171 | } | |
1172 | } | |
1173 | new->prefix.cost = ri->cost; | |
1174 | new->lifetime = ri->lifetime; | |
1175 | rfapiQprefix2Raddr(&ri->rk.vn, &new->vn_address); | |
1176 | rfapiQprefix2Raddr(&ri->un, &new->un_address); | |
1177 | /* free option chain from ri */ | |
1178 | rfapiFreeBgpTeaOptionChain(ri->tea_options); | |
1179 | ||
1180 | ri->tea_options = | |
1181 | NULL; /* option chain was transferred to NHL */ | |
1182 | ||
1183 | new->vn_options = ri->vn_options; | |
1184 | ri->vn_options = | |
1185 | NULL; /* option chain was transferred to NHL */ | |
1186 | ||
1187 | new->un_options = ri->un_options; | |
1188 | ri->un_options = | |
1189 | NULL; /* option chain was transferred to NHL */ | |
1190 | ||
1191 | if (*tail) | |
1192 | (*tail)->next = new; | |
1193 | *tail = new; | |
1194 | if (!*head) { | |
1195 | *head = new; | |
1196 | } | |
1197 | sendingsomeroutes = 1; | |
1198 | ||
1199 | ++rfd->stat_count_nh_reachable; | |
1200 | ++bgp->rfapi->stat.count_updated_response_updates; | |
1201 | ||
1202 | /* | |
1203 | * update this NVE's timestamp for this prefix | |
1204 | */ | |
fe08ba7e | 1205 | trn = agg_node_get(rfd->rsp_times[afi], |
26a3ffd6 | 1206 | p); /* locks trn */ |
083ec940 | 1207 | trn->info = (void *)(uintptr_t)monotime(NULL); |
c10e14e9 | 1208 | if (agg_node_get_lock_count(trn) > 1) |
fe08ba7e | 1209 | agg_unlock_node(trn); |
d62a17ae | 1210 | |
1211 | rfapiRfapiIpAddr2Str(&new->vn_address, buf, BUFSIZ); | |
1212 | rfapiRfapiIpAddr2Str(&new->un_address, buf2, BUFSIZ); | |
1213 | vnc_zlog_debug_verbose( | |
1214 | "%s: add vn=%s un=%s cost=%d life=%d", | |
1215 | __func__, buf, buf2, new->prefix.cost, | |
1216 | new->lifetime); | |
1217 | } | |
1218 | } | |
1219 | ||
1220 | RFAPI_RIB_CHECK_COUNTS(0, (delete_list ? delete_list->count : 0)); | |
1221 | ||
1222 | if (delete_list) { | |
1223 | ||
1224 | char buf[BUFSIZ]; | |
1225 | char buf2[BUFSIZ]; | |
1226 | ||
1227 | if (!printedprefix) { | |
26a3ffd6 DS |
1228 | vnc_zlog_debug_verbose("%s: For prefix %pRN (d)", |
1229 | __func__, pn); | |
d62a17ae | 1230 | } |
1231 | vnc_zlog_debug_verbose("%s: delete_list has %d elements", | |
1232 | __func__, delete_list->count); | |
1233 | ||
1234 | RFAPI_RIB_CHECK_COUNTS(0, delete_list->count); | |
1235 | if (!CHECK_FLAG(bgp->rfapi_cfg->flags, | |
1236 | BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) { | |
1237 | ||
1238 | for (ALL_LIST_ELEMENTS(delete_list, node, nnode, ri)) { | |
1239 | ||
1240 | struct rfapi_next_hop_entry *new; | |
1241 | struct rfapi_info *ri_del; | |
1242 | ||
1243 | RFAPI_RIB_CHECK_COUNTS(0, delete_list->count); | |
1244 | new = XCALLOC( | |
1245 | MTYPE_RFAPI_NEXTHOP, | |
1246 | sizeof(struct rfapi_next_hop_entry)); | |
d62a17ae | 1247 | |
1248 | if (ri->rk.aux_prefix.family) { | |
1249 | rfapiQprefix2Rprefix(&ri->rk.aux_prefix, | |
1250 | &new->prefix); | |
1251 | } else { | |
1252 | new->prefix = hp; | |
1253 | if (AFI_L2VPN == afi) { | |
1254 | /* hp is 0; need to set length | |
1255 | * to match AF of vn */ | |
1256 | new->prefix.length = | |
1257 | (ri->rk.vn.family | |
1258 | == AF_INET) | |
1259 | ? 32 | |
1260 | : 128; | |
1261 | } | |
1262 | } | |
1263 | ||
1264 | new->prefix.cost = ri->cost; | |
1265 | new->lifetime = RFAPI_REMOVE_RESPONSE_LIFETIME; | |
1266 | rfapiQprefix2Raddr(&ri->rk.vn, | |
1267 | &new->vn_address); | |
1268 | rfapiQprefix2Raddr(&ri->un, &new->un_address); | |
1269 | ||
1270 | new->vn_options = ri->vn_options; | |
1271 | ri->vn_options = NULL; /* option chain was | |
1272 | transferred to NHL */ | |
1273 | ||
1274 | new->un_options = ri->un_options; | |
1275 | ri->un_options = NULL; /* option chain was | |
1276 | transferred to NHL */ | |
1277 | ||
1278 | if (*tail) | |
1279 | (*tail)->next = new; | |
1280 | *tail = new; | |
1281 | if (!*head) { | |
1282 | *head = new; | |
1283 | } | |
1284 | ++rfd->stat_count_nh_removal; | |
1285 | ++bgp->rfapi->stat | |
1286 | .count_updated_response_deletes; | |
1287 | ||
1288 | rfapiRfapiIpAddr2Str(&new->vn_address, buf, | |
1289 | BUFSIZ); | |
1290 | rfapiRfapiIpAddr2Str(&new->un_address, buf2, | |
1291 | BUFSIZ); | |
1292 | vnc_zlog_debug_verbose( | |
1293 | "%s: DEL vn=%s un=%s cost=%d life=%d", | |
1294 | __func__, buf, buf2, new->prefix.cost, | |
1295 | new->lifetime); | |
1296 | ||
1297 | RFAPI_RIB_CHECK_COUNTS(0, delete_list->count); | |
1298 | /* | |
1299 | * Update/add to list of recent deletions at | |
1300 | * this prefix | |
1301 | */ | |
1302 | if (!rn->aggregate) { | |
1303 | rn->aggregate = skiplist_new( | |
1304 | 0, rfapi_rib_key_cmp, | |
1305 | (void (*)(void *)) | |
1306 | rfapi_info_free); | |
fe08ba7e | 1307 | agg_lock_node(rn); |
d62a17ae | 1308 | } |
1309 | RFAPI_RIB_CHECK_COUNTS(0, delete_list->count); | |
1310 | ||
1311 | /* sanity check lifetime */ | |
1312 | if (ri->lifetime | |
1313 | > RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY) | |
1314 | ri->lifetime = | |
1315 | RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY; | |
1316 | ||
1317 | RFAPI_RIB_CHECK_COUNTS(0, delete_list->count); | |
1318 | /* cancel normal expire timer */ | |
1319 | if (ri->timer) { | |
1320 | struct rfapi_rib_tcb *tcb; | |
1321 | ||
c3aaa89a DS |
1322 | tcb = THREAD_ARG(ri->timer); |
1323 | THREAD_OFF(ri->timer); | |
d62a17ae | 1324 | XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb); |
d62a17ae | 1325 | } |
1326 | RFAPI_RIB_CHECK_COUNTS(0, delete_list->count); | |
1327 | ||
1328 | /* | |
1329 | * Look in "recently-deleted" list | |
1330 | */ | |
1331 | if (skiplist_search( | |
1332 | (struct skiplist *)(rn->aggregate), | |
1333 | &ri->rk, (void **)&ri_del)) { | |
1334 | ||
1335 | int rc; | |
1336 | ||
1337 | RFAPI_RIB_CHECK_COUNTS( | |
1338 | 0, delete_list->count); | |
1339 | /* | |
1340 | * NOT in "recently-deleted" list | |
1341 | */ | |
1342 | list_delete_node( | |
1343 | delete_list, | |
1344 | node); /* does not free ri */ | |
1345 | rc = skiplist_insert( | |
1346 | (struct skiplist | |
1347 | *)(rn->aggregate), | |
1348 | &ri->rk, ri); | |
1349 | assert(!rc); | |
1350 | ||
1351 | RFAPI_RIB_CHECK_COUNTS( | |
1352 | 0, delete_list->count); | |
1353 | rfapiRibStartTimer(rfd, ri, rn, 1); | |
1354 | RFAPI_RIB_CHECK_COUNTS( | |
1355 | 0, delete_list->count); | |
98b7e975 | 1356 | ri->last_sent_time = monotime(NULL); |
65efcfce | 1357 | #if DEBUG_RIB_SL_RD |
c4f64ea9 | 1358 | vnc_zlog_debug_verbose( |
4a8cd6ad | 1359 | "%s: move route to recently deleted list, rd=%pRDP", |
c4f64ea9 | 1360 | __func__, &ri->rk.rd); |
65efcfce LB |
1361 | #endif |
1362 | ||
d62a17ae | 1363 | } else { |
1364 | /* | |
1365 | * IN "recently-deleted" list | |
1366 | */ | |
1367 | RFAPI_RIB_CHECK_COUNTS( | |
1368 | 0, delete_list->count); | |
1369 | rfapiRibStartTimer(rfd, ri_del, rn, 1); | |
1370 | RFAPI_RIB_CHECK_COUNTS( | |
1371 | 0, delete_list->count); | |
98b7e975 | 1372 | ri->last_sent_time = monotime(NULL); |
d62a17ae | 1373 | } |
1374 | } | |
1375 | } else { | |
1376 | vnc_zlog_debug_verbose( | |
1377 | "%s: response removal disabled, omitting removals", | |
1378 | __func__); | |
1379 | } | |
1380 | ||
1381 | delete_list->del = (void (*)(void *))rfapi_info_free; | |
6a154c88 | 1382 | list_delete(&delete_list); |
d62a17ae | 1383 | } |
1384 | ||
1385 | RFAPI_RIB_CHECK_COUNTS(0, 0); | |
1386 | ||
1387 | /* | |
fe08ba7e | 1388 | * Reset pending lists. The final agg_unlock_node() will probably |
d62a17ae | 1389 | * cause the pending node to be released. |
1390 | */ | |
1391 | if (slPendPt) { | |
1392 | skiplist_free(slPendPt); | |
1393 | pn->aggregate = NULL; | |
fe08ba7e | 1394 | agg_unlock_node(pn); |
d62a17ae | 1395 | } |
1396 | if (lPendCost) { | |
6a154c88 | 1397 | list_delete(&lPendCost); |
d62a17ae | 1398 | pn->info = NULL; |
fe08ba7e | 1399 | agg_unlock_node(pn); |
d62a17ae | 1400 | } |
1401 | RFAPI_RIB_CHECK_COUNTS(0, 0); | |
1402 | ||
1403 | if (rib_node_started_nonempty) { | |
1404 | if (!rn->info) { | |
1405 | RFAPI_RIB_PREFIX_COUNT_DECR(rfd, bgp->rfapi); | |
1406 | } | |
1407 | } else { | |
1408 | if (rn->info) { | |
1409 | RFAPI_RIB_PREFIX_COUNT_INCR(rfd, bgp->rfapi); | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | if (sendingsomeroutes) | |
26a3ffd6 | 1414 | rfapiMonitorTimersRestart(rfd, p); |
d62a17ae | 1415 | |
fe08ba7e | 1416 | agg_unlock_node(rn); /* agg_node_get() */ |
d62a17ae | 1417 | |
1418 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
65efcfce LB |
1419 | } |
1420 | ||
1421 | /* | |
1422 | * regardless of targets, construct a single callback by doing | |
1423 | * only one traversal of the pending RIB | |
1424 | * | |
1425 | * | |
1426 | * Do callback | |
1427 | * | |
1428 | */ | |
d62a17ae | 1429 | static void rib_do_callback_onepass(struct rfapi_descriptor *rfd, afi_t afi) |
65efcfce | 1430 | { |
d62a17ae | 1431 | struct bgp *bgp = bgp_get_default(); |
1432 | struct rfapi_next_hop_entry *head = NULL; | |
1433 | struct rfapi_next_hop_entry *tail = NULL; | |
fe08ba7e | 1434 | struct agg_node *rn; |
65efcfce | 1435 | |
1e20238a | 1436 | #ifdef DEBUG_L2_EXTRA |
d62a17ae | 1437 | vnc_zlog_debug_verbose("%s: rfd=%p, afi=%d", __func__, rfd, afi); |
65efcfce LB |
1438 | #endif |
1439 | ||
d62a17ae | 1440 | if (!rfd->rib_pending[afi]) |
1441 | return; | |
65efcfce | 1442 | |
d62a17ae | 1443 | assert(bgp->rfapi); |
65efcfce | 1444 | |
fe08ba7e DS |
1445 | for (rn = agg_route_top(rfd->rib_pending[afi]); rn; |
1446 | rn = agg_route_next(rn)) { | |
d62a17ae | 1447 | process_pending_node(bgp, rfd, afi, rn, &head, &tail); |
1448 | } | |
65efcfce | 1449 | |
d62a17ae | 1450 | if (head) { |
1451 | rfapi_response_cb_t *f; | |
65efcfce LB |
1452 | |
1453 | #if DEBUG_NHL | |
d62a17ae | 1454 | vnc_zlog_debug_verbose("%s: response callback NHL follows:", |
1455 | __func__); | |
1456 | rfapiPrintNhl(NULL, head); | |
65efcfce LB |
1457 | #endif |
1458 | ||
d62a17ae | 1459 | if (rfd->response_cb) |
1460 | f = rfd->response_cb; | |
1461 | else | |
1462 | f = bgp->rfapi->rfp_methods.response_cb; | |
1463 | ||
1464 | bgp->rfapi->flags |= RFAPI_INCALLBACK; | |
1465 | vnc_zlog_debug_verbose("%s: invoking updated response callback", | |
1466 | __func__); | |
1467 | (*f)(head, rfd->cookie); | |
1468 | bgp->rfapi->flags &= ~RFAPI_INCALLBACK; | |
1469 | ++bgp->rfapi->response_updated_count; | |
1470 | } | |
65efcfce LB |
1471 | } |
1472 | ||
d62a17ae | 1473 | static wq_item_status rfapiRibDoQueuedCallback(struct work_queue *wq, |
1474 | void *data) | |
65efcfce | 1475 | { |
d62a17ae | 1476 | struct rfapi_descriptor *rfd; |
1477 | afi_t afi; | |
1478 | uint32_t queued_flag; | |
65efcfce | 1479 | |
d62a17ae | 1480 | RFAPI_RIB_CHECK_COUNTS(1, 0); |
65efcfce | 1481 | |
d62a17ae | 1482 | rfd = ((struct rfapi_updated_responses_queue *)data)->rfd; |
1483 | afi = ((struct rfapi_updated_responses_queue *)data)->afi; | |
65efcfce | 1484 | |
d62a17ae | 1485 | /* Make sure the HD wasn't closed after the work item was scheduled */ |
1486 | if (rfapi_check(rfd)) | |
1487 | return WQ_SUCCESS; | |
65efcfce | 1488 | |
d62a17ae | 1489 | rib_do_callback_onepass(rfd, afi); |
65efcfce | 1490 | |
d62a17ae | 1491 | queued_flag = RFAPI_QUEUED_FLAG(afi); |
65efcfce | 1492 | |
d62a17ae | 1493 | UNSET_FLAG(rfd->flags, queued_flag); |
65efcfce | 1494 | |
d62a17ae | 1495 | RFAPI_RIB_CHECK_COUNTS(1, 0); |
65efcfce | 1496 | |
d62a17ae | 1497 | return WQ_SUCCESS; |
65efcfce LB |
1498 | } |
1499 | ||
d62a17ae | 1500 | static void rfapiRibQueueItemDelete(struct work_queue *wq, void *data) |
65efcfce | 1501 | { |
d62a17ae | 1502 | XFREE(MTYPE_RFAPI_UPDATED_RESPONSE_QUEUE, data); |
65efcfce LB |
1503 | } |
1504 | ||
d62a17ae | 1505 | static void updated_responses_queue_init(struct rfapi_descriptor *rfd) |
65efcfce | 1506 | { |
d62a17ae | 1507 | if (rfd->updated_responses_queue) |
1508 | return; | |
1509 | ||
1510 | rfd->updated_responses_queue = | |
1511 | work_queue_new(bm->master, "rfapi updated responses"); | |
1512 | assert(rfd->updated_responses_queue); | |
1513 | ||
1514 | rfd->updated_responses_queue->spec.workfunc = rfapiRibDoQueuedCallback; | |
1515 | rfd->updated_responses_queue->spec.del_item_data = | |
1516 | rfapiRibQueueItemDelete; | |
1517 | rfd->updated_responses_queue->spec.max_retries = 0; | |
1518 | rfd->updated_responses_queue->spec.hold = 1; | |
65efcfce LB |
1519 | } |
1520 | ||
1521 | /* | |
1522 | * Called when an import table node is modified. Construct a | |
1523 | * new complete nexthop list, sorted by cost (lowest first), | |
1524 | * based on the import table node. | |
1525 | * | |
1526 | * Filter out duplicate nexthops (vn address). There should be | |
1527 | * only one UN address per VN address from the point of view of | |
1528 | * a given import table, so we can probably ignore UN addresses | |
1529 | * while filtering. | |
1530 | * | |
1531 | * Based on rfapiNhlAddNodeRoutes() | |
1532 | */ | |
d62a17ae | 1533 | void rfapiRibUpdatePendingNode( |
1534 | struct bgp *bgp, struct rfapi_descriptor *rfd, | |
1535 | struct rfapi_import_table *it, /* needed for L2 */ | |
fe08ba7e | 1536 | struct agg_node *it_node, uint32_t lifetime) |
65efcfce | 1537 | { |
26a3ffd6 | 1538 | const struct prefix *prefix; |
40381db7 | 1539 | struct bgp_path_info *bpi; |
fe08ba7e | 1540 | struct agg_node *pn; |
d62a17ae | 1541 | afi_t afi; |
1542 | uint32_t queued_flag; | |
1543 | int count = 0; | |
d62a17ae | 1544 | |
1545 | vnc_zlog_debug_verbose("%s: entry", __func__); | |
1546 | ||
1547 | if (CHECK_FLAG(bgp->rfapi_cfg->flags, BGP_VNC_CONFIG_CALLBACK_DISABLE)) | |
1548 | return; | |
1549 | ||
1550 | vnc_zlog_debug_verbose("%s: callbacks are not disabled", __func__); | |
1551 | ||
1552 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
1553 | ||
26a3ffd6 | 1554 | prefix = agg_node_get_prefix(it_node); |
d62a17ae | 1555 | afi = family2afi(prefix->family); |
2dbe669b | 1556 | vnc_zlog_debug_verbose("%s: prefix=%pFX", __func__, prefix); |
d62a17ae | 1557 | |
fe08ba7e | 1558 | pn = agg_node_get(rfd->rib_pending[afi], prefix); |
d62a17ae | 1559 | assert(pn); |
1560 | ||
1561 | vnc_zlog_debug_verbose("%s: pn->info=%p, pn->aggregate=%p", __func__, | |
1562 | pn->info, pn->aggregate); | |
1563 | ||
1564 | if (pn->aggregate) { | |
1565 | /* | |
1566 | * free references into the rfapi_info structures before | |
1567 | * freeing the structures themselves | |
1568 | */ | |
1569 | skiplist_free((struct skiplist *)(pn->aggregate)); | |
1570 | pn->aggregate = NULL; | |
fe08ba7e | 1571 | agg_unlock_node(pn); /* skiplist deleted */ |
d62a17ae | 1572 | } |
1573 | ||
1574 | ||
1575 | /* | |
1576 | * free the rfapi_info structures | |
1577 | */ | |
1578 | if (pn->info) { | |
1579 | if (pn->info != (void *)1) { | |
6a154c88 | 1580 | list_delete((struct list **)(&pn->info)); |
d62a17ae | 1581 | } |
1582 | pn->info = NULL; | |
fe08ba7e | 1583 | agg_unlock_node(pn); /* linklist or 1 deleted */ |
d62a17ae | 1584 | } |
1585 | ||
1586 | /* | |
40381db7 | 1587 | * The BPIs in the import table are already sorted by cost |
d62a17ae | 1588 | */ |
40381db7 | 1589 | for (bpi = it_node->info; bpi; bpi = bpi->next) { |
d62a17ae | 1590 | |
1591 | struct rfapi_info *ri; | |
1592 | struct prefix pfx_nh; | |
1593 | ||
40381db7 | 1594 | if (!bpi->extra) { |
d62a17ae | 1595 | /* shouldn't happen */ |
1596 | /* TBD increment error stats counter */ | |
1597 | continue; | |
1598 | } | |
1599 | ||
40381db7 | 1600 | rfapiNexthop2Prefix(bpi->attr, &pfx_nh); |
d62a17ae | 1601 | |
1602 | /* | |
1603 | * Omit route if nexthop is self | |
1604 | */ | |
1605 | if (CHECK_FLAG(bgp->rfapi_cfg->flags, | |
1606 | BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP)) { | |
1607 | ||
1608 | struct prefix pfx_vn; | |
1609 | ||
cbb65f5e | 1610 | assert(!rfapiRaddr2Qprefix(&rfd->vn_addr, &pfx_vn)); |
d62a17ae | 1611 | if (prefix_same(&pfx_vn, &pfx_nh)) |
1612 | continue; | |
1613 | } | |
1614 | ||
1615 | ri = rfapi_info_new(); | |
1616 | ri->rk.vn = pfx_nh; | |
40381db7 | 1617 | ri->rk.rd = bpi->extra->vnc.import.rd; |
d62a17ae | 1618 | /* |
1619 | * If there is an auxiliary IP address (L2 can have it), copy it | |
1620 | */ | |
40381db7 DS |
1621 | if (bpi->extra->vnc.import.aux_prefix.family) { |
1622 | ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; | |
d62a17ae | 1623 | } |
1624 | ||
40381db7 | 1625 | if (rfapiGetUnAddrOfVpnBi(bpi, &ri->un)) { |
d62a17ae | 1626 | rfapi_info_free(ri); |
1627 | continue; | |
1628 | } | |
1629 | ||
1630 | if (!pn->aggregate) { | |
1631 | pn->aggregate = | |
1632 | skiplist_new(0, rfapi_rib_key_cmp, NULL); | |
fe08ba7e | 1633 | agg_lock_node(pn); |
d62a17ae | 1634 | } |
1635 | ||
1636 | /* | |
1637 | * If we have already added this nexthop, the insert will fail. | |
1638 | * Note that the skiplist key is a pointer INTO the rfapi_info | |
1639 | * structure which will be added to the "info" list. | |
1640 | * The skiplist entry VALUE is not used for anything but | |
1641 | * might be useful during debugging. | |
1642 | */ | |
1643 | if (skiplist_insert((struct skiplist *)pn->aggregate, &ri->rk, | |
1644 | ri)) { | |
1645 | ||
1646 | /* | |
1647 | * duplicate | |
1648 | */ | |
1649 | rfapi_info_free(ri); | |
1650 | continue; | |
1651 | } | |
1652 | ||
40381db7 | 1653 | rfapiRibBi2Ri(bpi, ri, lifetime); |
d62a17ae | 1654 | |
1655 | if (!pn->info) { | |
1656 | pn->info = list_new(); | |
1657 | ((struct list *)(pn->info))->del = | |
1658 | (void (*)(void *))rfapi_info_free; | |
fe08ba7e | 1659 | agg_lock_node(pn); |
d62a17ae | 1660 | } |
1661 | ||
1662 | listnode_add((struct list *)(pn->info), ri); | |
1663 | } | |
1664 | ||
1665 | if (pn->info) { | |
1666 | count = ((struct list *)(pn->info))->count; | |
1667 | } | |
1668 | ||
1669 | if (!count) { | |
1670 | assert(!pn->info); | |
1671 | assert(!pn->aggregate); | |
1672 | pn->info = (void *)1; /* magic value means this node has no | |
1673 | routes */ | |
fe08ba7e | 1674 | agg_lock_node(pn); |
d62a17ae | 1675 | } |
1676 | ||
fe08ba7e | 1677 | agg_unlock_node(pn); /* agg_node_get */ |
d62a17ae | 1678 | |
1679 | queued_flag = RFAPI_QUEUED_FLAG(afi); | |
1680 | ||
1681 | if (!CHECK_FLAG(rfd->flags, queued_flag)) { | |
1682 | ||
1683 | struct rfapi_updated_responses_queue *urq; | |
1684 | ||
1685 | urq = XCALLOC(MTYPE_RFAPI_UPDATED_RESPONSE_QUEUE, | |
1686 | sizeof(struct rfapi_updated_responses_queue)); | |
d62a17ae | 1687 | if (!rfd->updated_responses_queue) |
1688 | updated_responses_queue_init(rfd); | |
1689 | ||
1690 | SET_FLAG(rfd->flags, queued_flag); | |
1691 | urq->rfd = rfd; | |
1692 | urq->afi = afi; | |
1693 | work_queue_add(rfd->updated_responses_queue, urq); | |
1694 | } | |
1695 | RFAPI_RIB_CHECK_COUNTS(1, 0); | |
65efcfce LB |
1696 | } |
1697 | ||
d62a17ae | 1698 | void rfapiRibUpdatePendingNodeSubtree( |
1699 | struct bgp *bgp, struct rfapi_descriptor *rfd, | |
fe08ba7e DS |
1700 | struct rfapi_import_table *it, struct agg_node *it_node, |
1701 | struct agg_node *omit_subtree, /* may be NULL */ | |
d62a17ae | 1702 | uint32_t lifetime) |
65efcfce | 1703 | { |
d62a17ae | 1704 | /* FIXME: need to find a better way here to work without sticking our |
1705 | * hands in node->link */ | |
fe08ba7e DS |
1706 | if (agg_node_left(it_node) |
1707 | && (agg_node_left(it_node) != omit_subtree)) { | |
1708 | if (agg_node_left(it_node)->info) | |
1709 | rfapiRibUpdatePendingNode( | |
1710 | bgp, rfd, it, agg_node_left(it_node), lifetime); | |
1711 | rfapiRibUpdatePendingNodeSubtree(bgp, rfd, it, | |
1712 | agg_node_left(it_node), | |
d62a17ae | 1713 | omit_subtree, lifetime); |
1714 | } | |
1715 | ||
fe08ba7e DS |
1716 | if (agg_node_right(it_node) |
1717 | && (agg_node_right(it_node) != omit_subtree)) { | |
1718 | if (agg_node_right(it_node)->info) | |
d62a17ae | 1719 | rfapiRibUpdatePendingNode(bgp, rfd, it, |
fe08ba7e DS |
1720 | agg_node_right(it_node), |
1721 | lifetime); | |
1722 | rfapiRibUpdatePendingNodeSubtree(bgp, rfd, it, | |
1723 | agg_node_right(it_node), | |
d62a17ae | 1724 | omit_subtree, lifetime); |
1725 | } | |
65efcfce LB |
1726 | } |
1727 | ||
1728 | /* | |
1729 | * RETURN VALUE | |
1730 | * | |
1731 | * 0 allow prefix to be included in response | |
1732 | * !0 don't allow prefix to be included in response | |
1733 | */ | |
d62a17ae | 1734 | int rfapiRibFTDFilterRecentPrefix( |
1735 | struct rfapi_descriptor *rfd, | |
fe08ba7e | 1736 | struct agg_node *it_rn, /* import table node */ |
d62a17ae | 1737 | struct prefix *pfx_target_original) /* query target */ |
65efcfce | 1738 | { |
d62a17ae | 1739 | struct bgp *bgp = rfd->bgp; |
26a3ffd6 DS |
1740 | const struct prefix *p = agg_node_get_prefix(it_rn); |
1741 | afi_t afi = family2afi(p->family); | |
d62a17ae | 1742 | time_t prefix_time; |
fe08ba7e | 1743 | struct agg_node *trn; |
d62a17ae | 1744 | |
1745 | /* | |
1746 | * Not in FTD mode, so allow prefix | |
1747 | */ | |
1748 | if (bgp->rfapi_cfg->rfp_cfg.download_type != RFAPI_RFP_DOWNLOAD_FULL) | |
1749 | return 0; | |
1750 | ||
1751 | /* | |
1752 | * TBD | |
1753 | * This matches behavior of now-obsolete rfapiRibFTDFilterRecent(), | |
1754 | * but we need to decide if that is correct. | |
1755 | */ | |
26a3ffd6 | 1756 | if (p->family == AF_ETHERNET) |
d62a17ae | 1757 | return 0; |
65efcfce | 1758 | |
1e20238a | 1759 | #ifdef DEBUG_FTD_FILTER_RECENT |
d62a17ae | 1760 | { |
2dbe669b DA |
1761 | vnc_zlog_debug_verbose("%s: prefix %pFX", __func__, |
1762 | agg_node_get_prefix(it_rn)); | |
d62a17ae | 1763 | } |
65efcfce LB |
1764 | #endif |
1765 | ||
d62a17ae | 1766 | /* |
1767 | * prefix covers target address, so allow prefix | |
1768 | */ | |
26a3ffd6 | 1769 | if (prefix_match(p, pfx_target_original)) { |
1e20238a | 1770 | #ifdef DEBUG_FTD_FILTER_RECENT |
d62a17ae | 1771 | vnc_zlog_debug_verbose("%s: prefix covers target, allowed", |
1772 | __func__); | |
65efcfce | 1773 | #endif |
d62a17ae | 1774 | return 0; |
1775 | } | |
65efcfce | 1776 | |
d62a17ae | 1777 | /* |
1778 | * check this NVE's timestamp for this prefix | |
1779 | */ | |
26a3ffd6 | 1780 | trn = agg_node_get(rfd->rsp_times[afi], p); /* locks trn */ |
d62a17ae | 1781 | prefix_time = (time_t)trn->info; |
c10e14e9 | 1782 | if (agg_node_get_lock_count(trn) > 1) |
fe08ba7e | 1783 | agg_unlock_node(trn); |
65efcfce | 1784 | |
1e20238a | 1785 | #ifdef DEBUG_FTD_FILTER_RECENT |
d62a17ae | 1786 | vnc_zlog_debug_verbose("%s: last sent time %lu, last allowed time %lu", |
1787 | __func__, prefix_time, | |
1788 | rfd->ftd_last_allowed_time); | |
65efcfce LB |
1789 | #endif |
1790 | ||
d62a17ae | 1791 | /* |
1792 | * haven't sent this prefix, which doesn't cover target address, | |
1793 | * to NVE since ftd_advertisement_interval, so OK to send now. | |
1794 | */ | |
1795 | if (prefix_time <= rfd->ftd_last_allowed_time) | |
1796 | return 0; | |
65efcfce | 1797 | |
d62a17ae | 1798 | return 1; |
65efcfce LB |
1799 | } |
1800 | ||
1801 | /* | |
1802 | * Call when rfapi returns from rfapi_query() so the RIB reflects | |
1803 | * the routes sent to the NVE before the first updated response | |
1804 | * | |
1805 | * Also: remove duplicates from response. Caller should use returned | |
1806 | * value of nexthop chain. | |
1807 | */ | |
1808 | struct rfapi_next_hop_entry * | |
d62a17ae | 1809 | rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd, |
1810 | struct rfapi_next_hop_entry *response, int use_eth_resolution) | |
65efcfce | 1811 | { |
d62a17ae | 1812 | struct rfapi_next_hop_entry *nhp; |
1813 | struct rfapi_next_hop_entry *nhp_next; | |
1814 | struct rfapi_next_hop_entry *head = NULL; | |
1815 | struct rfapi_next_hop_entry *tail = NULL; | |
1816 | time_t new_last_sent_time; | |
1817 | ||
1818 | vnc_zlog_debug_verbose("%s: loading response=%p, use_eth_resolution=%d", | |
1819 | __func__, response, use_eth_resolution); | |
1820 | ||
98b7e975 | 1821 | new_last_sent_time = monotime(NULL); |
d62a17ae | 1822 | |
1823 | for (nhp = response; nhp; nhp = nhp_next) { | |
1824 | ||
1825 | struct prefix pfx; | |
1826 | struct rfapi_rib_key rk; | |
1827 | afi_t afi; | |
1828 | struct rfapi_info *ri; | |
1829 | int need_insert; | |
fe08ba7e | 1830 | struct agg_node *rn; |
d62a17ae | 1831 | int rib_node_started_nonempty = 0; |
fe08ba7e | 1832 | struct agg_node *trn; |
d62a17ae | 1833 | int allowed = 0; |
1834 | ||
1835 | /* save in case we delete nhp */ | |
1836 | nhp_next = nhp->next; | |
1837 | ||
1838 | if (nhp->lifetime == RFAPI_REMOVE_RESPONSE_LIFETIME) { | |
1839 | /* | |
1840 | * weird, shouldn't happen | |
1841 | */ | |
1842 | vnc_zlog_debug_verbose( | |
1843 | "%s: got nhp->lifetime == RFAPI_REMOVE_RESPONSE_LIFETIME", | |
1844 | __func__); | |
1845 | continue; | |
1846 | } | |
1847 | ||
1848 | ||
1849 | if (use_eth_resolution) { | |
1850 | /* get the prefix of the ethernet address in the L2 | |
1851 | * option */ | |
1852 | struct rfapi_l2address_option *pL2o; | |
1853 | struct rfapi_vn_option *vo; | |
1854 | ||
1855 | /* | |
1856 | * Look for VN option of type | |
1857 | * RFAPI_VN_OPTION_TYPE_L2ADDR | |
1858 | */ | |
1859 | for (pL2o = NULL, vo = nhp->vn_options; vo; | |
1860 | vo = vo->next) { | |
1861 | if (RFAPI_VN_OPTION_TYPE_L2ADDR == vo->type) { | |
1862 | pL2o = &vo->v.l2addr; | |
1863 | break; | |
1864 | } | |
1865 | } | |
1866 | ||
1867 | if (!pL2o) { | |
1868 | /* | |
1869 | * not supposed to happen | |
1870 | */ | |
1871 | vnc_zlog_debug_verbose("%s: missing L2 info", | |
1872 | __func__); | |
1873 | continue; | |
1874 | } | |
1875 | ||
1876 | afi = AFI_L2VPN; | |
1877 | rfapiL2o2Qprefix(pL2o, &pfx); | |
1878 | } else { | |
1879 | rfapiRprefix2Qprefix(&nhp->prefix, &pfx); | |
1880 | afi = family2afi(pfx.family); | |
1881 | } | |
1882 | ||
1883 | /* | |
1884 | * TBD for ethernet, rib must know the right way to distinguish | |
1885 | * duplicate routes | |
1886 | * | |
1887 | * Current approach: prefix is key to radix tree; then | |
1888 | * each prefix has a set of routes with unique VN addrs | |
1889 | */ | |
1890 | ||
1891 | /* | |
1892 | * Look up prefix in RIB | |
1893 | */ | |
fe08ba7e | 1894 | rn = agg_node_get(rfd->rib[afi], &pfx); /* locks rn */ |
d62a17ae | 1895 | |
1896 | if (rn->info) { | |
1897 | rib_node_started_nonempty = 1; | |
1898 | } else { | |
1899 | rn->info = skiplist_new(0, rfapi_rib_key_cmp, NULL); | |
fe08ba7e | 1900 | agg_lock_node(rn); |
d62a17ae | 1901 | } |
1902 | ||
1903 | /* | |
1904 | * Look up route at prefix | |
1905 | */ | |
1906 | need_insert = 0; | |
1907 | memset((void *)&rk, 0, sizeof(rk)); | |
1908 | assert(!rfapiRaddr2Qprefix(&nhp->vn_address, &rk.vn)); | |
1909 | ||
1910 | if (use_eth_resolution) { | |
1911 | /* copy what came from aux_prefix to rk.aux_prefix */ | |
1912 | rfapiRprefix2Qprefix(&nhp->prefix, &rk.aux_prefix); | |
1913 | if (RFAPI_0_PREFIX(&rk.aux_prefix) | |
1914 | && RFAPI_HOST_PREFIX(&rk.aux_prefix)) { | |
1915 | /* mark as "none" if nhp->prefix is 0/32 or | |
1916 | * 0/128 */ | |
c7ca5ccf | 1917 | rk.aux_prefix.family = AF_UNSPEC; |
d62a17ae | 1918 | } |
1919 | } | |
65efcfce LB |
1920 | |
1921 | #if DEBUG_NHL | |
d62a17ae | 1922 | { |
872ed4c7 | 1923 | char str_aux_prefix[PREFIX_STRLEN]; |
d62a17ae | 1924 | |
d62a17ae | 1925 | str_aux_prefix[0] = 0; |
1926 | ||
872ed4c7 DS |
1927 | prefix2str(&rk.aux_prefix, str_aux_prefix, |
1928 | sizeof(str_aux_prefix)); | |
d62a17ae | 1929 | |
1930 | if (!rk.aux_prefix.family) { | |
1931 | } | |
1932 | vnc_zlog_debug_verbose( | |
2dbe669b DA |
1933 | "%s: rk.vn=%pFX rk.aux_prefix=%s", __func__, |
1934 | &rk.vn, | |
d62a17ae | 1935 | (rk.aux_prefix.family ? str_aux_prefix : "-")); |
1936 | } | |
1937 | vnc_zlog_debug_verbose( | |
1938 | "%s: RIB skiplist for this prefix follows", __func__); | |
b54892e0 DS |
1939 | rfapiRibShowRibSl(NULL, agg_node_get_prefix(rn), |
1940 | (struct skiplist *)rn->info); | |
65efcfce LB |
1941 | #endif |
1942 | ||
1943 | ||
d62a17ae | 1944 | if (!skiplist_search((struct skiplist *)rn->info, &rk, |
1945 | (void **)&ri)) { | |
1946 | /* | |
1947 | * Already have this route; make values match | |
1948 | */ | |
1949 | rfapiFreeRfapiUnOptionChain(ri->un_options); | |
1950 | ri->un_options = NULL; | |
1951 | rfapiFreeRfapiVnOptionChain(ri->vn_options); | |
1952 | ri->vn_options = NULL; | |
65efcfce LB |
1953 | |
1954 | #if DEBUG_NHL | |
d62a17ae | 1955 | vnc_zlog_debug_verbose("%s: found in RIB", __func__); |
65efcfce LB |
1956 | #endif |
1957 | ||
d62a17ae | 1958 | /* |
1959 | * Filter duplicate routes from initial response. | |
1960 | * Check timestamps to avoid wraparound problems | |
1961 | */ | |
1962 | if ((ri->rsp_counter != rfd->rsp_counter) | |
1963 | || (ri->last_sent_time != new_last_sent_time)) { | |
65efcfce LB |
1964 | |
1965 | #if DEBUG_NHL | |
d62a17ae | 1966 | vnc_zlog_debug_verbose( |
1967 | "%s: allowed due to counter/timestamp diff", | |
1968 | __func__); | |
65efcfce | 1969 | #endif |
d62a17ae | 1970 | allowed = 1; |
1971 | } | |
65efcfce | 1972 | |
d62a17ae | 1973 | } else { |
65efcfce LB |
1974 | |
1975 | #if DEBUG_NHL | |
d62a17ae | 1976 | vnc_zlog_debug_verbose( |
1977 | "%s: allowed due to not yet in RIB", __func__); | |
65efcfce | 1978 | #endif |
d62a17ae | 1979 | /* not found: add new route to RIB */ |
1980 | ri = rfapi_info_new(); | |
1981 | need_insert = 1; | |
1982 | allowed = 1; | |
1983 | } | |
1984 | ||
1985 | ri->rk = rk; | |
1986 | assert(!rfapiRaddr2Qprefix(&nhp->un_address, &ri->un)); | |
1987 | ri->cost = nhp->prefix.cost; | |
1988 | ri->lifetime = nhp->lifetime; | |
1989 | ri->vn_options = rfapiVnOptionsDup(nhp->vn_options); | |
1990 | ri->rsp_counter = rfd->rsp_counter; | |
98b7e975 | 1991 | ri->last_sent_time = monotime(NULL); |
d62a17ae | 1992 | |
1993 | if (need_insert) { | |
1994 | int rc; | |
1995 | rc = skiplist_insert((struct skiplist *)rn->info, | |
1996 | &ri->rk, ri); | |
1997 | assert(!rc); | |
1998 | } | |
1999 | ||
2000 | if (!rib_node_started_nonempty) { | |
2001 | RFAPI_RIB_PREFIX_COUNT_INCR(rfd, bgp->rfapi); | |
2002 | } | |
2003 | ||
2004 | RFAPI_RIB_CHECK_COUNTS(0, 0); | |
2005 | rfapiRibStartTimer(rfd, ri, rn, 0); | |
2006 | RFAPI_RIB_CHECK_COUNTS(0, 0); | |
2007 | ||
fe08ba7e | 2008 | agg_unlock_node(rn); |
d62a17ae | 2009 | |
2010 | /* | |
2011 | * update this NVE's timestamp for this prefix | |
2012 | */ | |
fe08ba7e | 2013 | trn = agg_node_get(rfd->rsp_times[afi], &pfx); /* locks trn */ |
083ec940 | 2014 | trn->info = (void *)(uintptr_t)monotime(NULL); |
c10e14e9 | 2015 | if (agg_node_get_lock_count(trn) > 1) |
fe08ba7e | 2016 | agg_unlock_node(trn); |
d62a17ae | 2017 | |
2dbe669b DA |
2018 | vnc_zlog_debug_verbose( |
2019 | "%s: added pfx=%pFX nh[vn]=%pFX, cost=%u, lifetime=%u, allowed=%d", | |
2020 | __func__, &pfx, &rk.vn, nhp->prefix.cost, nhp->lifetime, | |
2021 | allowed); | |
d62a17ae | 2022 | |
2023 | if (allowed) { | |
2024 | if (tail) | |
2025 | (tail)->next = nhp; | |
2026 | tail = nhp; | |
2027 | if (!head) { | |
2028 | head = nhp; | |
2029 | } | |
2030 | } else { | |
2031 | rfapi_un_options_free(nhp->un_options); | |
2032 | nhp->un_options = NULL; | |
2033 | rfapi_vn_options_free(nhp->vn_options); | |
2034 | nhp->vn_options = NULL; | |
2035 | ||
2036 | XFREE(MTYPE_RFAPI_NEXTHOP, nhp); | |
d62a17ae | 2037 | } |
2038 | } | |
2039 | ||
2040 | if (tail) | |
2041 | tail->next = NULL; | |
2042 | return head; | |
65efcfce LB |
2043 | } |
2044 | ||
d62a17ae | 2045 | void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it, |
fe08ba7e | 2046 | afi_t afi, struct agg_node *it_node) |
65efcfce | 2047 | { |
d62a17ae | 2048 | struct rfapi_descriptor *rfd; |
2049 | struct listnode *node; | |
26a3ffd6 | 2050 | const struct prefix *p = agg_node_get_prefix(it_node); |
d62a17ae | 2051 | |
26a3ffd6 DS |
2052 | vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%pRN", |
2053 | __func__, it, afi, it_node, it_node); | |
d62a17ae | 2054 | |
2055 | if (AFI_L2VPN == afi) { | |
2056 | /* | |
2057 | * ethernet import tables are per-LNI and each ethernet monitor | |
2058 | * identifies the rfd that owns it. | |
2059 | */ | |
2060 | struct rfapi_monitor_eth *m; | |
fe08ba7e | 2061 | struct agg_node *rn; |
d62a17ae | 2062 | struct skiplist *sl; |
2063 | void *cursor; | |
2064 | int rc; | |
2065 | ||
2066 | /* | |
2067 | * route-specific monitors | |
2068 | */ | |
2069 | if ((sl = RFAPI_MONITOR_ETH(it_node))) { | |
2070 | ||
2071 | vnc_zlog_debug_verbose( | |
2072 | "%s: route-specific skiplist: %p", __func__, | |
2073 | sl); | |
2074 | ||
2075 | for (cursor = NULL, | |
8998807f | 2076 | rc = skiplist_next(sl, NULL, (void **)&m, &cursor); |
d62a17ae | 2077 | !rc; rc = skiplist_next(sl, NULL, (void **)&m, |
8998807f | 2078 | &cursor)) { |
65efcfce LB |
2079 | |
2080 | #if DEBUG_PENDING_DELETE_ROUTE | |
d62a17ae | 2081 | vnc_zlog_debug_verbose("%s: eth monitor rfd=%p", |
2082 | __func__, m->rfd); | |
65efcfce | 2083 | #endif |
d62a17ae | 2084 | /* |
2085 | * If we have already sent a route with this | |
2086 | * prefix to this | |
2087 | * NVE, it's OK to send an update with the | |
2088 | * delete | |
2089 | */ | |
fe08ba7e | 2090 | if ((rn = agg_node_lookup(m->rfd->rib[afi], |
26a3ffd6 | 2091 | p))) { |
d62a17ae | 2092 | rfapiRibUpdatePendingNode( |
2093 | bgp, m->rfd, it, it_node, | |
2094 | m->rfd->response_lifetime); | |
fe08ba7e | 2095 | agg_unlock_node(rn); |
d62a17ae | 2096 | } |
2097 | } | |
2098 | } | |
2099 | ||
2100 | /* | |
2101 | * all-routes/FTD monitors | |
2102 | */ | |
2103 | for (m = it->eth0_queries; m; m = m->next) { | |
65efcfce | 2104 | #if DEBUG_PENDING_DELETE_ROUTE |
d62a17ae | 2105 | vnc_zlog_debug_verbose("%s: eth0 monitor rfd=%p", |
2106 | __func__, m->rfd); | |
65efcfce | 2107 | #endif |
d62a17ae | 2108 | /* |
2109 | * If we have already sent a route with this prefix to | |
2110 | * this | |
2111 | * NVE, it's OK to send an update with the delete | |
2112 | */ | |
26a3ffd6 | 2113 | if ((rn = agg_node_lookup(m->rfd->rib[afi], p))) { |
d62a17ae | 2114 | rfapiRibUpdatePendingNode( |
2115 | bgp, m->rfd, it, it_node, | |
2116 | m->rfd->response_lifetime); | |
94f7f37d | 2117 | agg_unlock_node(rn); |
d62a17ae | 2118 | } |
2119 | } | |
2120 | ||
2121 | } else { | |
2122 | /* | |
2123 | * Find RFDs that reference this import table | |
2124 | */ | |
2125 | for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, node, | |
2126 | rfd)) { | |
2127 | ||
fe08ba7e | 2128 | struct agg_node *rn; |
d62a17ae | 2129 | |
2130 | vnc_zlog_debug_verbose( | |
2131 | "%s: comparing rfd(%p)->import_table=%p to it=%p", | |
2132 | __func__, rfd, rfd->import_table, it); | |
2133 | ||
2134 | if (rfd->import_table != it) | |
2135 | continue; | |
2136 | ||
2137 | vnc_zlog_debug_verbose("%s: matched rfd %p", __func__, | |
2138 | rfd); | |
2139 | ||
2140 | /* | |
2141 | * If we have sent a response to this NVE with this | |
2142 | * prefix | |
2143 | * previously, we should send an updated response. | |
2144 | */ | |
26a3ffd6 | 2145 | if ((rn = agg_node_lookup(rfd->rib[afi], p))) { |
d62a17ae | 2146 | rfapiRibUpdatePendingNode( |
2147 | bgp, rfd, it, it_node, | |
2148 | rfd->response_lifetime); | |
fe08ba7e | 2149 | agg_unlock_node(rn); |
d62a17ae | 2150 | } |
2151 | } | |
2152 | } | |
65efcfce LB |
2153 | } |
2154 | ||
d62a17ae | 2155 | void rfapiRibShowResponsesSummary(void *stream) |
65efcfce | 2156 | { |
d62a17ae | 2157 | int (*fp)(void *, const char *, ...); |
2158 | struct vty *vty; | |
2159 | void *out; | |
2160 | const char *vty_newline; | |
2161 | struct bgp *bgp = bgp_get_default(); | |
2162 | ||
2163 | int nves = 0; | |
2164 | int nves_with_nonempty_ribs = 0; | |
2165 | struct rfapi_descriptor *rfd; | |
2166 | struct listnode *node; | |
2167 | ||
d62a17ae | 2168 | if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) |
2169 | return; | |
9b86009a RW |
2170 | if (!bgp) { |
2171 | fp(out, "Unable to find default BGP instance\n"); | |
2172 | return; | |
2173 | } | |
d62a17ae | 2174 | |
2175 | fp(out, "%-24s ", "Responses: (Prefixes)"); | |
2176 | fp(out, "%-8s %-8u ", "Active:", bgp->rfapi->rib_prefix_count_total); | |
2177 | fp(out, "%-8s %-8u", | |
2178 | "Maximum:", bgp->rfapi->rib_prefix_count_total_max); | |
2179 | fp(out, "\n"); | |
2180 | ||
2181 | fp(out, "%-24s ", " (Updated)"); | |
2182 | fp(out, "%-8s %-8u ", | |
2183 | "Update:", bgp->rfapi->stat.count_updated_response_updates); | |
2184 | fp(out, "%-8s %-8u", | |
2185 | "Remove:", bgp->rfapi->stat.count_updated_response_deletes); | |
2186 | fp(out, "%-8s %-8u", "Total:", | |
2187 | bgp->rfapi->stat.count_updated_response_updates | |
2188 | + bgp->rfapi->stat.count_updated_response_deletes); | |
2189 | fp(out, "\n"); | |
2190 | ||
2191 | fp(out, "%-24s ", " (NVEs)"); | |
2192 | for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, node, rfd)) { | |
2193 | ++nves; | |
2194 | if (rfd->rib_prefix_count) | |
2195 | ++nves_with_nonempty_ribs; | |
2196 | } | |
2197 | fp(out, "%-8s %-8u ", "Active:", nves_with_nonempty_ribs); | |
2198 | fp(out, "%-8s %-8u", "Total:", nves); | |
2199 | fp(out, "\n"); | |
65efcfce LB |
2200 | } |
2201 | ||
d62a17ae | 2202 | void rfapiRibShowResponsesSummaryClear(void) |
65efcfce | 2203 | { |
d62a17ae | 2204 | struct bgp *bgp = bgp_get_default(); |
65efcfce | 2205 | |
d62a17ae | 2206 | bgp->rfapi->rib_prefix_count_total_max = |
2207 | bgp->rfapi->rib_prefix_count_total; | |
65efcfce LB |
2208 | } |
2209 | ||
d62a17ae | 2210 | static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty, |
2211 | void *out, struct skiplist *sl, int deleted, | |
2212 | char *str_pfx, int *printedprefix) | |
65efcfce | 2213 | { |
d62a17ae | 2214 | struct rfapi_info *ri; |
2215 | int rc; | |
2216 | void *cursor; | |
2217 | int routes_displayed = 0; | |
2218 | ||
2219 | cursor = NULL; | |
2220 | for (rc = skiplist_next(sl, NULL, (void **)&ri, &cursor); !rc; | |
2221 | rc = skiplist_next(sl, NULL, (void **)&ri, &cursor)) { | |
2222 | ||
872ed4c7 DS |
2223 | char str_vn[PREFIX_STRLEN]; |
2224 | char str_un[PREFIX_STRLEN]; | |
d62a17ae | 2225 | char str_lifetime[BUFSIZ]; |
2226 | char str_age[BUFSIZ]; | |
2227 | char *p; | |
d62a17ae | 2228 | |
2229 | ++routes_displayed; | |
2230 | ||
872ed4c7 | 2231 | prefix2str(&ri->rk.vn, str_vn, sizeof(str_vn)); |
d62a17ae | 2232 | p = index(str_vn, '/'); |
2233 | if (p) | |
2234 | *p = 0; | |
2235 | ||
872ed4c7 | 2236 | prefix2str(&ri->un, str_un, sizeof(str_un)); |
d62a17ae | 2237 | p = index(str_un, '/'); |
2238 | if (p) | |
2239 | *p = 0; | |
2240 | ||
2241 | rfapiFormatSeconds(ri->lifetime, str_lifetime, BUFSIZ); | |
1e20238a | 2242 | #ifdef RFAPI_REGISTRATIONS_REPORT_AGE |
d62a17ae | 2243 | rfapiFormatAge(ri->last_sent_time, str_age, BUFSIZ); |
65efcfce | 2244 | #else |
d62a17ae | 2245 | { |
98b7e975 | 2246 | time_t now = monotime(NULL); |
d62a17ae | 2247 | time_t expire = |
2248 | ri->last_sent_time + (time_t)ri->lifetime; | |
2249 | /* allow for delayed/async removal */ | |
2250 | rfapiFormatSeconds((expire > now ? expire - now : 1), | |
2251 | str_age, BUFSIZ); | |
2252 | } | |
65efcfce LB |
2253 | #endif |
2254 | ||
4a8cd6ad | 2255 | fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %pRDP\n", |
d62a17ae | 2256 | deleted ? 'r' : ' ', *printedprefix ? "" : str_pfx, str_vn, |
c4f64ea9 | 2257 | str_un, ri->cost, str_lifetime, str_age, &ri->rk.rd); |
65efcfce | 2258 | |
d62a17ae | 2259 | if (!*printedprefix) |
2260 | *printedprefix = 1; | |
2261 | } | |
2262 | return routes_displayed; | |
65efcfce LB |
2263 | } |
2264 | ||
2265 | #if DEBUG_NHL | |
2266 | /* | |
2267 | * This one is for debugging (set stream to NULL to send output to log) | |
2268 | */ | |
d62a17ae | 2269 | static void rfapiRibShowRibSl(void *stream, struct prefix *pfx, |
2270 | struct skiplist *sl) | |
65efcfce | 2271 | { |
d62a17ae | 2272 | int (*fp)(void *, const char *, ...); |
2273 | struct vty *vty; | |
2274 | void *out; | |
2275 | const char *vty_newline; | |
65efcfce | 2276 | |
d62a17ae | 2277 | int nhs_displayed = 0; |
872ed4c7 | 2278 | char str_pfx[PREFIX_STRLEN]; |
d62a17ae | 2279 | int printedprefix = 0; |
65efcfce | 2280 | |
d62a17ae | 2281 | if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) |
2282 | return; | |
65efcfce | 2283 | |
872ed4c7 | 2284 | prefix2str(pfx, str_pfx, sizeof(str_pfx)); |
65efcfce | 2285 | |
d62a17ae | 2286 | nhs_displayed += |
2287 | print_rib_sl(fp, vty, out, sl, 0, str_pfx, &printedprefix); | |
65efcfce LB |
2288 | } |
2289 | #endif | |
2290 | ||
d62a17ae | 2291 | void rfapiRibShowResponses(void *stream, struct prefix *pfx_match, |
2292 | int show_removed) | |
65efcfce | 2293 | { |
d62a17ae | 2294 | int (*fp)(void *, const char *, ...); |
2295 | struct vty *vty; | |
2296 | void *out; | |
2297 | const char *vty_newline; | |
2298 | ||
2299 | struct rfapi_descriptor *rfd; | |
2300 | struct listnode *node; | |
2301 | ||
2302 | struct bgp *bgp = bgp_get_default(); | |
2303 | int printedheader = 0; | |
2304 | int routes_total = 0; | |
2305 | int nhs_total = 0; | |
2306 | int prefixes_total = 0; | |
2307 | int prefixes_displayed = 0; | |
2308 | int nves_total = 0; | |
2309 | int nves_with_routes = 0; | |
2310 | int nves_displayed = 0; | |
2311 | int routes_displayed = 0; | |
2312 | int nhs_displayed = 0; | |
2313 | ||
2314 | if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) | |
2315 | return; | |
9b86009a RW |
2316 | if (!bgp) { |
2317 | fp(out, "Unable to find default BGP instance\n"); | |
2318 | return; | |
2319 | } | |
2320 | ||
d62a17ae | 2321 | /* |
2322 | * loop over NVEs | |
2323 | */ | |
2324 | for (ALL_LIST_ELEMENTS_RO(&bgp->rfapi->descriptors, node, rfd)) { | |
2325 | ||
2326 | int printednve = 0; | |
2327 | afi_t afi; | |
2328 | ||
2329 | ++nves_total; | |
2330 | if (rfd->rib_prefix_count) | |
2331 | ++nves_with_routes; | |
2332 | ||
2333 | for (afi = AFI_IP; afi < AFI_MAX; ++afi) { | |
2334 | ||
fe08ba7e | 2335 | struct agg_node *rn; |
d62a17ae | 2336 | |
2337 | if (!rfd->rib[afi]) | |
2338 | continue; | |
2339 | ||
fe08ba7e DS |
2340 | for (rn = agg_route_top(rfd->rib[afi]); rn; |
2341 | rn = agg_route_next(rn)) { | |
26a3ffd6 DS |
2342 | const struct prefix *p = |
2343 | agg_node_get_prefix(rn); | |
d62a17ae | 2344 | struct skiplist *sl; |
872ed4c7 | 2345 | char str_pfx[PREFIX_STRLEN]; |
d62a17ae | 2346 | int printedprefix = 0; |
2347 | ||
2348 | if (!show_removed) | |
2349 | sl = rn->info; | |
2350 | else | |
2351 | sl = rn->aggregate; | |
2352 | ||
2353 | if (!sl) | |
2354 | continue; | |
2355 | ||
2356 | routes_total++; | |
2357 | nhs_total += skiplist_count(sl); | |
2358 | ++prefixes_total; | |
2359 | ||
26a3ffd6 DS |
2360 | if (pfx_match && !prefix_match(pfx_match, p) |
2361 | && !prefix_match(p, pfx_match)) | |
d62a17ae | 2362 | continue; |
2363 | ||
2364 | ++prefixes_displayed; | |
2365 | ||
2366 | if (!printedheader) { | |
2367 | ++printedheader; | |
2368 | ||
2369 | fp(out, "\n[%s]\n", | |
2370 | show_removed ? "Removed" : "Active"); | |
2371 | fp(out, "%-15s %-15s\n", "Querying VN", | |
2372 | "Querying UN"); | |
2373 | fp(out, | |
2374 | " %-20s %-15s %-15s %4s %-8s %-8s\n", | |
2375 | "Prefix", "Registered VN", | |
2376 | "Registered UN", "Cost", "Lifetime", | |
1e20238a | 2377 | #ifdef RFAPI_REGISTRATIONS_REPORT_AGE |
d62a17ae | 2378 | "Age" |
65efcfce | 2379 | #else |
d62a17ae | 2380 | "Remaining" |
65efcfce | 2381 | #endif |
1e20238a | 2382 | ); |
d62a17ae | 2383 | } |
2384 | if (!printednve) { | |
2385 | char str_vn[BUFSIZ]; | |
2386 | char str_un[BUFSIZ]; | |
2387 | ||
2388 | ++printednve; | |
2389 | ++nves_displayed; | |
2390 | ||
2391 | fp(out, "%-15s %-15s\n", | |
2392 | rfapiRfapiIpAddr2Str(&rfd->vn_addr, | |
2393 | str_vn, BUFSIZ), | |
2394 | rfapiRfapiIpAddr2Str(&rfd->un_addr, | |
2395 | str_un, | |
2396 | BUFSIZ)); | |
2397 | } | |
26a3ffd6 | 2398 | prefix2str(p, str_pfx, sizeof(str_pfx)); |
d62a17ae | 2399 | // fp(out, " %s\n", buf); /* prefix */ |
2400 | ||
2401 | routes_displayed++; | |
2402 | nhs_displayed += print_rib_sl( | |
2403 | fp, vty, out, sl, show_removed, str_pfx, | |
2404 | &printedprefix); | |
2405 | } | |
2406 | } | |
2407 | } | |
2408 | ||
2409 | if (routes_total) { | |
2410 | fp(out, "\n"); | |
2411 | fp(out, "Displayed %u NVEs, and %u out of %u %s prefixes", | |
2412 | nves_displayed, routes_displayed, routes_total, | |
2413 | show_removed ? "removed" : "active"); | |
2414 | if (nhs_displayed != routes_displayed | |
2415 | || nhs_total != routes_total) | |
2416 | fp(out, " with %u out of %u next hops", nhs_displayed, | |
2417 | nhs_total); | |
2418 | fp(out, "\n"); | |
2419 | } | |
65efcfce | 2420 | } |