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