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