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