]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/rfapi_import.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / bgpd / rfapi / rfapi_import.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_import.c
23 * Purpose: Handle import of routes from BGP to RFAPI
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/thread.h"
36
37 #include "bgpd/bgpd.h"
38 #include "bgpd/bgp_ecommunity.h"
39 #include "bgpd/bgp_attr.h"
40 #include "bgpd/bgp_route.h"
41 #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
42 #include "bgpd/bgp_vnc_types.h"
43
44 #include "bgpd/rfapi/rfapi.h"
45 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
46 #include "bgpd/rfapi/rfapi_backend.h"
47 #include "bgpd/rfapi/rfapi_import.h"
48 #include "bgpd/rfapi/rfapi_private.h"
49 #include "bgpd/rfapi/rfapi_monitor.h"
50 #include "bgpd/rfapi/rfapi_nve_addr.h"
51 #include "bgpd/rfapi/rfapi_vty.h"
52 #include "bgpd/rfapi/vnc_export_bgp.h"
53 #include "bgpd/rfapi/vnc_export_bgp_p.h"
54 #include "bgpd/rfapi/vnc_zebra.h"
55 #include "bgpd/rfapi/vnc_import_bgp.h"
56 #include "bgpd/rfapi/vnc_import_bgp_p.h"
57 #include "bgpd/rfapi/rfapi_rib.h"
58 #include "bgpd/rfapi/rfapi_encap_tlv.h"
59 #include "bgpd/rfapi/vnc_debug.h"
60
61 #ifdef HAVE_GLIBC_BACKTRACE
62 /* for backtrace and friends */
63 #include <execinfo.h>
64 #endif /* HAVE_GLIBC_BACKTRACE */
65
66 #undef DEBUG_MONITOR_MOVE_SHORTER
67 #undef DEBUG_RETURNED_NHL
68 #undef DEBUG_ROUTE_COUNTERS
69 #undef DEBUG_ENCAP_MONITOR
70 #undef DEBUG_L2_EXTRA
71 #undef DEBUG_IT_NODES
72 #undef DEBUG_BI_SEARCH
73
74 /*
75 * Allocated for each withdraw timer instance; freed when the timer
76 * expires or is canceled
77 */
78 struct rfapi_withdraw
79 {
80 struct rfapi_import_table *import_table;
81 struct route_node *node;
82 struct bgp_info *info;
83 safi_t safi; /* used only for bulk operations */
84 /*
85 * For import table node reference count checking (i.e., debugging).
86 * Normally when a timer expires, lockoffset should be 0. However, if
87 * the timer expiration function is called directly (e.g.,
88 * rfapiExpireVpnNow), the node could be locked by a preceding
89 * route_top() or route_next() in a loop, so we need to pass this
90 * value in.
91 */
92 int lockoffset;
93 };
94
95 /*
96 * DEBUG FUNCTION
97 * It's evil and fiendish. It's compiler-dependent.
98 * ? Might need LDFLAGS -rdynamic to produce all function names
99 */
100 void
101 rfapiDebugBacktrace (void)
102 {
103 #ifdef HAVE_GLIBC_BACKTRACE
104 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 200
105 void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES];
106 char **syms;
107 size_t i;
108 size_t size;
109
110 size = backtrace (buf, RFAPI_DEBUG_BACKTRACE_NENTRIES);
111 syms = backtrace_symbols (buf, size);
112
113 for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i)
114 {
115 vnc_zlog_debug_verbose ("backtrace[%2zu]: %s", i, syms[i]);
116 }
117
118 free (syms);
119 #else
120 #endif
121 }
122
123 /*
124 * DEBUG FUNCTION
125 * Count remote routes and compare with actively-maintained values.
126 * Abort if they disagree.
127 */
128 void
129 rfapiCheckRouteCount ()
130 {
131 struct bgp *bgp = bgp_get_default ();
132 struct rfapi *h;
133 struct rfapi_import_table *it;
134 afi_t afi;
135
136 assert (bgp);
137
138 h = bgp->rfapi;
139 assert (h);
140
141 for (it = h->imports; it; it = it->next)
142 {
143 for (afi = AFI_IP; afi < AFI_MAX; ++afi)
144 {
145
146 struct route_table *rt;
147 struct route_node *rn;
148
149 int holddown_count = 0;
150 int local_count = 0;
151 int imported_count = 0;
152 int remote_count = 0;
153
154 rt = it->imported_vpn[afi];
155
156 for (rn = route_top (rt); rn; rn = route_next (rn))
157 {
158 struct bgp_info *bi;
159 struct bgp_info *next;
160
161 for (bi = rn->info; bi; bi = next)
162 {
163 next = bi->next;
164
165 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
166 {
167 ++holddown_count;
168
169 }
170 else
171 {
172 if (RFAPI_LOCAL_BI (bi))
173 {
174 ++local_count;
175 }
176 else
177 {
178 if (RFAPI_DIRECT_IMPORT_BI (bi))
179 {
180 ++imported_count;
181 }
182 else
183 {
184 ++remote_count;
185 }
186 }
187 }
188 }
189 }
190
191 if (it->holddown_count[afi] != holddown_count)
192 {
193 vnc_zlog_debug_verbose ("%s: it->holddown_count %d != holddown_count %d",
194 __func__, it->holddown_count[afi], holddown_count);
195 assert (0);
196 }
197 if (it->remote_count[afi] != remote_count)
198 {
199 vnc_zlog_debug_verbose ("%s: it->remote_count %d != remote_count %d",
200 __func__, it->remote_count[afi], remote_count);
201 assert (0);
202 }
203 if (it->imported_count[afi] != imported_count)
204 {
205 vnc_zlog_debug_verbose ("%s: it->imported_count %d != imported_count %d",
206 __func__, it->imported_count[afi], imported_count);
207 assert (0);
208 }
209 }
210 }
211 }
212
213 #if DEBUG_ROUTE_COUNTERS
214 #define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
215 #else
216 #define VNC_ITRCCK
217 #endif
218
219 /*
220 * Validate reference count for a node in an import table
221 *
222 * Normally lockoffset is 0 for nodes in quiescent state. However,
223 * route_unlock_node will delete the node if it is called when
224 * node->lock == 1, and we have to validate the refcount before
225 * the node is deleted. In this case, we specify lockoffset 1.
226 */
227 void
228 rfapiCheckRefcount (struct route_node *rn, safi_t safi, int lockoffset)
229 {
230 unsigned int count_bi = 0;
231 unsigned int count_monitor = 0;
232 struct bgp_info *bi;
233 struct rfapi_monitor_encap *hme;
234 struct rfapi_monitor_vpn *hmv;
235
236 for (bi = rn->info; bi; bi = bi->next)
237 ++count_bi;
238
239
240 if (rn->aggregate)
241 {
242 ++count_monitor; /* rfapi_it_extra */
243
244 switch (safi)
245 {
246 void *cursor;
247 int rc;
248
249 case SAFI_ENCAP:
250 for (hme = RFAPI_MONITOR_ENCAP (rn); hme; hme = hme->next)
251 ++count_monitor;
252 break;
253
254 case SAFI_MPLS_VPN:
255
256 for (hmv = RFAPI_MONITOR_VPN (rn); hmv; hmv = hmv->next)
257 ++count_monitor;
258
259 if (RFAPI_MONITOR_EXTERIOR (rn)->source)
260 {
261 ++count_monitor; /* sl */
262 cursor = NULL;
263 for (rc = skiplist_next (RFAPI_MONITOR_EXTERIOR (rn)->source,
264 NULL, NULL, &cursor);
265 !rc;
266 rc = skiplist_next (RFAPI_MONITOR_EXTERIOR (rn)->source,
267 NULL, NULL, &cursor))
268 {
269
270 ++count_monitor; /* sl entry */
271 }
272 }
273 break;
274
275 default:
276 assert (0);
277 }
278 }
279
280 if (count_bi + count_monitor + lockoffset != rn->lock)
281 {
282 vnc_zlog_debug_verbose
283 ("%s: count_bi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
284 __func__, count_bi, count_monitor, lockoffset, rn->lock);
285 assert (0);
286 }
287 }
288
289 /*
290 * Perform deferred rfapi_close operations that were queued
291 * during callbacks.
292 */
293 static wq_item_status
294 rfapi_deferred_close_workfunc (struct work_queue *q, void *data)
295 {
296 struct rfapi_descriptor *rfd = data;
297 struct rfapi *h = q->spec.data;
298
299 assert (!(h->flags & RFAPI_INCALLBACK));
300 rfapi_close (rfd);
301 vnc_zlog_debug_verbose ("%s: completed deferred close on handle %p", __func__, rfd);
302 return WQ_SUCCESS;
303 }
304
305 /*
306 * Extract layer 2 option from Encap TLVS in BGP attrs
307 */
308 int
309 rfapiGetL2o (struct attr *attr, struct rfapi_l2address_option *l2o)
310 {
311 if (attr && attr->extra)
312 {
313
314 struct bgp_attr_encap_subtlv *pEncap;
315
316 for (pEncap = attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next)
317 {
318
319 if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION)
320 {
321 if (pEncap->value[0] == RFAPI_VN_OPTION_TYPE_L2ADDR)
322 {
323
324 if (pEncap->value[1] == 14)
325 {
326 memcpy (l2o->macaddr.octet, pEncap->value + 2,
327 ETHER_ADDR_LEN);
328 l2o->label =
329 ((pEncap->value[10] >> 4) & 0x0f) +
330 ((pEncap->value[9] << 4) & 0xff0) +
331 ((pEncap->value[8] << 12) & 0xff000);
332
333 l2o->local_nve_id = pEncap->value[12];
334
335 l2o->logical_net_id =
336 (pEncap->value[15] & 0xff) +
337 ((pEncap->value[14] << 8) & 0xff00) +
338 ((pEncap->value[13] << 16) & 0xff0000);
339 }
340
341 return 0;
342 }
343 }
344 }
345 }
346
347 return ENOENT;
348 }
349
350 /*
351 * Extract the lifetime from the Tunnel Encap attribute of a route in
352 * an import table
353 */
354 int
355 rfapiGetVncLifetime (struct attr *attr, uint32_t * lifetime)
356 {
357 struct bgp_attr_encap_subtlv *pEncap;
358
359 *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */
360
361 if (attr && attr->extra)
362 {
363
364 for (pEncap = attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next)
365 {
366
367 if (pEncap->type == BGP_VNC_SUBTLV_TYPE_LIFETIME)
368 { /* lifetime */
369 if (pEncap->length == 4)
370 {
371 memcpy (lifetime, pEncap->value, 4);
372 *lifetime = ntohl (*lifetime);
373 return 0;
374 }
375 }
376 }
377 }
378
379 return ENOENT;
380 }
381
382 /*
383 * Extract the tunnel type from the extended community
384 */
385 int
386 rfapiGetTunnelType (struct attr *attr,
387 bgp_encap_types *type)
388 {
389 *type = BGP_ENCAP_TYPE_MPLS; /* default to MPLS */
390 if (attr && attr->extra && attr->extra->ecommunity)
391 {
392 struct ecommunity *ecom = attr->extra->ecommunity;
393 int i;
394
395 for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE)
396 {
397 uint8_t *ep;
398
399 ep = ecom->val + i;
400 if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE &&
401 ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
402 {
403 *type = (ep[6]<<8) + ep[7];
404 return 0;
405 }
406 }
407 }
408
409 return ENOENT;
410 }
411
412
413 /*
414 * Look for UN address in Encap attribute
415 */
416 int
417 rfapiGetVncTunnelUnAddr (struct attr *attr, struct prefix *p)
418 {
419 struct bgp_attr_encap_subtlv *pEncap;
420 bgp_encap_types tun_type;
421
422 rfapiGetTunnelType (attr, &tun_type);
423 if (tun_type == BGP_ENCAP_TYPE_MPLS)
424 {
425 if (!p)
426 return 0;
427 /* MPLS carries UN address in next hop */
428 rfapiNexthop2Prefix (attr, p);
429 if (p->family != 0)
430 return 0;
431
432 return ENOENT;
433 }
434 if (attr && attr->extra)
435 {
436 for (pEncap = attr->extra->encap_subtlvs; pEncap; pEncap = pEncap->next)
437 {
438
439 if (pEncap->type == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT)
440 { /* un addr */
441 switch (pEncap->length)
442 {
443 case 8:
444 if (p)
445 {
446 p->family = AF_INET;
447 p->prefixlen = 32;
448 memcpy (p->u.val, pEncap->value, 4);
449 }
450 return 0;
451
452 case 20:
453 if (p)
454 {
455 p->family = AF_INET6;
456 p->prefixlen = 128;
457 memcpy (p->u.val, pEncap->value, 16);
458 }
459 return 0;
460 }
461 }
462 }
463 }
464
465 return ENOENT;
466 }
467
468 /*
469 * Get UN address wherever it might be
470 */
471 int
472 rfapiGetUnAddrOfVpnBi (struct bgp_info *bi, struct prefix *p)
473 {
474 /* If it's in this route's VNC attribute, we're done */
475 if (!rfapiGetVncTunnelUnAddr (bi->attr, p))
476 return 0;
477 /*
478 * Otherwise, see if it's cached from a corresponding ENCAP SAFI
479 * advertisement
480 */
481 if (bi->extra)
482 {
483 switch (bi->extra->vnc.import.un_family)
484 {
485 case AF_INET:
486 if (p)
487 {
488 p->family = bi->extra->vnc.import.un_family;
489 p->u.prefix4 = bi->extra->vnc.import.un.addr4;
490 p->prefixlen = 32;
491 }
492 return 0;
493 case AF_INET6:
494 if (p)
495 {
496 p->family = bi->extra->vnc.import.un_family;
497 p->u.prefix6 = bi->extra->vnc.import.un.addr6;
498 p->prefixlen = 128;
499 }
500 return 0;
501 default:
502 if (p)
503 p->family = 0;
504 #if DEBUG_ENCAP_MONITOR
505 vnc_zlog_debug_verbose ("%s: bi->extra->vnc.import.un_family is 0, no UN addr",
506 __func__);
507 #endif
508 break;
509 }
510 }
511
512 return ENOENT;
513 }
514
515
516 /*
517 * Make a new bgp_info from gathered parameters
518 */
519 static struct bgp_info *
520 rfapiBgpInfoCreate (
521 struct attr *attr,
522 struct peer *peer,
523 void *rfd,
524 struct prefix_rd *prd,
525 u_char type,
526 u_char sub_type,
527 uint32_t *label)
528 {
529 struct bgp_info *new;
530
531 new = bgp_info_new ();
532 assert (new);
533
534 if (attr)
535 {
536 if (!new->attr)
537 new->attr = bgp_attr_intern (attr);
538 }
539 bgp_info_extra_get (new);
540 if (prd)
541 {
542 new->extra->vnc.import.rd = *prd;
543 rfapi_time (&new->extra->vnc.import.create_time);
544 }
545 if (label)
546 encode_label (*label, new->extra->tag);
547 new->type = type;
548 new->sub_type = sub_type;
549 new->peer = peer;
550 peer_lock (peer);
551
552 return new;
553 }
554
555 /*
556 * Frees bgp_info as used in import tables (parts are not
557 * allocated exactly the way they are in the main RIBs)
558 */
559 static void
560 rfapiBgpInfoFree (struct bgp_info *goner)
561 {
562 if (!goner)
563 return;
564
565 if (goner->peer)
566 {
567 vnc_zlog_debug_verbose ("%s: calling peer_unlock(%p), #%d",
568 __func__, goner->peer, goner->peer->lock);
569 peer_unlock (goner->peer);
570 }
571
572 if (goner->attr)
573 {
574 bgp_attr_unintern (&goner->attr);
575 }
576 if (goner->extra)
577 {
578 assert (!goner->extra->damp_info); /* Not used in import tbls */
579 XFREE (MTYPE_BGP_ROUTE_EXTRA, goner->extra);
580 goner->extra = NULL;
581 }
582 XFREE (MTYPE_BGP_ROUTE, goner);
583 }
584
585 struct rfapi_import_table *
586 rfapiMacImportTableGetNoAlloc (struct bgp *bgp, uint32_t lni)
587 {
588 struct rfapi *h;
589 struct rfapi_import_table *it = NULL;
590 uintptr_t lni_as_ptr = lni;
591
592 h = bgp->rfapi;
593 if (!h)
594 return NULL;
595
596 if (!h->import_mac)
597 return NULL;
598
599 if (skiplist_search (h->import_mac, (void *) lni_as_ptr, (void **) &it))
600 return NULL;
601
602 return it;
603 }
604
605 struct rfapi_import_table *
606 rfapiMacImportTableGet (struct bgp *bgp, uint32_t lni)
607 {
608 struct rfapi *h;
609 struct rfapi_import_table *it = NULL;
610 uintptr_t lni_as_ptr = lni;
611
612 h = bgp->rfapi;
613 assert (h);
614
615 if (!h->import_mac)
616 {
617 /* default cmp is good enough for LNI */
618 h->import_mac = skiplist_new (0, NULL, NULL);
619 }
620
621 if (skiplist_search (h->import_mac, (void *) lni_as_ptr, (void **) &it))
622 {
623
624 struct ecommunity *enew;
625 struct ecommunity_val eval;
626 afi_t afi;
627
628 it =
629 XCALLOC (MTYPE_RFAPI_IMPORTTABLE, sizeof (struct rfapi_import_table));
630 /* set RT list of new import table based on LNI */
631 memset ((char *) &eval, 0, sizeof (eval));
632 eval.val[0] = 0; /* VNC L2VPN */
633 eval.val[1] = 2; /* VNC L2VPN */
634 eval.val[5] = (lni >> 16) & 0xff;
635 eval.val[6] = (lni >> 8) & 0xff;
636 eval.val[7] = (lni >> 0) & 0xff;
637
638 enew = ecommunity_new ();
639 ecommunity_add_val (enew, &eval);
640 it->rt_import_list = enew;
641
642 for (afi = AFI_IP; afi < AFI_MAX; ++afi)
643 {
644 it->imported_vpn[afi] = route_table_init ();
645 it->imported_encap[afi] = route_table_init ();
646 }
647
648 it->l2_logical_net_id = lni;
649
650 skiplist_insert (h->import_mac, (void *) lni_as_ptr, it);
651 }
652
653 assert (it);
654 return it;
655 }
656
657 /*
658 * Implement MONITOR_MOVE_SHORTER(original_node) from
659 * RFAPI-Import-Event-Handling.txt
660 *
661 * Returns pointer to the list of moved monitors
662 */
663 static struct rfapi_monitor_vpn *
664 rfapiMonitorMoveShorter (struct route_node *original_vpn_node, int lockoffset)
665 {
666 struct bgp_info *bi;
667 struct route_node *par;
668 struct rfapi_monitor_vpn *m;
669 struct rfapi_monitor_vpn *mlast;
670 struct rfapi_monitor_vpn *moved;
671 int movecount = 0;
672 int parent_already_refcounted = 0;
673
674 RFAPI_CHECK_REFCOUNT (original_vpn_node, SAFI_MPLS_VPN, lockoffset);
675
676 #if DEBUG_MONITOR_MOVE_SHORTER
677 {
678 char buf[BUFSIZ];
679
680 prefix2str (&original_vpn_node->p, buf, BUFSIZ);
681 buf[BUFSIZ - 1] = 0;
682 vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__, buf);
683 }
684 #endif
685
686 /*
687 * 1. If there is at least one bi (either regular route or
688 * route marked as withdrawn, with a pending timer) at
689 * original_node with a valid UN address, we're done. Return.
690 */
691 for (bi = original_vpn_node->info; bi; bi = bi->next)
692 {
693 struct prefix pfx;
694
695 if (!rfapiGetUnAddrOfVpnBi (bi, &pfx))
696 {
697 #if DEBUG_MONITOR_MOVE_SHORTER
698 vnc_zlog_debug_verbose ("%s: have valid UN at original node, no change",
699 __func__);
700 #endif
701 return NULL;
702 }
703 }
704
705 /*
706 * 2. Travel up the tree (toward less-specific prefixes) from
707 * original_node to find the first node that has at least
708 * one route (even if it is only a withdrawn route) with a
709 * valid UN address. Call this node "Node P."
710 */
711 for (par = original_vpn_node->parent; par; par = par->parent)
712 {
713 for (bi = par->info; bi; bi = bi->next)
714 {
715 struct prefix pfx;
716 if (!rfapiGetUnAddrOfVpnBi (bi, &pfx))
717 {
718 break;
719 }
720 }
721 if (bi)
722 break;
723 }
724
725 if (par)
726 {
727 RFAPI_CHECK_REFCOUNT (par, SAFI_MPLS_VPN, 0);
728 }
729
730 /*
731 * If no less-specific routes, try to use the 0/0 node
732 */
733 if (!par)
734 {
735 /* this isn't necessarily 0/0 */
736 par = route_top (original_vpn_node->table);
737
738 /*
739 * If we got the top node but it wasn't 0/0,
740 * ignore it
741 */
742 if (par && par->p.prefixlen)
743 {
744 route_unlock_node (par); /* maybe free */
745 par = NULL;
746 }
747
748 if (par)
749 {
750 ++parent_already_refcounted;
751 }
752 }
753
754 /*
755 * Create 0/0 node if it isn't there
756 */
757 if (!par)
758 {
759 struct prefix pfx_default;
760
761 memset (&pfx_default, 0, sizeof (pfx_default));
762 pfx_default.family = original_vpn_node->p.family;
763
764 /* creates default node if none exists */
765 par = route_node_get (original_vpn_node->table, &pfx_default);
766 ++parent_already_refcounted;
767 }
768
769 /*
770 * 3. Move each of the monitors found at original_node to Node P.
771 * These are "Moved Monitors."
772 *
773 */
774
775 /*
776 * Attach at end so that the list pointer we return points
777 * only to the moved routes
778 */
779 for (m = RFAPI_MONITOR_VPN (par), mlast = NULL; m; mlast = m, m = m->next);
780
781 if (mlast)
782 {
783 moved = mlast->next = RFAPI_MONITOR_VPN (original_vpn_node);
784 }
785 else
786 {
787 moved = RFAPI_MONITOR_VPN_W_ALLOC (par) =
788 RFAPI_MONITOR_VPN (original_vpn_node);
789 }
790 if (RFAPI_MONITOR_VPN (original_vpn_node)) /* check agg, so not allocated */
791 RFAPI_MONITOR_VPN_W_ALLOC (original_vpn_node) = NULL;
792
793 /*
794 * update the node pointers on the monitors
795 */
796 for (m = moved; m; m = m->next)
797 {
798 ++movecount;
799 m->node = par;
800 }
801
802 RFAPI_CHECK_REFCOUNT (par, SAFI_MPLS_VPN,
803 parent_already_refcounted - movecount);
804 while (movecount > parent_already_refcounted)
805 {
806 route_lock_node (par);
807 ++parent_already_refcounted;
808 }
809 while (movecount < parent_already_refcounted)
810 {
811 /* unlikely, but code defensively */
812 route_unlock_node (par);
813 --parent_already_refcounted;
814 }
815 RFAPI_CHECK_REFCOUNT (original_vpn_node, SAFI_MPLS_VPN,
816 movecount + lockoffset);
817 while (movecount--)
818 {
819 route_unlock_node (original_vpn_node);
820 }
821
822 #if DEBUG_MONITOR_MOVE_SHORTER
823 {
824 char buf[BUFSIZ];
825
826 prefix2str (&par->p, buf, BUFSIZ);
827 buf[BUFSIZ - 1] = 0;
828 vnc_zlog_debug_verbose ("%s: moved to node pfx=%s", __func__, buf);
829 }
830 #endif
831
832
833 return moved;
834 }
835
836 /*
837 * Implement MONITOR_MOVE_LONGER(new_node) from
838 * RFAPI-Import-Event-Handling.txt
839 */
840 static void
841 rfapiMonitorMoveLonger (struct route_node *new_vpn_node)
842 {
843 struct rfapi_monitor_vpn *monitor;
844 struct rfapi_monitor_vpn *mlast;
845 struct bgp_info *bi;
846 struct route_node *par;
847
848 RFAPI_CHECK_REFCOUNT (new_vpn_node, SAFI_MPLS_VPN, 0);
849
850 /*
851 * Make sure we have at least one valid route at the new node
852 */
853 for (bi = new_vpn_node->info; bi; bi = bi->next)
854 {
855 struct prefix pfx;
856 if (!rfapiGetUnAddrOfVpnBi (bi, &pfx))
857 break;
858 }
859
860 if (!bi)
861 {
862 vnc_zlog_debug_verbose ("%s: no valid routes at node %p, so not attempting moves",
863 __func__, new_vpn_node);
864 return;
865 }
866
867 /*
868 * Find first parent node that has monitors
869 */
870 for (par = new_vpn_node->parent; par; par = par->parent)
871 {
872 if (RFAPI_MONITOR_VPN (par))
873 break;
874 }
875
876 if (!par)
877 {
878 vnc_zlog_debug_verbose ("%s: no parent nodes with monitors, done", __func__);
879 return;
880 }
881
882 /*
883 * Check each of these monitors to see of their longest-match
884 * is now the updated node. Move any such monitors to the more-
885 * specific updated node
886 */
887 for (mlast = NULL, monitor = RFAPI_MONITOR_VPN (par); monitor;)
888 {
889
890 /*
891 * If new longest match for monitor prefix is the new
892 * route's prefix, move monitor to new route's prefix
893 */
894 if (prefix_match (&new_vpn_node->p, &monitor->p))
895 {
896 /* detach */
897 if (mlast)
898 {
899 mlast->next = monitor->next;
900 }
901 else
902 {
903 RFAPI_MONITOR_VPN_W_ALLOC (par) = monitor->next;
904 }
905
906
907 /* attach */
908 monitor->next = RFAPI_MONITOR_VPN (new_vpn_node);
909 RFAPI_MONITOR_VPN_W_ALLOC (new_vpn_node) = monitor;
910 monitor->node = new_vpn_node;
911
912 route_lock_node (new_vpn_node); /* incr refcount */
913
914 monitor = mlast ? mlast->next : RFAPI_MONITOR_VPN (par);
915
916 RFAPI_CHECK_REFCOUNT (par, SAFI_MPLS_VPN, 1);
917 /* decr refcount after we're done with par as this might free it */
918 route_unlock_node (par);
919
920 continue;
921 }
922 mlast = monitor;
923 monitor = monitor->next;
924 }
925
926 RFAPI_CHECK_REFCOUNT (new_vpn_node, SAFI_MPLS_VPN, 0);
927 }
928
929
930 static void
931 rfapiBgpInfoChainFree (struct bgp_info *bi)
932 {
933 struct bgp_info *next;
934
935 while (bi)
936 {
937
938 /*
939 * If there is a timer waiting to delete this bi, cancel
940 * the timer and delete immediately
941 */
942 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) &&
943 bi->extra->vnc.import.timer)
944 {
945
946 struct thread *t = (struct thread *) bi->extra->vnc.import.timer;
947 struct rfapi_withdraw *wcb = t->arg;
948
949 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
950 thread_cancel (t);
951 }
952
953 next = bi->next;
954 bi->next = NULL;
955 rfapiBgpInfoFree (bi);
956 bi = next;
957 }
958 }
959
960 static void
961 rfapiImportTableFlush (struct rfapi_import_table *it)
962 {
963 afi_t afi;
964
965 /*
966 * Free ecommunity
967 */
968 ecommunity_free (&it->rt_import_list);
969 it->rt_import_list = NULL;
970
971 for (afi = AFI_IP; afi < AFI_MAX; ++afi)
972 {
973
974 struct route_node *rn;
975
976 for (rn = route_top (it->imported_vpn[afi]); rn; rn = route_next (rn))
977 {
978 /*
979 * Each route_node has:
980 * aggregate: points to rfapi_it_extra with monitor chain(s)
981 * info: points to chain of bgp_info
982 */
983 /* free bgp_info and its children */
984 rfapiBgpInfoChainFree (rn->info);
985 rn->info = NULL;
986
987 rfapiMonitorExtraFlush (SAFI_MPLS_VPN, rn);
988 }
989
990 for (rn = route_top (it->imported_encap[afi]); rn; rn = route_next (rn))
991 {
992 /* free bgp_info and its children */
993 rfapiBgpInfoChainFree (rn->info);
994 rn->info = NULL;
995
996 rfapiMonitorExtraFlush (SAFI_ENCAP, rn);
997 }
998
999 route_table_finish (it->imported_vpn[afi]);
1000 route_table_finish (it->imported_encap[afi]);
1001 }
1002 if (it->monitor_exterior_orphans)
1003 {
1004 skiplist_free (it->monitor_exterior_orphans);
1005 }
1006 }
1007
1008 void
1009 rfapiImportTableRefDelByIt (
1010 struct bgp *bgp,
1011 struct rfapi_import_table *it_target)
1012 {
1013 struct rfapi *h;
1014 struct rfapi_import_table *it;
1015 struct rfapi_import_table *prev = NULL;
1016
1017 assert (it_target);
1018
1019 h = bgp->rfapi;
1020 assert (h);
1021
1022 for (it = h->imports; it; prev = it, it = it->next)
1023 {
1024 if (it == it_target)
1025 break;
1026 }
1027
1028 assert (it);
1029 assert (it->refcount);
1030
1031 it->refcount -= 1;
1032
1033 if (!it->refcount)
1034 {
1035 if (prev)
1036 {
1037 prev->next = it->next;
1038 }
1039 else
1040 {
1041 h->imports = it->next;
1042 }
1043 rfapiImportTableFlush (it);
1044 XFREE (MTYPE_RFAPI_IMPORTTABLE, it);
1045 }
1046 }
1047
1048 #if RFAPI_REQUIRE_ENCAP_BEEC
1049 /*
1050 * Look for magic BGP Encapsulation Extended Community value
1051 * Format in RFC 5512 Sect. 4.5
1052 */
1053 static int
1054 rfapiEcommunitiesMatchBeec (struct ecommunity *ecom,
1055 bgp_encap_types type)
1056 {
1057 int i;
1058
1059 if (!ecom)
1060 return 0;
1061
1062 for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE)
1063 {
1064
1065 uint8_t *ep;
1066
1067 ep = ecom->val + i;
1068
1069 if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE &&
1070 ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP &&
1071 ep[6] == ((type && 0xff00)>>8) &&
1072 ep[7] == (type&0xff))
1073 {
1074
1075 return 1;
1076 }
1077 }
1078 return 0;
1079
1080 }
1081 #endif
1082
1083 int
1084 rfapiEcommunitiesIntersect (struct ecommunity *e1, struct ecommunity *e2)
1085 {
1086 int i, j;
1087
1088 if (!e1 || !e2)
1089 return 0;
1090
1091 {
1092 char *s1, *s2;
1093 s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, 0);
1094 s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, 0);
1095 vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__, s1, s2);
1096 XFREE (MTYPE_ECOMMUNITY_STR, s1);
1097 XFREE (MTYPE_ECOMMUNITY_STR, s2);
1098 }
1099
1100 for (i = 0; i < e1->size; ++i)
1101 {
1102 for (j = 0; j < e2->size; ++j)
1103 {
1104 if (!memcmp (e1->val + (i * ECOMMUNITY_SIZE),
1105 e2->val + (j * ECOMMUNITY_SIZE), ECOMMUNITY_SIZE))
1106 {
1107
1108 return 1;
1109 }
1110 }
1111 }
1112 return 0;
1113 }
1114
1115 int
1116 rfapiEcommunityGetLNI (struct ecommunity *ecom, uint32_t * lni)
1117 {
1118 if (ecom)
1119 {
1120 int i;
1121 for (i = 0; i < ecom->size; ++i)
1122 {
1123 uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
1124
1125 if ((*(p + 0) == 0x00) && (*(p + 1) == 0x02))
1126 {
1127
1128 *lni = (*(p + 5) << 16) | (*(p + 6) << 8) | (*(p + 7));
1129 return 0;
1130 }
1131 }
1132 }
1133 return ENOENT;
1134 }
1135
1136 int
1137 rfapiEcommunityGetEthernetTag (struct ecommunity *ecom, uint16_t * tag_id)
1138 {
1139 struct bgp *bgp = bgp_get_default ();
1140 *tag_id = 0; /* default to untagged */
1141 if (ecom)
1142 {
1143 int i;
1144 for (i = 0; i < ecom->size; ++i)
1145 {
1146 as_t as = 0;
1147 int encode = 0;
1148 uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
1149
1150 /* High-order octet of type. */
1151 encode = *p++;
1152
1153 if (*p++ == ECOMMUNITY_ROUTE_TARGET) {
1154 if (encode == ECOMMUNITY_ENCODE_AS4)
1155 {
1156 as = (*p++ << 24);
1157 as |= (*p++ << 16);
1158 as |= (*p++ << 8);
1159 as |= (*p++);
1160 }
1161 else if (encode == ECOMMUNITY_ENCODE_AS)
1162 {
1163 as = (*p++ << 8);
1164 as |= (*p++);
1165 p += 2; /* skip next two, tag/vid always in lowest bytes */
1166 }
1167 if (as == bgp->as)
1168 {
1169 *tag_id = *p++ << 8;
1170 *tag_id |= (*p++);
1171 return 0;
1172 }
1173 }
1174 }
1175 }
1176 return ENOENT;
1177 }
1178
1179 static int
1180 rfapiVpnBiNhEqualsPt (struct bgp_info *bi, struct rfapi_ip_addr *hpt)
1181 {
1182 uint8_t family;
1183
1184 if (!hpt || !bi)
1185 return 0;
1186
1187 family = BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len);
1188
1189 if (hpt->addr_family != family)
1190 return 0;
1191
1192 switch (family)
1193 {
1194 case AF_INET:
1195 if (bi->attr->extra->mp_nexthop_global_in.s_addr != hpt->addr.v4.s_addr)
1196 return 0;
1197 break;
1198
1199 case AF_INET6:
1200 if (IPV6_ADDR_CMP (&bi->attr->extra->mp_nexthop_global, &hpt->addr.v6))
1201 return 0;
1202 break;
1203
1204 default:
1205 return 0;
1206 break;
1207 }
1208
1209 return 1;
1210 }
1211
1212
1213 /*
1214 * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
1215 */
1216 static int
1217 rfapiVpnBiSamePtUn (struct bgp_info *bi1, struct bgp_info *bi2)
1218 {
1219 struct prefix pfx_un1;
1220 struct prefix pfx_un2;
1221
1222 if (!bi1 || !bi2)
1223 return 0;
1224
1225 if (!bi1->attr || !bi2->attr)
1226 return 0;
1227
1228 if (!bi1->attr->extra || !bi2->attr->extra)
1229 return 0;
1230
1231 /*
1232 * VN address comparisons
1233 */
1234
1235 if (BGP_MP_NEXTHOP_FAMILY (bi1->attr->extra->mp_nexthop_len) !=
1236 BGP_MP_NEXTHOP_FAMILY (bi2->attr->extra->mp_nexthop_len))
1237 {
1238 return 0;
1239 }
1240
1241 switch (BGP_MP_NEXTHOP_FAMILY (bi1->attr->extra->mp_nexthop_len))
1242 {
1243
1244 case AF_INET:
1245 if (bi1->attr->extra->mp_nexthop_global_in.s_addr !=
1246 bi2->attr->extra->mp_nexthop_global_in.s_addr)
1247 return 0;
1248 break;
1249
1250 case AF_INET6:
1251 if (IPV6_ADDR_CMP (&bi1->attr->extra->mp_nexthop_global,
1252 &bi2->attr->extra->mp_nexthop_global))
1253 return 0;
1254 break;
1255
1256 default:
1257 return 0;
1258 break;
1259 }
1260
1261 /*
1262 * UN address comparisons
1263 */
1264 if (rfapiGetVncTunnelUnAddr (bi1->attr, &pfx_un1))
1265 {
1266 if (bi1->extra)
1267 {
1268 pfx_un1.family = bi1->extra->vnc.import.un_family;
1269 switch (bi1->extra->vnc.import.un_family)
1270 {
1271 case AF_INET:
1272 pfx_un1.u.prefix4 = bi1->extra->vnc.import.un.addr4;
1273 break;
1274 case AF_INET6:
1275 pfx_un1.u.prefix6 = bi1->extra->vnc.import.un.addr6;
1276 break;
1277 default:
1278 pfx_un1.family = 0;
1279 break;
1280 }
1281 }
1282 }
1283
1284 if (rfapiGetVncTunnelUnAddr (bi2->attr, &pfx_un2))
1285 {
1286 if (bi2->extra)
1287 {
1288 pfx_un2.family = bi2->extra->vnc.import.un_family;
1289 switch (bi2->extra->vnc.import.un_family)
1290 {
1291 case AF_INET:
1292 pfx_un2.u.prefix4 = bi2->extra->vnc.import.un.addr4;
1293 break;
1294 case AF_INET6:
1295 pfx_un2.u.prefix6 = bi2->extra->vnc.import.un.addr6;
1296 break;
1297 default:
1298 pfx_un2.family = 0;
1299 break;
1300 }
1301 }
1302 }
1303
1304 if (!pfx_un1.family || !pfx_un2.family)
1305 return 0;
1306
1307 if (pfx_un1.family != pfx_un2.family)
1308 return 0;
1309
1310 switch (pfx_un1.family)
1311 {
1312 case AF_INET:
1313 if (!IPV4_ADDR_SAME
1314 (&pfx_un1.u.prefix4.s_addr, &pfx_un2.u.prefix4.s_addr))
1315 return 0;
1316 break;
1317 case AF_INET6:
1318 if (!IPV6_ADDR_SAME (&pfx_un1.u.prefix6, &pfx_un2.u.prefix6))
1319 return 0;
1320 break;
1321 }
1322
1323
1324
1325 return 1;
1326 }
1327
1328 uint8_t
1329 rfapiRfpCost (struct attr * attr)
1330 {
1331 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1332 {
1333 if (attr->local_pref > 255)
1334 {
1335 return 0;
1336 }
1337 return 255 - attr->local_pref;
1338 }
1339
1340 return 255;
1341 }
1342
1343 /*------------------------------------------
1344 * rfapi_extract_l2o
1345 *
1346 * Find Layer 2 options in an option chain
1347 *
1348 * input:
1349 * pHop option chain
1350 *
1351 * output:
1352 * l2o layer 2 options extracted
1353 *
1354 * return value:
1355 * 0 OK
1356 * 1 no options found
1357 *
1358 --------------------------------------------*/
1359 int
1360 rfapi_extract_l2o (struct bgp_tea_options *pHop, /* chain of options */
1361 struct rfapi_l2address_option *l2o) /* return extracted value */
1362 {
1363 struct bgp_tea_options *p;
1364
1365 for (p = pHop; p; p = p->next)
1366 {
1367 if ((p->type == RFAPI_VN_OPTION_TYPE_L2ADDR) && (p->length >= 8))
1368 {
1369
1370 char *v = p->value;
1371
1372 memcpy (&l2o->macaddr, v, 6);
1373
1374 l2o->label =
1375 ((v[6] << 12) & 0xff000) +
1376 ((v[7] << 4) & 0xff0) + ((v[8] >> 4) & 0xf);
1377
1378 l2o->local_nve_id = (uint8_t) v[10];
1379
1380 l2o->logical_net_id = (v[11] << 16) + (v[12] << 8) + (v[13] << 0);
1381
1382 return 0;
1383 }
1384 }
1385 return 1;
1386 }
1387
1388 static struct rfapi_next_hop_entry *
1389 rfapiRouteInfo2NextHopEntry (
1390 struct rfapi_ip_prefix *rprefix,
1391 struct bgp_info *bi, /* route to encode */
1392 uint32_t lifetime, /* use this in nhe */
1393 struct route_node *rn) /* req for L2 eth addr */
1394 {
1395 struct rfapi_next_hop_entry *new;
1396 int have_vnc_tunnel_un = 0;
1397
1398 #if DEBUG_ENCAP_MONITOR
1399 vnc_zlog_debug_verbose ("%s: entry, bi %p, rn %p", __func__, bi, rn);
1400 #endif
1401
1402 new = XCALLOC (MTYPE_RFAPI_NEXTHOP, sizeof (struct rfapi_next_hop_entry));
1403 assert (new);
1404
1405 new->prefix = *rprefix;
1406
1407 if (bi->extra &&
1408 decode_rd_type(bi->extra->vnc.import.rd.val) == RD_TYPE_VNC_ETH)
1409 {
1410 /* ethernet */
1411
1412 struct rfapi_vn_option *vo;
1413
1414 vo = XCALLOC (MTYPE_RFAPI_VN_OPTION, sizeof (struct rfapi_vn_option));
1415 assert (vo);
1416
1417 vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
1418
1419 memcpy (&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet,
1420 ETHER_ADDR_LEN);
1421 /* only low 3 bytes of this are significant */
1422 if (bi->attr && bi->attr->extra)
1423 {
1424 (void) rfapiEcommunityGetLNI (bi->attr->extra->ecommunity,
1425 &vo->v.l2addr.logical_net_id);
1426 (void) rfapiEcommunityGetEthernetTag (bi->attr->extra->ecommunity,
1427 &vo->v.l2addr.tag_id);
1428 }
1429
1430 /* local_nve_id comes from lower byte of RD type */
1431 vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
1432
1433 /* label comes from MP_REACH_NLRI label */
1434 vo->v.l2addr.label = decode_label (bi->extra->tag);
1435
1436 new->vn_options = vo;
1437
1438 /*
1439 * If there is an auxiliary prefix (i.e., host IP address),
1440 * use it as the nexthop prefix instead of the query prefix
1441 */
1442 if (bi->extra->vnc.import.aux_prefix.family)
1443 {
1444 rfapiQprefix2Rprefix (&bi->extra->vnc.import.aux_prefix,
1445 &new->prefix);
1446 }
1447 }
1448
1449 if (bi->attr)
1450 {
1451 bgp_encap_types tun_type;
1452 new->prefix.cost = rfapiRfpCost (bi->attr);
1453
1454 if (bi->attr->extra)
1455 {
1456
1457 struct bgp_attr_encap_subtlv *pEncap;
1458
1459 switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len))
1460 {
1461 case AF_INET:
1462 new->vn_address.addr_family = AF_INET;
1463 new->vn_address.addr.v4 = bi->attr->extra->mp_nexthop_global_in;
1464 break;
1465
1466 case AF_INET6:
1467 new->vn_address.addr_family = AF_INET6;
1468 new->vn_address.addr.v6 = bi->attr->extra->mp_nexthop_global;
1469 break;
1470
1471 default:
1472 zlog_warn ("%s: invalid vpn nexthop length: %d",
1473 __func__, bi->attr->extra->mp_nexthop_len);
1474 rfapi_free_next_hop_list (new);
1475 return NULL;
1476 }
1477
1478 for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap;
1479 pEncap = pEncap->next)
1480 {
1481 switch (pEncap->type)
1482 {
1483 case BGP_VNC_SUBTLV_TYPE_LIFETIME:
1484 /* use configured lifetime, not attr lifetime */
1485 break;
1486
1487 default:
1488 zlog_warn ("%s: unknown VNC option type %d",
1489 __func__, pEncap->type);
1490
1491
1492 break;
1493 }
1494 }
1495
1496 rfapiGetTunnelType (bi->attr, &tun_type);
1497 if (tun_type == BGP_ENCAP_TYPE_MPLS)
1498 {
1499 struct prefix p;
1500 /* MPLS carries UN address in next hop */
1501 rfapiNexthop2Prefix (bi->attr, &p);
1502 if (p.family != 0)
1503 {
1504 rfapiQprefix2Raddr(&p, &new->un_address);
1505 have_vnc_tunnel_un = 1;
1506 }
1507 }
1508
1509 for (pEncap = bi->attr->extra->encap_subtlvs; pEncap;
1510 pEncap = pEncap->next)
1511 {
1512 switch (pEncap->type)
1513 {
1514 case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
1515 /*
1516 * Overrides ENCAP UN address, if any
1517 */
1518 switch (pEncap->length)
1519 {
1520
1521 case 8:
1522 new->un_address.addr_family = AF_INET;
1523 memcpy (&new->un_address.addr.v4, pEncap->value, 4);
1524 have_vnc_tunnel_un = 1;
1525 break;
1526
1527 case 20:
1528 new->un_address.addr_family = AF_INET6;
1529 memcpy (&new->un_address.addr.v6, pEncap->value, 16);
1530 have_vnc_tunnel_un = 1;
1531 break;
1532
1533 default:
1534 zlog_warn
1535 ("%s: invalid tunnel subtlv UN addr length (%d) for bi %p",
1536 __func__, pEncap->length, bi);
1537 }
1538 break;
1539
1540 default:
1541 zlog_warn ("%s: unknown Encap Attribute option type %d",
1542 __func__, pEncap->type);
1543
1544
1545 break;
1546 }
1547 }
1548
1549 new->un_options = rfapi_encap_tlv_to_un_option (bi->attr);
1550
1551 #if DEBUG_ENCAP_MONITOR
1552 vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d",
1553 __func__, __LINE__, have_vnc_tunnel_un);
1554 #endif
1555
1556 if (!have_vnc_tunnel_un && bi && bi->extra)
1557 {
1558 /*
1559 * use cached UN address from ENCAP route
1560 */
1561 new->un_address.addr_family = bi->extra->vnc.import.un_family;
1562 switch (new->un_address.addr_family)
1563 {
1564 case AF_INET:
1565 new->un_address.addr.v4 = bi->extra->vnc.import.un.addr4;
1566 break;
1567 case AF_INET6:
1568 new->un_address.addr.v6 = bi->extra->vnc.import.un.addr6;
1569 break;
1570 default:
1571 zlog_warn ("%s: invalid UN addr family (%d) for bi %p",
1572 __func__, new->un_address.addr_family, bi);
1573 rfapi_free_next_hop_list (new);
1574 return NULL;
1575 break;
1576 }
1577 }
1578 }
1579 }
1580 new->lifetime = lifetime;
1581 return new;
1582 }
1583
1584 int
1585 rfapiHasNonRemovedRoutes (struct route_node *rn)
1586 {
1587 struct bgp_info *bi;
1588
1589 for (bi = rn->info; bi; bi = bi->next)
1590 {
1591 struct prefix pfx;
1592
1593 if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) &&
1594 (bi->extra && !rfapiGetUnAddrOfVpnBi (bi, &pfx)))
1595 {
1596
1597 return 1;
1598 }
1599 }
1600 return 0;
1601 }
1602
1603 #if DEBUG_IT_NODES
1604 /*
1605 * DEBUG FUNCTION
1606 */
1607 void
1608 rfapiDumpNode (struct route_node *rn)
1609 {
1610 struct bgp_info *bi;
1611
1612 vnc_zlog_debug_verbose ("%s: rn=%p", __func__, rn);
1613 for (bi = rn->info; bi; bi = bi->next)
1614 {
1615 struct prefix pfx;
1616 int ctrc = rfapiGetUnAddrOfVpnBi (bi, &pfx);
1617 int nr;
1618
1619 if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) && (bi->extra && !ctrc))
1620 {
1621
1622 nr = 1;
1623 }
1624 else
1625 {
1626 nr = 0;
1627 }
1628
1629 vnc_zlog_debug_verbose (" bi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d",
1630 bi, nr, bi->flags, bi->extra, ctrc);
1631 }
1632 }
1633 #endif
1634
1635 static int
1636 rfapiNhlAddNodeRoutes (
1637 struct route_node *rn, /* in */
1638 struct rfapi_ip_prefix *rprefix, /* in */
1639 uint32_t lifetime, /* in */
1640 int removed, /* in */
1641 struct rfapi_next_hop_entry **head, /* in/out */
1642 struct rfapi_next_hop_entry **tail, /* in/out */
1643 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1644 struct route_node *rfd_rib_node,/* preload this NVE rib node */
1645 struct prefix *pfx_target_original) /* query target */
1646 {
1647 struct bgp_info *bi;
1648 struct rfapi_next_hop_entry *new;
1649 struct prefix pfx_un;
1650 struct skiplist *seen_nexthops;
1651 int count = 0;
1652 int is_l2 = (rn->p.family == AF_ETHERNET);
1653
1654 if (rfapiRibFTDFilterRecentPrefix(
1655 (struct rfapi_descriptor *)(rfd_rib_node->table->info), rn,
1656 pfx_target_original))
1657 {
1658 return 0;
1659 }
1660
1661 seen_nexthops =
1662 skiplist_new (0, vnc_prefix_cmp, (void (*)(void *)) prefix_free);
1663
1664 for (bi = rn->info; bi; bi = bi->next)
1665 {
1666
1667 struct prefix pfx_vn;
1668 struct prefix *newpfx;
1669
1670 if (removed && !CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
1671 {
1672 #if DEBUG_RETURNED_NHL
1673 vnc_zlog_debug_verbose ("%s: want holddown, this route not holddown, skip",
1674 __func__);
1675 #endif
1676 continue;
1677 }
1678 if (!removed && CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
1679 {
1680 continue;
1681 }
1682
1683 if (!bi->extra)
1684 {
1685 continue;
1686 }
1687
1688 /*
1689 * Check for excluded VN address
1690 */
1691 if (rfapiVpnBiNhEqualsPt (bi, exclude_vnaddr))
1692 continue;
1693
1694 /*
1695 * Check for VN address (nexthop) copied already
1696 */
1697 if (is_l2)
1698 {
1699 /* L2 routes: semantic nexthop in aux_prefix; VN addr ain't it */
1700 pfx_vn = bi->extra->vnc.import.aux_prefix;
1701 }
1702 else
1703 {
1704 rfapiNexthop2Prefix (bi->attr, &pfx_vn);
1705 }
1706 if (!skiplist_search (seen_nexthops, &pfx_vn, NULL))
1707 {
1708 #if DEBUG_RETURNED_NHL
1709 char buf[BUFSIZ];
1710
1711 prefix2str (&pfx_vn, buf, BUFSIZ);
1712 buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
1713 vnc_zlog_debug_verbose ("%s: already put VN/nexthop %s, skip", __func__, buf);
1714 #endif
1715 continue;
1716 }
1717
1718 if (rfapiGetUnAddrOfVpnBi (bi, &pfx_un))
1719 {
1720 #if DEBUG_ENCAP_MONITOR
1721 vnc_zlog_debug_verbose ("%s: failed to get UN address of this VPN bi",
1722 __func__);
1723 #endif
1724 continue;
1725 }
1726
1727 newpfx = prefix_new ();
1728 *newpfx = pfx_vn;
1729 skiplist_insert (seen_nexthops, newpfx, newpfx);
1730
1731 new = rfapiRouteInfo2NextHopEntry(rprefix, bi, lifetime, rn);
1732 if (new)
1733 {
1734 if (rfapiRibPreloadBi(rfd_rib_node, &pfx_vn, &pfx_un, lifetime, bi))
1735 {
1736 /* duplicate filtered by RIB */
1737 rfapi_free_next_hop_list (new);
1738 new = NULL;
1739 }
1740 }
1741
1742 if (new)
1743 {
1744 if (*tail)
1745 {
1746 (*tail)->next = new;
1747 }
1748 else
1749 {
1750 *head = new;
1751 }
1752 *tail = new;
1753 ++count;
1754 }
1755 }
1756
1757 skiplist_free (seen_nexthops);
1758
1759 return count;
1760 }
1761
1762
1763 /*
1764 * Breadth-first
1765 *
1766 * omit_node is meant for the situation where we are adding a subtree
1767 * of a parent of some original requested node. The response already
1768 * contains the original requested node, and we don't want to duplicate
1769 * its routes in the list, so we skip it if the right or left node
1770 * matches (of course, we still travel down its child subtrees).
1771 */
1772 static int
1773 rfapiNhlAddSubtree (
1774 struct route_node *rn, /* in */
1775 uint32_t lifetime, /* in */
1776 struct rfapi_next_hop_entry **head, /* in/out */
1777 struct rfapi_next_hop_entry **tail, /* in/out */
1778 struct route_node *omit_node, /* in */
1779 struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */
1780 struct route_table *rfd_rib_table,/* preload here */
1781 struct prefix *pfx_target_original) /* query target */
1782 {
1783 struct rfapi_ip_prefix rprefix;
1784 int rcount = 0;
1785
1786 if (rn->l_left && rn->l_left != omit_node)
1787 {
1788 if (rn->l_left->info)
1789 {
1790 int count = 0;
1791 struct route_node *rib_rn = NULL;
1792
1793 rfapiQprefix2Rprefix (&rn->l_left->p, &rprefix);
1794 if (rfd_rib_table)
1795 {
1796 rib_rn = route_node_get(rfd_rib_table, &rn->l_left->p);
1797 }
1798
1799 count = rfapiNhlAddNodeRoutes (rn->l_left, &rprefix, lifetime, 0,
1800 head, tail, exclude_vnaddr, rib_rn, pfx_target_original);
1801 if (!count)
1802 {
1803 count = rfapiNhlAddNodeRoutes (rn->l_left, &rprefix, lifetime, 1,
1804 head, tail, exclude_vnaddr, rib_rn, pfx_target_original);
1805 }
1806 rcount += count;
1807 if (rib_rn)
1808 route_unlock_node(rib_rn);
1809 }
1810 }
1811
1812 if (rn->l_right && rn->l_right != omit_node)
1813 {
1814 if (rn->l_right->info)
1815 {
1816 int count = 0;
1817 struct route_node *rib_rn = NULL;
1818
1819 rfapiQprefix2Rprefix (&rn->l_right->p, &rprefix);
1820 if (rfd_rib_table)
1821 {
1822 rib_rn = route_node_get(rfd_rib_table, &rn->l_right->p);
1823 }
1824 count = rfapiNhlAddNodeRoutes (rn->l_right, &rprefix, lifetime, 0,
1825 head, tail, exclude_vnaddr, rib_rn, pfx_target_original);
1826 if (!count)
1827 {
1828 count = rfapiNhlAddNodeRoutes (rn->l_right, &rprefix, lifetime, 1,
1829 head, tail, exclude_vnaddr, rib_rn, pfx_target_original);
1830 }
1831 rcount += count;
1832 if (rib_rn)
1833 route_unlock_node(rib_rn);
1834 }
1835 }
1836
1837 if (rn->l_left)
1838 {
1839 rcount += rfapiNhlAddSubtree (rn->l_left, lifetime, head, tail, omit_node,
1840 exclude_vnaddr, rfd_rib_table, pfx_target_original);
1841 }
1842 if (rn->l_right)
1843 {
1844 rcount += rfapiNhlAddSubtree (rn->l_right, lifetime, head, tail,
1845 omit_node, exclude_vnaddr, rfd_rib_table, pfx_target_original);
1846 }
1847
1848 return rcount;
1849 }
1850
1851 /*
1852 * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
1853 *
1854 * Construct an rfapi nexthop list based on the routes attached to
1855 * the specified node.
1856 *
1857 * If there are any routes that do NOT have BGP_INFO_REMOVED set,
1858 * return those only. If there are ONLY routes with BGP_INFO_REMOVED,
1859 * then return those, and also include all the non-removed routes from the
1860 * next less-specific node (i.e., this node's parent) at the end.
1861 */
1862 struct rfapi_next_hop_entry *
1863 rfapiRouteNode2NextHopList (
1864 struct route_node *rn,
1865 uint32_t lifetime, /* put into nexthop entries */
1866 struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */
1867 struct route_table *rfd_rib_table,/* preload here */
1868 struct prefix *pfx_target_original) /* query target */
1869 {
1870 struct rfapi_ip_prefix rprefix;
1871 struct rfapi_next_hop_entry *answer = NULL;
1872 struct rfapi_next_hop_entry *last = NULL;
1873 struct route_node *parent;
1874 int count = 0;
1875 struct route_node *rib_rn;
1876
1877 #if DEBUG_RETURNED_NHL
1878 {
1879 char buf[BUFSIZ];
1880
1881 prefix2str (&rn->p, buf, BUFSIZ);
1882 buf[BUFSIZ - 1] = 0;
1883 vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__, buf);
1884 }
1885 rfapiDebugBacktrace ();
1886 #endif
1887
1888 rfapiQprefix2Rprefix (&rn->p, &rprefix);
1889
1890 rib_rn = rfd_rib_table? route_node_get(rfd_rib_table, &rn->p): NULL;
1891
1892 /*
1893 * Add non-withdrawn routes at this node
1894 */
1895 count = rfapiNhlAddNodeRoutes (rn, &rprefix, lifetime, 0, &answer, &last,
1896 exclude_vnaddr, rib_rn, pfx_target_original);
1897
1898 /*
1899 * If the list has at least one entry, it's finished
1900 */
1901 if (count)
1902 {
1903 count += rfapiNhlAddSubtree (rn, lifetime, &answer, &last, NULL,
1904 exclude_vnaddr, rfd_rib_table, pfx_target_original);
1905 vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__, count, answer);
1906 #if DEBUG_RETURNED_NHL
1907 rfapiPrintNhl (NULL, answer);
1908 #endif
1909 if (rib_rn)
1910 route_unlock_node(rib_rn);
1911 return answer;
1912 }
1913
1914 /*
1915 * Add withdrawn routes at this node
1916 */
1917 count = rfapiNhlAddNodeRoutes (rn, &rprefix, lifetime, 1, &answer, &last,
1918 exclude_vnaddr, rib_rn, pfx_target_original);
1919 if (rib_rn)
1920 route_unlock_node(rib_rn);
1921
1922 // rfapiPrintNhl(NULL, answer);
1923
1924 /*
1925 * walk up the tree until we find a node with non-deleted
1926 * routes, then add them
1927 */
1928 for (parent = rn->parent; parent; parent = parent->parent)
1929 {
1930 if (rfapiHasNonRemovedRoutes (parent))
1931 {
1932 break;
1933 }
1934 }
1935
1936 /*
1937 * Add non-withdrawn routes from less-specific prefix
1938 */
1939 if (parent)
1940 {
1941 rib_rn = rfd_rib_table? route_node_get(rfd_rib_table, &parent->p): NULL;
1942 rfapiQprefix2Rprefix (&parent->p, &rprefix);
1943 count += rfapiNhlAddNodeRoutes (parent, &rprefix, lifetime, 0,
1944 &answer, &last, exclude_vnaddr, rib_rn, pfx_target_original);
1945 count += rfapiNhlAddSubtree (parent, lifetime, &answer, &last, rn,
1946 exclude_vnaddr, rfd_rib_table, pfx_target_original);
1947 if (rib_rn)
1948 route_unlock_node(rib_rn);
1949 }
1950 else
1951 {
1952 /*
1953 * There is no parent with non-removed routes. Still need to
1954 * add subtree of original node if it contributed routes to the
1955 * answer.
1956 */
1957 if (count)
1958 count += rfapiNhlAddSubtree (rn, lifetime, &answer, &last, rn,
1959 exclude_vnaddr, rfd_rib_table, pfx_target_original);
1960 }
1961
1962 vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__, count, answer);
1963 #if DEBUG_RETURNED_NHL
1964 rfapiPrintNhl (NULL, answer);
1965 #endif
1966 return answer;
1967 }
1968
1969 /*
1970 * Construct nexthop list of all routes in table
1971 */
1972 struct rfapi_next_hop_entry *
1973 rfapiRouteTable2NextHopList (
1974 struct route_table *rt,
1975 uint32_t lifetime, /* put into nexthop entries */
1976 struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */
1977 struct route_table *rfd_rib_table, /* preload this NVE rib table */
1978 struct prefix *pfx_target_original) /* query target */
1979 {
1980 struct route_node *rn;
1981 struct rfapi_next_hop_entry *biglist = NULL;
1982 struct rfapi_next_hop_entry *nhl;
1983 struct rfapi_next_hop_entry *tail = NULL;
1984 int count = 0;
1985
1986 for (rn = route_top (rt); rn; rn = route_next (rn))
1987 {
1988
1989 nhl = rfapiRouteNode2NextHopList (rn, lifetime, exclude_vnaddr,
1990 rfd_rib_table, pfx_target_original);
1991 if (!tail)
1992 {
1993 tail = biglist = nhl;
1994 if (tail)
1995 count = 1;
1996 }
1997 else
1998 {
1999 tail->next = nhl;
2000 }
2001 if (tail)
2002 {
2003 while (tail->next)
2004 {
2005 ++count;
2006 tail = tail->next;
2007 }
2008 }
2009 }
2010
2011 vnc_zlog_debug_verbose ("%s: returning %d routes", __func__, count);
2012 return biglist;
2013 }
2014
2015 struct rfapi_next_hop_entry *
2016 rfapiEthRouteNode2NextHopList (
2017 struct route_node *rn,
2018 struct rfapi_ip_prefix *rprefix,
2019 uint32_t lifetime, /* put into nexthop entries */
2020 struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */
2021 struct route_table *rfd_rib_table,/* preload NVE rib table */
2022 struct prefix *pfx_target_original) /* query target */
2023 {
2024 int count = 0;
2025 struct rfapi_next_hop_entry *answer = NULL;
2026 struct rfapi_next_hop_entry *last = NULL;
2027 struct route_node *rib_rn;
2028
2029 rib_rn = rfd_rib_table? route_node_get(rfd_rib_table, &rn->p): NULL;
2030
2031 count = rfapiNhlAddNodeRoutes (rn, rprefix, lifetime, 0, &answer, &last,
2032 NULL, rib_rn, pfx_target_original);
2033
2034 #if DEBUG_ENCAP_MONITOR
2035 vnc_zlog_debug_verbose ("%s: node %p: %d non-holddown routes", __func__, rn, count);
2036 #endif
2037
2038 if (!count)
2039 {
2040 count = rfapiNhlAddNodeRoutes (rn, rprefix, lifetime, 1, &answer, &last,
2041 exclude_vnaddr, rib_rn, pfx_target_original);
2042 vnc_zlog_debug_verbose ("%s: node %p: %d holddown routes", __func__, rn, count);
2043 }
2044
2045 if (rib_rn)
2046 route_unlock_node(rib_rn);
2047
2048 #if DEBUG_RETURNED_NHL
2049 rfapiPrintNhl (NULL, answer);
2050 #endif
2051
2052 return answer;
2053 }
2054
2055
2056 /*
2057 * Construct nexthop list of all routes in table
2058 */
2059 struct rfapi_next_hop_entry *
2060 rfapiEthRouteTable2NextHopList (
2061 uint32_t logical_net_id,
2062 struct rfapi_ip_prefix *rprefix,
2063 uint32_t lifetime, /* put into nexthop entries */
2064 struct rfapi_ip_addr *exclude_vnaddr,/* omit routes to same NVE */
2065 struct route_table *rfd_rib_table, /* preload NVE rib node */
2066 struct prefix *pfx_target_original) /* query target */
2067 {
2068 struct rfapi_import_table *it;
2069 struct bgp *bgp = bgp_get_default ();
2070 struct route_table *rt;
2071 struct route_node *rn;
2072 struct rfapi_next_hop_entry *biglist = NULL;
2073 struct rfapi_next_hop_entry *nhl;
2074 struct rfapi_next_hop_entry *tail = NULL;
2075 int count = 0;
2076
2077
2078 it = rfapiMacImportTableGet (bgp, logical_net_id);
2079 rt = it->imported_vpn[AFI_L2VPN];
2080
2081 for (rn = route_top (rt); rn; rn = route_next (rn))
2082 {
2083
2084 nhl = rfapiEthRouteNode2NextHopList(rn, rprefix, lifetime,
2085 exclude_vnaddr, rfd_rib_table, pfx_target_original);
2086 if (!tail)
2087 {
2088 tail = biglist = nhl;
2089 if (tail)
2090 count = 1;
2091 }
2092 else
2093 {
2094 tail->next = nhl;
2095 }
2096 if (tail)
2097 {
2098 while (tail->next)
2099 {
2100 ++count;
2101 tail = tail->next;
2102 }
2103 }
2104 }
2105
2106 vnc_zlog_debug_verbose ("%s: returning %d routes", __func__, count);
2107 return biglist;
2108 }
2109
2110 /*
2111 * Insert a new bi to the imported route table node,
2112 * keeping the list of BIs sorted best route first
2113 */
2114 static void
2115 rfapiBgpInfoAttachSorted (
2116 struct route_node *rn,
2117 struct bgp_info *info_new,
2118 afi_t afi,
2119 safi_t safi)
2120 {
2121 struct bgp *bgp;
2122 struct bgp_info *prev;
2123 struct bgp_info *next;
2124
2125 bgp = bgp_get_default (); /* assume 1 instance for now */
2126
2127 if (VNC_DEBUG(IMPORT_BI_ATTACH))
2128 {
2129 vnc_zlog_debug_verbose ("%s: info_new->peer=%p", __func__, info_new->peer);
2130 vnc_zlog_debug_verbose ("%s: info_new->peer->su_remote=%p", __func__,
2131 info_new->peer->su_remote);
2132 }
2133
2134 for (prev = NULL, next = rn->info; next; prev = next, next = next->next)
2135 {
2136 if (!bgp ||
2137 (!CHECK_FLAG (info_new->flags, BGP_INFO_REMOVED) &&
2138 CHECK_FLAG (next->flags, BGP_INFO_REMOVED)) ||
2139 bgp_info_cmp_compatible (bgp, info_new, next, afi, safi) == -1)
2140 { /* -1 if 1st is better */
2141 break;
2142 }
2143 }
2144 vnc_zlog_debug_verbose ("%s: prev=%p, next=%p", __func__, prev, next);
2145 if (prev)
2146 {
2147 prev->next = info_new;
2148 }
2149 else
2150 {
2151 rn->info = info_new;
2152 }
2153 info_new->prev = prev;
2154 info_new->next = next;
2155 if (next)
2156 next->prev = info_new;
2157 bgp_attr_intern (info_new->attr);
2158 }
2159
2160 static void
2161 rfapiBgpInfoDetach (struct route_node *rn, struct bgp_info *bi)
2162 {
2163 /*
2164 * Remove the route (doubly-linked)
2165 */
2166 // bgp_attr_unintern (&bi->attr);
2167 if (bi->next)
2168 bi->next->prev = bi->prev;
2169 if (bi->prev)
2170 bi->prev->next = bi->next;
2171 else
2172 rn->info = bi->next;
2173 }
2174
2175 /*
2176 * For L3-indexed import tables
2177 */
2178 static int
2179 rfapi_bi_peer_rd_cmp (void *b1, void *b2)
2180 {
2181 struct bgp_info *bi1 = b1;
2182 struct bgp_info *bi2 = b2;
2183
2184 /*
2185 * Compare peers
2186 */
2187 if (bi1->peer < bi2->peer)
2188 return -1;
2189 if (bi1->peer > bi2->peer)
2190 return 1;
2191
2192 /*
2193 * compare RDs
2194 */
2195 return vnc_prefix_cmp ((struct prefix *) &bi1->extra->vnc.import.rd,
2196 (struct prefix *) &bi2->extra->vnc.import.rd);
2197 }
2198
2199 /*
2200 * For L2-indexed import tables
2201 * The BIs in these tables should ALWAYS have an aux_prefix set because
2202 * they arrive via IPv4 or IPv6 advertisements.
2203 */
2204 static int
2205 rfapi_bi_peer_rd_aux_cmp (void *b1, void *b2)
2206 {
2207 struct bgp_info *bi1 = b1;
2208 struct bgp_info *bi2 = b2;
2209 int rc;
2210
2211 /*
2212 * Compare peers
2213 */
2214 if (bi1->peer < bi2->peer)
2215 return -1;
2216 if (bi1->peer > bi2->peer)
2217 return 1;
2218
2219 /*
2220 * compare RDs
2221 */
2222 rc = vnc_prefix_cmp ((struct prefix *) &bi1->extra->vnc.import.rd,
2223 (struct prefix *) &bi2->extra->vnc.import.rd);
2224 if (rc)
2225 {
2226 return rc;
2227 }
2228
2229 /*
2230 * L2 import tables can have multiple entries with the
2231 * same MAC address, same RD, but different L3 addresses.
2232 *
2233 * Use presence of aux_prefix with AF=ethernet and prefixlen=1
2234 * as magic value to signify explicit wildcarding of the aux_prefix.
2235 * This magic value will not appear in bona fide bi entries in
2236 * the import table, but is allowed in the "fake" bi used to
2237 * probe the table when searching. (We have to test both b1 and b2
2238 * because there is no guarantee of the order the test key and
2239 * the real key will be passed)
2240 */
2241 if ((bi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET &&
2242 (bi1->extra->vnc.import.aux_prefix.prefixlen == 1)) ||
2243 (bi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET &&
2244 (bi2->extra->vnc.import.aux_prefix.prefixlen == 1)))
2245 {
2246
2247 /*
2248 * wildcard aux address specified
2249 */
2250 return 0;
2251 }
2252
2253 return vnc_prefix_cmp (&bi1->extra->vnc.import.aux_prefix,
2254 &bi2->extra->vnc.import.aux_prefix);
2255 }
2256
2257
2258 /*
2259 * Index on RD and Peer
2260 */
2261 static void
2262 rfapiItBiIndexAdd (
2263 struct route_node *rn, /* Import table VPN node */
2264 struct bgp_info *bi) /* new BI */
2265 {
2266 struct skiplist *sl;
2267
2268 assert (rn);
2269 assert (bi);
2270 assert (bi->extra);
2271
2272 {
2273 char buf[BUFSIZ];
2274 prefix_rd2str (&bi->extra->vnc.import.rd, buf, BUFSIZ);
2275 vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__, bi, bi->peer, buf);
2276 }
2277
2278 sl = RFAPI_RDINDEX_W_ALLOC (rn);
2279 if (!sl)
2280 {
2281 if (AF_ETHERNET == rn->p.family)
2282 {
2283 sl = skiplist_new (0, rfapi_bi_peer_rd_aux_cmp, NULL);
2284 }
2285 else
2286 {
2287 sl = skiplist_new (0, rfapi_bi_peer_rd_cmp, NULL);
2288 }
2289 RFAPI_IT_EXTRA_GET (rn)->u.vpn.idx_rd = sl;
2290 route_lock_node (rn); /* for skiplist */
2291 }
2292 assert (!skiplist_insert (sl, (void *) bi, (void *) bi));
2293 route_lock_node (rn); /* for skiplist entry */
2294
2295 /* NB: BIs in import tables are not refcounted */
2296 }
2297
2298 static void
2299 rfapiItBiIndexDump (struct route_node *rn)
2300 {
2301 struct skiplist *sl;
2302 void *cursor = NULL;
2303 struct bgp_info *k;
2304 struct bgp_info *v;
2305 int rc;
2306
2307 sl = RFAPI_RDINDEX (rn);
2308 if (!sl)
2309 return;
2310
2311 for (rc = skiplist_next (sl, (void **) &k, (void **) &v, &cursor);
2312 !rc; rc = skiplist_next (sl, (void **) &k, (void **) &v, &cursor))
2313 {
2314
2315 char buf[BUFSIZ];
2316 char buf_aux_pfx[BUFSIZ];
2317
2318 prefix_rd2str (&k->extra->vnc.import.rd, buf, BUFSIZ);
2319 buf_aux_pfx[0] = 0;
2320 if (k->extra->vnc.import.aux_prefix.family)
2321 {
2322 prefix2str (&k->extra->vnc.import.aux_prefix, buf_aux_pfx, BUFSIZ);
2323 }
2324 else
2325 {
2326 strncpy (buf_aux_pfx, "(none)", BUFSIZ);
2327 buf_aux_pfx[BUFSIZ - 1] = 0;
2328 }
2329
2330 vnc_zlog_debug_verbose ("bi %p, peer %p, rd %s, aux_prefix %s", k, k->peer, buf,
2331 buf_aux_pfx);
2332 }
2333 }
2334
2335 static struct bgp_info *
2336 rfapiItBiIndexSearch (
2337 struct route_node *rn, /* Import table VPN node */
2338 struct prefix_rd *prd,
2339 struct peer *peer,
2340 struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */
2341 {
2342 struct skiplist *sl;
2343 int rc;
2344 struct bgp_info bi_fake;
2345 struct bgp_info_extra bi_extra;
2346 struct bgp_info *bi_result;
2347
2348 sl = RFAPI_RDINDEX (rn);
2349 if (!sl)
2350 return NULL;
2351
2352 #if DEBUG_BI_SEARCH
2353 {
2354 char buf[BUFSIZ];
2355 char buf_aux_pfx[BUFSIZ];
2356
2357 prefix_rd2str (prd, buf, BUFSIZ);
2358 if (aux_prefix)
2359 {
2360 prefix2str (aux_prefix, buf_aux_pfx, BUFSIZ);
2361 }
2362 else
2363 {
2364 strncpy (buf_aux_pfx, "(nil)", BUFSIZ - 1);
2365 buf_aux_pfx[BUFSIZ - 1] = 0;
2366 }
2367
2368 vnc_zlog_debug_verbose ("%s want prd=%s, peer=%p, aux_prefix=%s",
2369 __func__, buf, peer, buf_aux_pfx);
2370 rfapiItBiIndexDump (rn);
2371 }
2372 #endif
2373
2374 /* threshold is a WAG */
2375 if (sl->count < 3)
2376 {
2377 #if DEBUG_BI_SEARCH
2378 vnc_zlog_debug_verbose ("%s: short list algorithm", __func__);
2379 #endif
2380 /* if short list, linear search might be faster */
2381 for (bi_result = rn->info; bi_result; bi_result = bi_result->next)
2382 {
2383 #if DEBUG_BI_SEARCH
2384 {
2385 char buf[BUFSIZ];
2386 prefix_rd2str (&bi_result->extra->vnc.import.rd, buf, BUFSIZ);
2387 vnc_zlog_debug_verbose ("%s: bi has prd=%s, peer=%p", __func__,
2388 buf, bi_result->peer);
2389 }
2390 #endif
2391 if (peer == bi_result->peer &&
2392 !prefix_cmp ((struct prefix *) &bi_result->extra->vnc.import.rd,
2393 (struct prefix *) prd))
2394 {
2395
2396 #if DEBUG_BI_SEARCH
2397 vnc_zlog_debug_verbose ("%s: peer and RD same, doing aux_prefix check",
2398 __func__);
2399 #endif
2400 if (!aux_prefix ||
2401 !prefix_cmp (aux_prefix,
2402 &bi_result->extra->vnc.import.aux_prefix))
2403 {
2404
2405 #if DEBUG_BI_SEARCH
2406 vnc_zlog_debug_verbose ("%s: match", __func__);
2407 #endif
2408 break;
2409 }
2410
2411 }
2412 }
2413 return bi_result;
2414 }
2415
2416 bi_fake.peer = peer;
2417 bi_fake.extra = &bi_extra;
2418 bi_fake.extra->vnc.import.rd = *(struct prefix_rd *) prd;
2419 if (aux_prefix)
2420 {
2421 bi_fake.extra->vnc.import.aux_prefix = *aux_prefix;
2422 }
2423 else
2424 {
2425 /* wildcard */
2426 bi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET;
2427 bi_fake.extra->vnc.import.aux_prefix.prefixlen = 1;
2428 }
2429
2430 rc = skiplist_search (sl, (void *) &bi_fake, (void *) &bi_result);
2431
2432 if (rc)
2433 {
2434 #if DEBUG_BI_SEARCH
2435 vnc_zlog_debug_verbose ("%s: no match", __func__);
2436 #endif
2437 return NULL;
2438 }
2439
2440 #if DEBUG_BI_SEARCH
2441 vnc_zlog_debug_verbose ("%s: matched bi=%p", __func__, bi_result);
2442 #endif
2443
2444 return bi_result;
2445 }
2446
2447 static void
2448 rfapiItBiIndexDel (
2449 struct route_node *rn, /* Import table VPN node */
2450 struct bgp_info *bi) /* old BI */
2451 {
2452 struct skiplist *sl;
2453 int rc;
2454
2455 {
2456 char buf[BUFSIZ];
2457 prefix_rd2str (&bi->extra->vnc.import.rd, buf, BUFSIZ);
2458 vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__, bi, bi->peer, buf);
2459 }
2460
2461 sl = RFAPI_RDINDEX (rn);
2462 assert (sl);
2463
2464 rc = skiplist_delete (sl, (void *) (bi), (void *) bi);
2465 if (rc)
2466 {
2467 rfapiItBiIndexDump (rn);
2468 }
2469 assert (!rc);
2470
2471 route_unlock_node (rn); /* for skiplist entry */
2472
2473 /* NB: BIs in import tables are not refcounted */
2474 }
2475
2476 /*
2477 * Add a backreference at the ENCAP node to the VPN route that
2478 * refers to it
2479 */
2480 static void
2481 rfapiMonitorEncapAdd (
2482 struct rfapi_import_table *import_table,
2483 struct prefix *p, /* VN address */
2484 struct route_node *vpn_rn, /* VPN node */
2485 struct bgp_info *vpn_bi) /* VPN bi/route */
2486 {
2487 afi_t afi = family2afi (p->family);
2488 struct route_node *rn;
2489 struct rfapi_monitor_encap *m;
2490
2491 assert (afi);
2492 rn = route_node_get (import_table->imported_encap[afi], p); /* locks rn */
2493 assert (rn);
2494
2495 m =
2496 XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP, sizeof (struct rfapi_monitor_encap));
2497 assert (m);
2498
2499 m->node = vpn_rn;
2500 m->bi = vpn_bi;
2501 m->rn = rn;
2502
2503 /* insert to encap node's list */
2504 m->next = RFAPI_MONITOR_ENCAP (rn);
2505 if (m->next)
2506 m->next->prev = m;
2507 RFAPI_MONITOR_ENCAP_W_ALLOC (rn) = m;
2508
2509 /* for easy lookup when deleting vpn route */
2510 vpn_bi->extra->vnc.import.hme = m;
2511
2512 vnc_zlog_debug_verbose
2513 ("%s: it=%p, vpn_bi=%p, afi=%d, encap rn=%p, setting vpn_bi->extra->vnc.import.hme=%p",
2514 __func__, import_table, vpn_bi, afi, rn, m);
2515
2516 RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, 0);
2517 bgp_attr_intern (vpn_bi->attr);
2518 }
2519
2520 static void
2521 rfapiMonitorEncapDelete (struct bgp_info *vpn_bi)
2522 {
2523 /*
2524 * Remove encap monitor
2525 */
2526 vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__, vpn_bi);
2527 if (vpn_bi->extra)
2528 {
2529 struct rfapi_monitor_encap *hme = vpn_bi->extra->vnc.import.hme;
2530
2531 if (hme)
2532 {
2533
2534 vnc_zlog_debug_verbose ("%s: hme=%p", __func__, hme);
2535
2536 /* Refcount checking takes too long here */
2537 //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
2538 if (hme->next)
2539 hme->next->prev = hme->prev;
2540 if (hme->prev)
2541 hme->prev->next = hme->next;
2542 else
2543 RFAPI_MONITOR_ENCAP_W_ALLOC (hme->rn) = hme->next;
2544 /* Refcount checking takes too long here */
2545 //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
2546
2547 /* see if the struct rfapi_it_extra is empty and can be freed */
2548 rfapiMonitorExtraPrune (SAFI_ENCAP, hme->rn);
2549
2550 route_unlock_node (hme->rn); /* decr ref count */
2551 XFREE (MTYPE_RFAPI_MONITOR_ENCAP, hme);
2552 vpn_bi->extra->vnc.import.hme = NULL;
2553 }
2554 }
2555 }
2556
2557 /*
2558 * quagga lib/thread.h says this must return int even though
2559 * it doesn't do anything with the return value
2560 */
2561 static int
2562 rfapiWithdrawTimerVPN (struct thread *t)
2563 {
2564 struct rfapi_withdraw *wcb = t->arg;
2565 struct bgp_info *bi = wcb->info;
2566 struct bgp *bgp = bgp_get_default ();
2567
2568 struct rfapi_monitor_vpn *moved;
2569 afi_t afi;
2570
2571 assert (wcb->node);
2572 assert (bi);
2573 assert (wcb->import_table);
2574 assert (bi->extra);
2575
2576 RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_MPLS_VPN, wcb->lockoffset);
2577
2578 {
2579 char buf[BUFSIZ];
2580
2581 vnc_zlog_debug_verbose ("%s: removing bi %p at prefix %s/%d",
2582 __func__,
2583 bi,
2584 rfapi_ntop (wcb->node->p.family, &wcb->node->p.u.prefix, buf,
2585 BUFSIZ), wcb->node->p.prefixlen);
2586 }
2587
2588 /*
2589 * Remove the route (doubly-linked)
2590 */
2591 if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)
2592 && VALID_INTERIOR_TYPE (bi->type))
2593 RFAPI_MONITOR_EXTERIOR (wcb->node)->valid_interior_count--;
2594
2595 afi = family2afi (wcb->node->p.family);
2596 wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */
2597 rfapiItBiIndexDel (wcb->node, bi);
2598 rfapiBgpInfoDetach (wcb->node, bi); /* with removed bi */
2599
2600 vnc_import_bgp_exterior_del_route_interior (bgp, wcb->import_table,
2601 wcb->node, bi);
2602
2603
2604 /*
2605 * If VNC is configured to send response remove messages, AND
2606 * if the removed route had a UN address, do response removal
2607 * processing.
2608 */
2609 if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE))
2610 {
2611
2612 int has_valid_duplicate = 0;
2613 struct bgp_info *bii;
2614
2615 /*
2616 * First check if there are any OTHER routes at this node
2617 * that have the same nexthop and a valid UN address. If
2618 * there are (e.g., from other peers), then the route isn't
2619 * really gone, so skip sending a response removal message.
2620 */
2621 for (bii = wcb->node->info; bii; bii = bii->next)
2622 {
2623 if (rfapiVpnBiSamePtUn (bi, bii))
2624 {
2625 has_valid_duplicate = 1;
2626 break;
2627 }
2628 }
2629
2630 vnc_zlog_debug_verbose ("%s: has_valid_duplicate=%d", __func__,
2631 has_valid_duplicate);
2632
2633 if (!has_valid_duplicate)
2634 {
2635 rfapiRibPendingDeleteRoute (bgp, wcb->import_table, afi, wcb->node);
2636 }
2637 }
2638
2639 rfapiMonitorEncapDelete (bi);
2640
2641 /*
2642 * If there are no VPN monitors at this VPN Node A,
2643 * we are done
2644 */
2645 if (!RFAPI_MONITOR_VPN (wcb->node))
2646 {
2647 vnc_zlog_debug_verbose ("%s: no VPN monitors at this node", __func__);
2648 goto done;
2649 }
2650
2651 /*
2652 * rfapiMonitorMoveShorter only moves monitors if there are
2653 * no remaining valid routes at the current node
2654 */
2655 moved = rfapiMonitorMoveShorter (wcb->node, 1);
2656
2657 if (moved)
2658 {
2659 rfapiMonitorMovedUp (wcb->import_table, wcb->node, moved->node, moved);
2660 }
2661
2662 done:
2663 /*
2664 * Free VPN bi
2665 */
2666 rfapiBgpInfoFree (bi);
2667 wcb->info = NULL;
2668
2669 /*
2670 * If route count at this node has gone to 0, withdraw exported prefix
2671 */
2672 if (!wcb->node->info)
2673 {
2674 /* see if the struct rfapi_it_extra is empty and can be freed */
2675 rfapiMonitorExtraPrune (SAFI_MPLS_VPN, wcb->node);
2676 vnc_direct_bgp_del_prefix (bgp, wcb->import_table, wcb->node);
2677 vnc_zebra_del_prefix (bgp, wcb->import_table, wcb->node);
2678 }
2679 else
2680 {
2681 /*
2682 * nexthop change event
2683 * vnc_direct_bgp_add_prefix() will recompute the VN addr ecommunity
2684 */
2685 vnc_direct_bgp_add_prefix (bgp, wcb->import_table, wcb->node);
2686 }
2687
2688 RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset);
2689 route_unlock_node (wcb->node); /* decr ref count */
2690 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
2691 return 0;
2692 }
2693
2694 /*
2695 * This works for multiprotocol extension, but not for plain ol'
2696 * unicast IPv4 because that nexthop is stored in attr->nexthop
2697 */
2698 void
2699 rfapiNexthop2Prefix (struct attr *attr, struct prefix *p)
2700 {
2701 assert (p);
2702 assert (attr);
2703 assert (attr->extra);
2704
2705 memset (p, 0, sizeof (struct prefix));
2706
2707 switch (p->family = BGP_MP_NEXTHOP_FAMILY (attr->extra->mp_nexthop_len))
2708 {
2709 case AF_INET:
2710 p->u.prefix4 = attr->extra->mp_nexthop_global_in;
2711 p->prefixlen = 32;
2712 break;
2713
2714 case AF_INET6:
2715 p->u.prefix6 = attr->extra->mp_nexthop_global;
2716 p->prefixlen = 128;
2717 break;
2718
2719 default:
2720 vnc_zlog_debug_verbose ("%s: Family is unknown = %d",
2721 __func__, p->family);
2722 }
2723 }
2724
2725 void
2726 rfapiUnicastNexthop2Prefix (afi_t afi, struct attr *attr, struct prefix *p)
2727 {
2728 if (afi == AFI_IP)
2729 {
2730 p->family = AF_INET;
2731 p->prefixlen = 32;
2732 p->u.prefix4 = attr->nexthop;
2733 }
2734 else
2735 {
2736 rfapiNexthop2Prefix (attr, p);
2737 }
2738 }
2739
2740 static int
2741 rfapiAttrNexthopAddrDifferent (struct prefix *p1, struct prefix *p2)
2742 {
2743 if (!p1 || !p2)
2744 {
2745 vnc_zlog_debug_verbose ("%s: p1 or p2 is NULL", __func__);
2746 return 1;
2747 }
2748
2749 /*
2750 * Are address families the same?
2751 */
2752 if (p1->family != p2->family)
2753 {
2754 return 1;
2755 }
2756
2757 switch (p1->family)
2758 {
2759 case AF_INET:
2760 if (IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4))
2761 return 0;
2762 break;
2763
2764 case AF_INET6:
2765 if (IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6))
2766 return 0;
2767 break;
2768
2769 default:
2770 assert (1);
2771
2772 }
2773
2774 return 1;
2775 }
2776
2777 static void
2778 rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi)
2779 {
2780 struct attr_extra *attre;
2781
2782 if (!encap_bi->attr || !encap_bi->attr->extra)
2783 {
2784 zlog_warn ("%s: no encap bi attr/extra, can't copy UN address",
2785 __func__);
2786 return;
2787 }
2788
2789 if (!vpn_bi || !vpn_bi->extra)
2790 {
2791 zlog_warn ("%s: no vpn bi attr/extra, can't copy UN address",
2792 __func__);
2793 return;
2794 }
2795
2796 attre = encap_bi->attr->extra;
2797
2798 switch (BGP_MP_NEXTHOP_FAMILY (attre->mp_nexthop_len))
2799 {
2800 case AF_INET:
2801
2802 /*
2803 * instrumentation to debug segfault of 091127
2804 */
2805 vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__, vpn_bi);
2806 if (vpn_bi)
2807 {
2808 vnc_zlog_debug_verbose ("%s: vpn_bi->extra=%p", __func__, vpn_bi->extra);
2809 }
2810
2811 vpn_bi->extra->vnc.import.un_family = AF_INET;
2812 vpn_bi->extra->vnc.import.un.addr4 = attre->mp_nexthop_global_in;
2813 break;
2814
2815 case AF_INET6:
2816 vpn_bi->extra->vnc.import.un_family = AF_INET6;
2817 vpn_bi->extra->vnc.import.un.addr6 = attre->mp_nexthop_global;
2818 break;
2819
2820 default:
2821 zlog_warn ("%s: invalid encap nexthop length: %d",
2822 __func__, attre->mp_nexthop_len);
2823 vpn_bi->extra->vnc.import.un_family = 0;
2824 break;
2825 }
2826 }
2827
2828 /*
2829 * returns 0 on success, nonzero on error
2830 */
2831 static int
2832 rfapiWithdrawEncapUpdateCachedUn (
2833 struct rfapi_import_table *import_table,
2834 struct bgp_info *encap_bi,
2835 struct route_node *vpn_rn,
2836 struct bgp_info *vpn_bi)
2837 {
2838 if (!encap_bi)
2839 {
2840
2841 /*
2842 * clear cached UN address
2843 */
2844 if (!vpn_bi || !vpn_bi->extra)
2845 {
2846 zlog_warn ("%s: missing VPN bi/extra, can't clear UN addr",
2847 __func__);
2848 return 1;
2849 }
2850 vpn_bi->extra->vnc.import.un_family = 0;
2851 memset (&vpn_bi->extra->vnc.import.un, 0,
2852 sizeof (vpn_bi->extra->vnc.import.un));
2853 if (CHECK_FLAG (vpn_bi->flags, BGP_INFO_VALID))
2854 {
2855 if (rfapiGetVncTunnelUnAddr (vpn_bi->attr, NULL))
2856 {
2857 UNSET_FLAG (vpn_bi->flags, BGP_INFO_VALID);
2858 if (VALID_INTERIOR_TYPE (vpn_bi->type))
2859 RFAPI_MONITOR_EXTERIOR (vpn_rn)->valid_interior_count--;
2860 /* signal interior route withdrawal to import-exterior */
2861 vnc_import_bgp_exterior_del_route_interior (bgp_get_default (),
2862 import_table,
2863 vpn_rn, vpn_bi);
2864 }
2865 }
2866
2867 }
2868 else
2869 {
2870 if (!vpn_bi)
2871 {
2872 zlog_warn ("%s: missing VPN bi, can't clear UN addr", __func__);
2873 return 1;
2874 }
2875 rfapiCopyUnEncap2VPN (encap_bi, vpn_bi);
2876 if (!CHECK_FLAG (vpn_bi->flags, BGP_INFO_VALID))
2877 {
2878 SET_FLAG (vpn_bi->flags, BGP_INFO_VALID);
2879 if (VALID_INTERIOR_TYPE (vpn_bi->type))
2880 RFAPI_MONITOR_EXTERIOR (vpn_rn)->valid_interior_count++;
2881 /* signal interior route withdrawal to import-exterior */
2882 vnc_import_bgp_exterior_add_route_interior (bgp_get_default (),
2883 import_table,
2884 vpn_rn, vpn_bi);
2885 }
2886 }
2887 return 0;
2888 }
2889
2890 static int
2891 rfapiWithdrawTimerEncap (struct thread *t)
2892 {
2893 struct rfapi_withdraw *wcb = t->arg;
2894 struct bgp_info *bi = wcb->info;
2895 int was_first_route = 0;
2896 struct rfapi_monitor_encap *em;
2897 struct skiplist *vpn_node_sl = skiplist_new (0, NULL, NULL);
2898
2899 assert (wcb->node);
2900 assert (bi);
2901 assert (wcb->import_table);
2902
2903 RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_ENCAP, 0);
2904
2905 if (wcb->node->info == bi)
2906 was_first_route = 1;
2907
2908 /*
2909 * Remove the route/bi and free it
2910 */
2911 rfapiBgpInfoDetach (wcb->node, bi);
2912 rfapiBgpInfoFree (bi);
2913
2914 if (!was_first_route)
2915 goto done;
2916
2917 for (em = RFAPI_MONITOR_ENCAP (wcb->node); em; em = em->next)
2918 {
2919
2920 /*
2921 * Update monitoring VPN BIs with new encap info at the
2922 * head of the encap bi chain (which could be NULL after
2923 * removing the expiring bi above)
2924 */
2925 if (rfapiWithdrawEncapUpdateCachedUn
2926 (wcb->import_table, wcb->node->info, em->node, em->bi))
2927 continue;
2928
2929 /*
2930 * Build a list of unique VPN nodes referenced by these monitors.
2931 * Use a skiplist for speed.
2932 */
2933 skiplist_insert (vpn_node_sl, em->node, em->node);
2934 }
2935
2936
2937 /*
2938 * for each VPN node referenced in the ENCAP monitors:
2939 */
2940 struct route_node *rn;
2941 while (!skiplist_first (vpn_node_sl, (void **) &rn, NULL))
2942 {
2943 if (!wcb->node->info)
2944 {
2945 struct rfapi_monitor_vpn *moved;
2946
2947 moved = rfapiMonitorMoveShorter (rn, 0);
2948 if (moved)
2949 {
2950 //rfapiDoRouteCallback(wcb->import_table, moved->node, moved);
2951 rfapiMonitorMovedUp (wcb->import_table, rn, moved->node, moved);
2952 }
2953 }
2954 else
2955 {
2956 //rfapiDoRouteCallback(wcb->import_table, rn, NULL);
2957 rfapiMonitorItNodeChanged (wcb->import_table, rn, NULL);
2958 }
2959 skiplist_delete_first (vpn_node_sl);
2960 }
2961
2962 done:
2963 RFAPI_CHECK_REFCOUNT (wcb->node, SAFI_ENCAP, 1);
2964 route_unlock_node (wcb->node); /* decr ref count */
2965 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
2966 skiplist_free (vpn_node_sl);
2967 return 0;
2968 }
2969
2970
2971 /*
2972 * Works for both VPN and ENCAP routes; timer_service_func is different
2973 * in each case
2974 */
2975 static void
2976 rfapiBiStartWithdrawTimer (
2977 struct rfapi_import_table *import_table,
2978 struct route_node *rn,
2979 struct bgp_info *bi,
2980 afi_t afi,
2981 safi_t safi,
2982 int (*timer_service_func) (struct thread *))
2983 {
2984 uint32_t lifetime;
2985 struct rfapi_withdraw *wcb;
2986
2987 if CHECK_FLAG
2988 (bi->flags, BGP_INFO_REMOVED)
2989 {
2990 /*
2991 * Already on the path to being withdrawn,
2992 * should already have a timer set up to
2993 * delete it.
2994 */
2995 vnc_zlog_debug_verbose ("%s: already being withdrawn, do nothing", __func__);
2996 return;
2997 }
2998
2999 rfapiGetVncLifetime (bi->attr, &lifetime);
3000 vnc_zlog_debug_verbose ("%s: VNC lifetime is %u", __func__, lifetime);
3001
3002 /*
3003 * withdrawn routes get to hang around for a while
3004 */
3005 SET_FLAG (bi->flags, BGP_INFO_REMOVED);
3006
3007 /* set timer to remove the route later */
3008 lifetime = rfapiGetHolddownFromLifetime (lifetime);
3009 vnc_zlog_debug_verbose ("%s: using timeout %u", __func__, lifetime);
3010
3011 /*
3012 * Stash import_table, node, and info for use by timer
3013 * service routine, which is supposed to free the wcb.
3014 */
3015 wcb = XCALLOC (MTYPE_RFAPI_WITHDRAW, sizeof (struct rfapi_withdraw));
3016 assert (wcb);
3017 wcb->node = rn;
3018 wcb->info = bi;
3019 wcb->import_table = import_table;
3020 bgp_attr_intern (bi->attr);
3021
3022 if (VNC_DEBUG(VERBOSE))
3023 {
3024 vnc_zlog_debug_verbose
3025 ("%s: wcb values: node=%p, info=%p, import_table=%p (bi follows)",
3026 __func__, wcb->node, wcb->info, wcb->import_table);
3027 rfapiPrintBi (NULL, bi);
3028 }
3029
3030
3031 assert (bi->extra);
3032 if (lifetime > UINT32_MAX / 1001)
3033 {
3034 /* sub-optimal case, but will probably never happen */
3035 bi->extra->vnc.import.timer = NULL;
3036 thread_add_timer(bm->master, timer_service_func, wcb, lifetime,
3037 &bi->extra->vnc.import.timer);
3038 }
3039 else
3040 {
3041 static uint32_t jitter;
3042 uint32_t lifetime_msec;
3043
3044 /*
3045 * the goal here is to spread out the timers so they are
3046 * sortable in the skip list
3047 */
3048 if (++jitter >= 1000)
3049 jitter = 0;
3050
3051 lifetime_msec = (lifetime * 1000) + jitter;
3052
3053 bi->extra->vnc.import.timer = NULL;
3054 thread_add_background(bm->master, timer_service_func, wcb, lifetime_msec,
3055 &bi->extra->vnc.import.timer);
3056 }
3057
3058 /* re-sort route list (BGP_INFO_REMOVED routes are last) */
3059 if (((struct bgp_info *) rn->info)->next)
3060 {
3061 rfapiBgpInfoDetach (rn, bi);
3062 rfapiBgpInfoAttachSorted (rn, bi, afi, safi);
3063 }
3064 }
3065
3066
3067 typedef void (rfapi_bi_filtered_import_f) (struct rfapi_import_table *,
3068 int,
3069 struct peer *,
3070 void *,
3071 struct prefix *,
3072 struct prefix *,
3073 afi_t,
3074 struct prefix_rd *,
3075 struct attr *,
3076 u_char, u_char, uint32_t *);
3077
3078
3079 static void
3080 rfapiExpireEncapNow (
3081 struct rfapi_import_table *it,
3082 struct route_node *rn,
3083 struct bgp_info *bi)
3084 {
3085 struct rfapi_withdraw *wcb;
3086 struct thread t;
3087
3088 /*
3089 * pretend we're an expiring timer
3090 */
3091 wcb = XCALLOC (MTYPE_RFAPI_WITHDRAW, sizeof (struct rfapi_withdraw));
3092 wcb->info = bi;
3093 wcb->node = rn;
3094 wcb->import_table = it;
3095 memset (&t, 0, sizeof (t));
3096 t.arg = wcb;
3097 rfapiWithdrawTimerEncap (&t); /* frees wcb */
3098 }
3099
3100 static int
3101 rfapiGetNexthop (struct attr *attr, struct prefix *prefix)
3102 {
3103 switch (BGP_MP_NEXTHOP_FAMILY (attr->extra->mp_nexthop_len))
3104 {
3105 case AF_INET:
3106 prefix->family = AF_INET;
3107 prefix->prefixlen = 32;
3108 prefix->u.prefix4 = attr->extra->mp_nexthop_global_in;
3109 break;
3110 case AF_INET6:
3111 prefix->family = AF_INET6;
3112 prefix->prefixlen = 128;
3113 prefix->u.prefix6 = attr->extra->mp_nexthop_global;
3114 break;
3115 default:
3116 vnc_zlog_debug_verbose ("%s: unknown attr->extra->mp_nexthop_len %d", __func__,
3117 attr->extra->mp_nexthop_len);
3118 return EINVAL;
3119 }
3120 return 0;
3121 }
3122
3123 /*
3124 * import a bgp_info if its route target list intersects with the
3125 * import table's route target list
3126 */
3127 static void
3128 rfapiBgpInfoFilteredImportEncap (
3129 struct rfapi_import_table *import_table,
3130 int action,
3131 struct peer *peer,
3132 void *rfd, /* set for looped back routes */
3133 struct prefix *p,
3134 struct prefix *aux_prefix, /* Unused for encap routes */
3135 afi_t afi,
3136 struct prefix_rd *prd,
3137 struct attr *attr, /* part of bgp_info */
3138 u_char type, /* part of bgp_info */
3139 u_char sub_type, /* part of bgp_info */
3140 uint32_t *label) /* part of bgp_info */
3141 {
3142 struct route_table *rt = NULL;
3143 struct route_node *rn;
3144 struct bgp_info *info_new;
3145 struct bgp_info *bi;
3146 struct bgp_info *next;
3147 char buf[BUFSIZ];
3148
3149 struct prefix p_firstbi_old;
3150 struct prefix p_firstbi_new;
3151 int replacing = 0;
3152 const char *action_str = NULL;
3153 struct prefix un_prefix;
3154
3155 struct bgp *bgp;
3156 bgp = bgp_get_default (); /* assume 1 instance for now */
3157
3158 switch (action)
3159 {
3160 case FIF_ACTION_UPDATE:
3161 action_str = "update";
3162 break;
3163 case FIF_ACTION_WITHDRAW:
3164 action_str = "withdraw";
3165 break;
3166 case FIF_ACTION_KILL:
3167 action_str = "kill";
3168 break;
3169 default:
3170 assert (0);
3171 break;
3172 }
3173
3174 vnc_zlog_debug_verbose ("%s: entry: %s: prefix %s/%d", __func__,
3175 action_str,
3176 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen);
3177
3178 memset (&p_firstbi_old, 0, sizeof (p_firstbi_old));
3179 memset (&p_firstbi_new, 0, sizeof (p_firstbi_new));
3180
3181 if (action == FIF_ACTION_UPDATE)
3182 {
3183 /*
3184 * Compare rt lists. If no intersection, don't import this route
3185 * On a withdraw, peer and RD are sufficient to determine if
3186 * we should act.
3187 */
3188 if (!attr || !attr->extra || !attr->extra->ecommunity)
3189 {
3190
3191 vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
3192 __func__);
3193 return;
3194 }
3195 #if RFAPI_REQUIRE_ENCAP_BEEC
3196 if (!rfapiEcommunitiesMatchBeec (attr->extra->ecommunity))
3197 {
3198 vnc_zlog_debug_verbose ("%s: it=%p: no match for BGP Encapsulation ecommunity",
3199 __func__, import_table);
3200 return;
3201 }
3202 #endif
3203 if (!rfapiEcommunitiesIntersect (import_table->rt_import_list,
3204 attr->extra->ecommunity))
3205 {
3206
3207 vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
3208 __func__, import_table);
3209 return;
3210 }
3211
3212 /*
3213 * Updates must also have a nexthop address
3214 */
3215 memset (&un_prefix, 0, sizeof (un_prefix)); /* keep valgrind happy */
3216 if (rfapiGetNexthop (attr, &un_prefix))
3217 {
3218 vnc_zlog_debug_verbose ("%s: missing nexthop address", __func__);
3219 return;
3220 }
3221 }
3222
3223 /*
3224 * Figure out which radix tree the route would go into
3225 */
3226 switch (afi)
3227 {
3228 case AFI_IP:
3229 case AFI_IP6:
3230 rt = import_table->imported_encap[afi];
3231 break;
3232
3233 default:
3234 zlog_err ("%s: bad afi %d", __func__, afi);
3235 return;
3236 }
3237
3238 /*
3239 * route_node_lookup returns a node only if there is at least
3240 * one route attached.
3241 */
3242 rn = route_node_lookup (rt, p);
3243
3244 #if DEBUG_ENCAP_MONITOR
3245 vnc_zlog_debug_verbose ("%s: initial encap lookup (it=%p) rn=%p",
3246 __func__, import_table, rn);
3247 #endif
3248
3249 if (rn)
3250 {
3251
3252 RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, 1);
3253 route_unlock_node (rn); /* undo lock in route_node_lookup */
3254
3255
3256 /*
3257 * capture nexthop of first bi
3258 */
3259 if (rn->info)
3260 {
3261 rfapiNexthop2Prefix (((struct bgp_info *) (rn->info))->attr,
3262 &p_firstbi_old);
3263 }
3264
3265 for (bi = rn->info; bi; bi = bi->next)
3266 {
3267
3268 /*
3269 * Does this bgp_info refer to the same route
3270 * as we are trying to add?
3271 */
3272 vnc_zlog_debug_verbose ("%s: comparing BI %p", __func__, bi);
3273
3274
3275 /*
3276 * Compare RDs
3277 *
3278 * RD of import table bi is in bi->extra->vnc.import.rd
3279 * RD of info_orig is in prd
3280 */
3281 if (!bi->extra)
3282 {
3283 vnc_zlog_debug_verbose ("%s: no bi->extra", __func__);
3284 continue;
3285 }
3286 if (prefix_cmp ((struct prefix *) &bi->extra->vnc.import.rd,
3287 (struct prefix *) prd))
3288 {
3289
3290 vnc_zlog_debug_verbose ("%s: prd does not match", __func__);
3291 continue;
3292 }
3293
3294 /*
3295 * Compare peers
3296 */
3297 if (bi->peer != peer)
3298 {
3299 vnc_zlog_debug_verbose ("%s: peer does not match", __func__);
3300 continue;
3301 }
3302
3303 vnc_zlog_debug_verbose ("%s: found matching bi", __func__);
3304
3305 /* Same route. Delete this bi, replace with new one */
3306
3307 if (action == FIF_ACTION_WITHDRAW)
3308 {
3309
3310 vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d",
3311 __func__,
3312 inet_ntop (rn->p.family, &rn->p.u.prefix, buf,
3313 BUFSIZ), rn->p.prefixlen);
3314
3315 rfapiBiStartWithdrawTimer (import_table, rn, bi,
3316 afi, SAFI_ENCAP,
3317 rfapiWithdrawTimerEncap);
3318
3319 }
3320 else
3321 {
3322 vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d",
3323 __func__,
3324 ((action ==
3325 FIF_ACTION_KILL) ? "killing" : "replacing"),
3326 inet_ntop (rn->p.family, &rn->p.u.prefix, buf,
3327 BUFSIZ), rn->p.prefixlen);
3328
3329 /*
3330 * If this route is waiting to be deleted because of
3331 * a previous withdraw, we must cancel its timer.
3332 */
3333 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED)
3334 && bi->extra->vnc.import.timer)
3335 {
3336
3337 struct thread *t =
3338 (struct thread *) bi->extra->vnc.import.timer;
3339 struct rfapi_withdraw *wcb = t->arg;
3340
3341 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
3342 thread_cancel (t);
3343 }
3344
3345 if (action == FIF_ACTION_UPDATE)
3346 {
3347 rfapiBgpInfoDetach (rn, bi);
3348 rfapiBgpInfoFree (bi);
3349 replacing = 1;
3350 }
3351 else
3352 {
3353 /*
3354 * Kill: do export stuff when removing bi
3355 */
3356 struct rfapi_withdraw *wcb;
3357 struct thread t;
3358
3359 /*
3360 * pretend we're an expiring timer
3361 */
3362 wcb =
3363 XCALLOC (MTYPE_RFAPI_WITHDRAW,
3364 sizeof (struct rfapi_withdraw));
3365 wcb->info = bi;
3366 wcb->node = rn;
3367 wcb->import_table = import_table;
3368 memset (&t, 0, sizeof (t));
3369 t.arg = wcb;
3370 rfapiWithdrawTimerEncap (&t); /* frees wcb */
3371 }
3372 }
3373
3374 break;
3375 }
3376 }
3377
3378 if (rn)
3379 RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, replacing ? 1 : 0);
3380
3381 if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL)
3382 return;
3383
3384 info_new = rfapiBgpInfoCreate (attr, peer, rfd, prd, type, sub_type, NULL);
3385
3386 if (rn)
3387 {
3388 if (!replacing)
3389 route_lock_node (rn); /* incr ref count for new BI */
3390 }
3391 else
3392 {
3393 rn = route_node_get (rt, p);
3394 }
3395
3396 vnc_zlog_debug_verbose ("%s: (afi=%d, rn=%p) inserting at prefix %s/%d",
3397 __func__,
3398 afi,
3399 rn,
3400 inet_ntop (rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
3401 rn->p.prefixlen);
3402
3403 rfapiBgpInfoAttachSorted (rn, info_new, afi, SAFI_ENCAP);
3404
3405 /*
3406 * Delete holddown routes from same NVE. See details in
3407 * rfapiBgpInfoFilteredImportVPN()
3408 */
3409 for (bi = info_new->next; bi; bi = next)
3410 {
3411
3412 struct prefix pfx_un;
3413 int un_match = 0;
3414
3415 next = bi->next;
3416 if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
3417 continue;
3418
3419 /*
3420 * We already match the VN address (it is the prefix
3421 * of the route node)
3422 */
3423
3424 if (!rfapiGetNexthop (bi->attr, &pfx_un) &&
3425 prefix_same (&pfx_un, &un_prefix))
3426 {
3427
3428 un_match = 1;
3429 }
3430
3431 if (!un_match)
3432 continue;
3433
3434 vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route",
3435 __func__);
3436 if (bi->extra->vnc.import.timer)
3437 {
3438 struct thread *t = (struct thread *) bi->extra->vnc.import.timer;
3439 struct rfapi_withdraw *wcb = t->arg;
3440
3441 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
3442 thread_cancel (t);
3443 }
3444 rfapiExpireEncapNow (import_table, rn, bi);
3445 }
3446
3447 rfapiNexthop2Prefix (((struct bgp_info *) (rn->info))->attr,
3448 &p_firstbi_new);
3449
3450 /*
3451 * If the nexthop address of the selected Encap route (i.e.,
3452 * the UN address) has changed, then we must update the VPN
3453 * routes that refer to this Encap route and possibly force
3454 * rfapi callbacks.
3455 */
3456 if (rfapiAttrNexthopAddrDifferent (&p_firstbi_old, &p_firstbi_new))
3457 {
3458
3459 struct rfapi_monitor_encap *m;
3460 struct rfapi_monitor_encap *mnext;
3461
3462 struct route_node *referenced_vpn_prefix;
3463
3464 /*
3465 * Optimized approach: build radix tree on the fly to
3466 * hold list of VPN nodes referenced by the ENCAP monitors
3467 *
3468 * The nodes in this table correspond to prefixes of VPN routes.
3469 * The "info" pointer of the node points to a chain of
3470 * struct rfapi_monitor_encap, each of which refers to a
3471 * specific VPN node.
3472 */
3473 struct route_table *referenced_vpn_table;
3474
3475 referenced_vpn_table = route_table_init ();
3476 assert (referenced_vpn_table);
3477
3478 /*
3479 * iterate over the set of monitors at this ENCAP node.
3480 */
3481 #if DEBUG_ENCAP_MONITOR
3482 vnc_zlog_debug_verbose ("%s: examining monitors at rn=%p", __func__, rn);
3483 #endif
3484 for (m = RFAPI_MONITOR_ENCAP (rn); m; m = m->next)
3485 {
3486
3487 /*
3488 * For each referenced bi/route, copy the ENCAP route's
3489 * nexthop to the VPN route's cached UN address field and set
3490 * the address family of the cached UN address field.
3491 */
3492 rfapiCopyUnEncap2VPN (info_new, m->bi);
3493 if (!CHECK_FLAG (m->bi->flags, BGP_INFO_VALID))
3494 {
3495 SET_FLAG (m->bi->flags, BGP_INFO_VALID);
3496 if (VALID_INTERIOR_TYPE (m->bi->type))
3497 RFAPI_MONITOR_EXTERIOR (m->node)->valid_interior_count++;
3498 vnc_import_bgp_exterior_add_route_interior (bgp,
3499 import_table,
3500 m->node, m->bi);
3501 }
3502
3503 /*
3504 * Build a list of unique VPN nodes referenced by these monitors
3505 *
3506 * There could be more than one VPN node here with a given
3507 * prefix. Those are currently in an unsorted linear list
3508 * per prefix.
3509 */
3510
3511 referenced_vpn_prefix =
3512 route_node_get (referenced_vpn_table, &m->node->p);
3513 assert (referenced_vpn_prefix);
3514 for (mnext = referenced_vpn_prefix->info; mnext;
3515 mnext = mnext->next)
3516 {
3517
3518 if (mnext->node == m->node)
3519 break;
3520 }
3521
3522 if (mnext)
3523 {
3524 /*
3525 * already have an entry for this VPN node
3526 */
3527 route_unlock_node (referenced_vpn_prefix);
3528 }
3529 else
3530 {
3531 mnext = XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP,
3532 sizeof (struct rfapi_monitor_encap));
3533 assert (mnext);
3534 mnext->node = m->node;
3535 mnext->next = referenced_vpn_prefix->info;
3536 referenced_vpn_prefix->info = mnext;
3537 }
3538
3539 }
3540
3541 /*
3542 * for each VPN node referenced in the ENCAP monitors:
3543 */
3544 for (referenced_vpn_prefix = route_top (referenced_vpn_table);
3545 referenced_vpn_prefix;
3546 referenced_vpn_prefix = route_next (referenced_vpn_prefix))
3547 {
3548
3549 while ((m = referenced_vpn_prefix->info))
3550 {
3551
3552 struct route_node *n;
3553
3554 rfapiMonitorMoveLonger (m->node);
3555 for (n = m->node; n; n = n->parent)
3556 {
3557 //rfapiDoRouteCallback(import_table, n, NULL);
3558 }
3559 rfapiMonitorItNodeChanged (import_table, m->node, NULL);
3560
3561 referenced_vpn_prefix->info = m->next;
3562 route_unlock_node (referenced_vpn_prefix);
3563 XFREE (MTYPE_RFAPI_MONITOR_ENCAP, m);
3564 }
3565
3566 }
3567 route_table_finish (referenced_vpn_table);
3568 }
3569
3570 RFAPI_CHECK_REFCOUNT (rn, SAFI_ENCAP, 0);
3571 }
3572
3573 static void
3574 rfapiExpireVpnNow (
3575 struct rfapi_import_table *it,
3576 struct route_node *rn,
3577 struct bgp_info *bi,
3578 int lockoffset)
3579 {
3580 struct rfapi_withdraw *wcb;
3581 struct thread t;
3582
3583 /*
3584 * pretend we're an expiring timer
3585 */
3586 wcb = XCALLOC (MTYPE_RFAPI_WITHDRAW, sizeof (struct rfapi_withdraw));
3587 wcb->info = bi;
3588 wcb->node = rn;
3589 wcb->import_table = it;
3590 wcb->lockoffset = lockoffset;
3591 memset (&t, 0, sizeof (t));
3592 t.arg = wcb;
3593 rfapiWithdrawTimerVPN (&t); /* frees wcb */
3594 }
3595
3596
3597 /*
3598 * import a bgp_info if its route target list intersects with the
3599 * import table's route target list
3600 */
3601 void
3602 rfapiBgpInfoFilteredImportVPN (
3603 struct rfapi_import_table *import_table,
3604 int action,
3605 struct peer *peer,
3606 void *rfd, /* set for looped back routes */
3607 struct prefix *p,
3608 struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
3609 afi_t afi,
3610 struct prefix_rd *prd,
3611 struct attr *attr, /* part of bgp_info */
3612 u_char type, /* part of bgp_info */
3613 u_char sub_type, /* part of bgp_info */
3614 uint32_t *label) /* part of bgp_info */
3615 {
3616 struct route_table *rt = NULL;
3617 struct route_node *rn;
3618 struct route_node *n;
3619 struct bgp_info *info_new;
3620 struct bgp_info *bi;
3621 struct bgp_info *next;
3622 char buf[BUFSIZ];
3623 struct prefix vn_prefix;
3624 struct prefix un_prefix;
3625 int un_prefix_valid = 0;
3626 struct route_node *ern;
3627 int replacing = 0;
3628 int original_had_routes = 0;
3629 struct prefix original_nexthop;
3630 const char *action_str = NULL;
3631 int is_it_ce = 0;
3632
3633 struct bgp *bgp;
3634 bgp = bgp_get_default (); /* assume 1 instance for now */
3635
3636 switch (action)
3637 {
3638 case FIF_ACTION_UPDATE:
3639 action_str = "update";
3640 break;
3641 case FIF_ACTION_WITHDRAW:
3642 action_str = "withdraw";
3643 break;
3644 case FIF_ACTION_KILL:
3645 action_str = "kill";
3646 break;
3647 default:
3648 assert (0);
3649 break;
3650 }
3651
3652 if (import_table == bgp->rfapi->it_ce)
3653 is_it_ce = 1;
3654
3655 vnc_zlog_debug_verbose ("%s: entry: %s%s: prefix %s/%d: it %p, afi %s", __func__,
3656 (is_it_ce ? "CE-IT " : ""),
3657 action_str,
3658 rfapi_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
3659 p->prefixlen, import_table, afi2str (afi));
3660
3661 VNC_ITRCCK;
3662
3663 /*
3664 * Compare rt lists. If no intersection, don't import this route
3665 * On a withdraw, peer and RD are sufficient to determine if
3666 * we should act.
3667 */
3668 if (action == FIF_ACTION_UPDATE)
3669 {
3670 if (!attr || !attr->extra || !attr->extra->ecommunity)
3671 {
3672
3673 vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
3674 __func__);
3675 return;
3676 }
3677 if ((import_table != bgp->rfapi->it_ce) &&
3678 !rfapiEcommunitiesIntersect (import_table->rt_import_list,
3679 attr->extra->ecommunity))
3680 {
3681
3682 vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
3683 __func__, import_table);
3684 return;
3685 }
3686
3687 memset (&vn_prefix, 0, sizeof (vn_prefix)); /* keep valgrind happy */
3688 if (rfapiGetNexthop (attr, &vn_prefix))
3689 {
3690 /* missing nexthop address would be a bad, bad thing */
3691 vnc_zlog_debug_verbose ("%s: missing nexthop", __func__);
3692 return;
3693 }
3694 }
3695
3696 /*
3697 * Figure out which radix tree the route would go into
3698 */
3699 switch (afi)
3700 {
3701 case AFI_IP:
3702 case AFI_IP6:
3703 case AFI_L2VPN:
3704 rt = import_table->imported_vpn[afi];
3705 break;
3706
3707 default:
3708 zlog_err ("%s: bad afi %d", __func__, afi);
3709 return;
3710 }
3711
3712 /* clear it */
3713 memset (&original_nexthop, 0, sizeof (original_nexthop));
3714
3715 /*
3716 * route_node_lookup returns a node only if there is at least
3717 * one route attached.
3718 */
3719 rn = route_node_lookup (rt, p);
3720
3721 vnc_zlog_debug_verbose ("%s: rn=%p", __func__, rn);
3722
3723 if (rn)
3724 {
3725
3726 RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1);
3727 route_unlock_node (rn); /* undo lock in route_node_lookup */
3728
3729 if (rn->info)
3730 original_had_routes = 1;
3731
3732 if (VNC_DEBUG(VERBOSE))
3733 {
3734 vnc_zlog_debug_verbose ("%s: showing IT node on entry", __func__);
3735 rfapiShowItNode (NULL, rn); /* debug */
3736 }
3737
3738 /*
3739 * Look for same route (will have same RD and peer)
3740 */
3741 bi = rfapiItBiIndexSearch (rn, prd, peer, aux_prefix);
3742
3743 if (bi)
3744 {
3745
3746 /*
3747 * This was an old test when we iterated over the
3748 * BIs linearly. Since we're now looking up with
3749 * RD and peer, comparing types should not be
3750 * needed. Changed to assertion.
3751 *
3752 * Compare types. Doing so prevents a RFP-originated
3753 * route from matching an imported route, for example.
3754 */
3755 assert (bi->type == type);
3756
3757 vnc_zlog_debug_verbose ("%s: found matching bi", __func__);
3758
3759 /*
3760 * In the special CE table, withdrawals occur without holddown
3761 */
3762 if (import_table == bgp->rfapi->it_ce)
3763 {
3764 vnc_direct_bgp_del_route_ce (bgp, rn, bi);
3765 if (action == FIF_ACTION_WITHDRAW)
3766 action = FIF_ACTION_KILL;
3767 }
3768
3769 if (action == FIF_ACTION_WITHDRAW)
3770 {
3771
3772 int washolddown = CHECK_FLAG (bi->flags, BGP_INFO_REMOVED);
3773
3774 vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d%s",
3775 __func__,
3776 rfapi_ntop (rn->p.family, &rn->p.u.prefix, buf,
3777 BUFSIZ), rn->p.prefixlen,
3778 (washolddown ? " (already being withdrawn)" : ""));
3779
3780 VNC_ITRCCK;
3781 if (!washolddown)
3782 {
3783 rfapiBiStartWithdrawTimer (import_table, rn, bi,
3784 afi, SAFI_MPLS_VPN,
3785 rfapiWithdrawTimerVPN);
3786
3787 RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, -1);
3788 import_table->holddown_count[afi] += 1;
3789 }
3790 VNC_ITRCCK;
3791 }
3792 else
3793 {
3794 vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d",
3795 __func__,
3796 ((action ==
3797 FIF_ACTION_KILL) ? "killing" : "replacing"),
3798 rfapi_ntop (rn->p.family, &rn->p.u.prefix, buf,
3799 BUFSIZ), rn->p.prefixlen);
3800
3801 /*
3802 * If this route is waiting to be deleted because of
3803 * a previous withdraw, we must cancel its timer.
3804 */
3805 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED) &&
3806 bi->extra->vnc.import.timer)
3807 {
3808
3809 struct thread *t =
3810 (struct thread *) bi->extra->vnc.import.timer;
3811 struct rfapi_withdraw *wcb = t->arg;
3812
3813 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
3814 thread_cancel (t);
3815
3816 import_table->holddown_count[afi] -= 1;
3817 RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, 1);
3818 }
3819 /*
3820 * decrement remote count (if route is remote) because
3821 * we are going to remove it below
3822 */
3823 RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, -1);
3824 if (action == FIF_ACTION_UPDATE)
3825 {
3826 replacing = 1;
3827
3828 /*
3829 * make copy of original nexthop so we can see if it changed
3830 */
3831 rfapiGetNexthop (bi->attr, &original_nexthop);
3832
3833 /*
3834 * remove bi without doing any export processing
3835 */
3836 if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)
3837 && VALID_INTERIOR_TYPE (bi->type))
3838 RFAPI_MONITOR_EXTERIOR (rn)->valid_interior_count--;
3839 rfapiItBiIndexDel (rn, bi);
3840 rfapiBgpInfoDetach (rn, bi);
3841 rfapiMonitorEncapDelete (bi);
3842 vnc_import_bgp_exterior_del_route_interior (bgp,
3843 import_table,
3844 rn, bi);
3845 rfapiBgpInfoFree (bi);
3846 }
3847 else
3848 {
3849 /* Kill */
3850 /*
3851 * remove bi and do export processing
3852 */
3853 import_table->holddown_count[afi] += 1;
3854 rfapiExpireVpnNow (import_table, rn, bi, 0);
3855 }
3856
3857 }
3858 }
3859
3860 }
3861
3862 if (rn)
3863 RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, replacing ? 1 : 0);
3864
3865 if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL)
3866 {
3867 VNC_ITRCCK;
3868 return;
3869 }
3870
3871 info_new = rfapiBgpInfoCreate (attr, peer, rfd, prd, type, sub_type, label);
3872
3873 /*
3874 * lookup un address in encap table
3875 */
3876 ern = route_node_match (import_table->imported_encap[afi], &vn_prefix);
3877 if (ern)
3878 {
3879 rfapiCopyUnEncap2VPN (ern->info, info_new);
3880 route_unlock_node (ern); /* undo lock in route_note_match */
3881 }
3882 else
3883 {
3884 char buf[BUFSIZ];
3885 prefix2str (&vn_prefix, buf, sizeof (buf));
3886 buf[BUFSIZ - 1] = 0;
3887 /* Not a big deal, just means VPN route got here first */
3888 vnc_zlog_debug_verbose ("%s: no encap route for vn addr %s", __func__, buf);
3889 info_new->extra->vnc.import.un_family = 0;
3890 }
3891
3892 if (rn)
3893 {
3894 if (!replacing)
3895 route_lock_node (rn);
3896 }
3897 else
3898 {
3899 /*
3900 * No need to increment reference count, so only "get"
3901 * if the node is not there already
3902 */
3903 rn = route_node_get (rt, p);
3904 }
3905
3906 /*
3907 * For ethernet routes, if there is an accompanying IP address,
3908 * save it in the bi
3909 */
3910 if ((AFI_L2VPN == afi) && aux_prefix)
3911 {
3912
3913 vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__);
3914 info_new->extra->vnc.import.aux_prefix = *aux_prefix;
3915 }
3916
3917 vnc_zlog_debug_verbose ("%s: inserting bi %p at prefix %s/%d #%d",
3918 __func__,
3919 info_new,
3920 rfapi_ntop (rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
3921 rn->p.prefixlen, rn->lock);
3922
3923 rfapiBgpInfoAttachSorted (rn, info_new, afi, SAFI_MPLS_VPN);
3924 rfapiItBiIndexAdd (rn, info_new);
3925 if (!rfapiGetUnAddrOfVpnBi (info_new, NULL))
3926 {
3927 if (VALID_INTERIOR_TYPE (info_new->type))
3928 RFAPI_MONITOR_EXTERIOR (rn)->valid_interior_count++;
3929 SET_FLAG (info_new->flags, BGP_INFO_VALID);
3930 }
3931 RFAPI_UPDATE_ITABLE_COUNT (info_new, import_table, afi, 1);
3932 vnc_import_bgp_exterior_add_route_interior (bgp, import_table, rn,
3933 info_new);
3934
3935 if (import_table == bgp->rfapi->it_ce)
3936 vnc_direct_bgp_add_route_ce (bgp, rn, info_new);
3937
3938 if (VNC_DEBUG(VERBOSE))
3939 {
3940 vnc_zlog_debug_verbose ("%s: showing IT node", __func__);
3941 rfapiShowItNode (NULL, rn); /* debug */
3942 }
3943
3944 rfapiMonitorEncapAdd (import_table, &vn_prefix, rn, info_new);
3945
3946 if (!rfapiGetUnAddrOfVpnBi (info_new, &un_prefix))
3947 {
3948
3949 /*
3950 * if we have a valid UN address (either via Encap route
3951 * or via tunnel attribute), then we should attempt
3952 * to move any monitors at less-specific nodes to this node
3953 */
3954 rfapiMonitorMoveLonger (rn);
3955
3956 un_prefix_valid = 1;
3957
3958 }
3959
3960 /*
3961 * 101129 Enhancement: if we add a route (implication: it is not
3962 * in holddown), delete all other routes from this nve at this
3963 * node that are in holddown, regardless of peer.
3964 *
3965 * Reasons it's OK to do that:
3966 *
3967 * - if the holddown route being deleted originally came from BGP VPN,
3968 * it is already gone from BGP (implication of holddown), so there
3969 * won't be any added inconsistency with the BGP RIB.
3970 *
3971 * - once a fresh route is added at a prefix, any routes in holddown
3972 * at that prefix will not show up in RFP responses, so deleting
3973 * the holddown routes won't affect the contents of responses.
3974 *
3975 * - lifetimes are supposed to be consistent, so there should not
3976 * be a case where the fresh route has a shorter lifetime than
3977 * the holddown route, so we don't expect the fresh route to
3978 * disappear and complete its holddown time before the existing
3979 * holddown routes time out. Therefore, we won't have a situation
3980 * where we expect the existing holddown routes to be hidden and
3981 * then to reappear sometime later (as holddown routes) in a
3982 * RFP response.
3983 *
3984 * Among other things, this would enable us to skirt the problem
3985 * of local holddown routes that refer to NVE descriptors that
3986 * have already been closed (if the same NVE triggers a subsequent
3987 * rfapi_open(), the new peer is different and doesn't match the
3988 * peer of the holddown route, so the stale holddown route still
3989 * hangs around until it times out instead of just being replaced
3990 * by the fresh route).
3991 */
3992 /*
3993 * We know that the new bi will have been inserted before any routes
3994 * in holddown, so we can skip any that came before it
3995 */
3996 for (bi = info_new->next; bi; bi = next)
3997 {
3998
3999 struct prefix pfx_vn;
4000 struct prefix pfx_un;
4001 int un_match = 0;
4002 int remote_peer_match = 0;
4003
4004 next = bi->next;
4005
4006 /*
4007 * Must be holddown
4008 */
4009 if (!CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
4010 continue;
4011
4012 /*
4013 * Must match VN address (nexthop of VPN route)
4014 */
4015 if (rfapiGetNexthop (bi->attr, &pfx_vn))
4016 continue;
4017 if (!prefix_same (&pfx_vn, &vn_prefix))
4018 continue;
4019
4020 if (un_prefix_valid && /* new route UN addr */
4021 !rfapiGetUnAddrOfVpnBi (bi, &pfx_un) && /* old route UN addr */
4022 prefix_same (&pfx_un, &un_prefix))
4023 { /* compare */
4024 un_match = 1;
4025 }
4026 if (!RFAPI_LOCAL_BI (bi) && !RFAPI_LOCAL_BI (info_new) &&
4027 sockunion_same (&bi->peer->su, &info_new->peer->su))
4028 {
4029 /* old & new are both remote, same peer */
4030 remote_peer_match = 1;
4031 }
4032
4033 if (!un_match & !remote_peer_match)
4034 continue;
4035
4036 vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route",
4037 __func__);
4038 if (bi->extra->vnc.import.timer)
4039 {
4040 struct thread *t = (struct thread *) bi->extra->vnc.import.timer;
4041 struct rfapi_withdraw *wcb = t->arg;
4042
4043 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
4044 thread_cancel (t);
4045 }
4046 rfapiExpireVpnNow (import_table, rn, bi, 0);
4047 }
4048
4049 if (!original_had_routes)
4050 {
4051 /*
4052 * We went from 0 usable routes to 1 usable route. Perform the
4053 * "Adding a Route" export process.
4054 */
4055 vnc_direct_bgp_add_prefix (bgp, import_table, rn);
4056 vnc_zebra_add_prefix (bgp, import_table, rn);
4057 }
4058 else
4059 {
4060 /*
4061 * Check for nexthop change event
4062 * Note: the prefix_same() test below detects two situations:
4063 * 1. route is replaced, new route has different nexthop
4064 * 2. new route is added (original_nexthop is 0)
4065 */
4066 struct prefix new_nexthop;
4067
4068 rfapiGetNexthop (attr, &new_nexthop);
4069 if (!prefix_same (&original_nexthop, &new_nexthop))
4070 {
4071 /*
4072 * nexthop change event
4073 * vnc_direct_bgp_add_prefix() will recompute VN addr ecommunity
4074 */
4075 vnc_direct_bgp_add_prefix (bgp, import_table, rn);
4076 }
4077 }
4078
4079 if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE))
4080 {
4081 for (n = rn; n; n = n->parent)
4082 {
4083 //rfapiDoRouteCallback(import_table, n, NULL);
4084 }
4085 rfapiMonitorItNodeChanged (import_table, rn, NULL);
4086 }
4087 RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 0);
4088 VNC_ITRCCK;
4089 }
4090
4091 static rfapi_bi_filtered_import_f *
4092 rfapiBgpInfoFilteredImportFunction (safi_t safi)
4093 {
4094 switch (safi)
4095 {
4096 case SAFI_MPLS_VPN:
4097 return rfapiBgpInfoFilteredImportVPN;
4098
4099 case SAFI_ENCAP:
4100 return rfapiBgpInfoFilteredImportEncap;
4101 }
4102 zlog_err ("%s: bad safi %d", __func__, safi);
4103 return NULL;
4104 }
4105
4106 void
4107 rfapiProcessUpdate (
4108 struct peer *peer,
4109 void *rfd, /* set when looped from RFP/RFAPI */
4110 struct prefix *p,
4111 struct prefix_rd *prd,
4112 struct attr *attr,
4113 afi_t afi,
4114 safi_t safi,
4115 u_char type,
4116 u_char sub_type,
4117 uint32_t *label)
4118 {
4119 struct bgp *bgp;
4120 struct rfapi *h;
4121 struct rfapi_import_table *it;
4122 int has_ip_route = 1;
4123 uint32_t lni = 0;
4124
4125 bgp = bgp_get_default (); /* assume 1 instance for now */
4126 assert (bgp);
4127
4128 h = bgp->rfapi;
4129 assert (h);
4130
4131 /*
4132 * look at high-order byte of RD. FF means MAC
4133 * address is present (VNC L2VPN)
4134 */
4135 if ((safi == SAFI_MPLS_VPN) &&
4136 (decode_rd_type(prd->val) == RD_TYPE_VNC_ETH))
4137 {
4138 struct prefix pfx_mac_buf;
4139 struct prefix pfx_nexthop_buf;
4140 int rc;
4141
4142 /*
4143 * Set flag if prefix and nexthop are the same - don't
4144 * add the route to normal IP-based import tables
4145 */
4146 if (!rfapiGetNexthop (attr, &pfx_nexthop_buf))
4147 {
4148 if (!prefix_cmp (&pfx_nexthop_buf, p))
4149 {
4150 has_ip_route = 0;
4151 }
4152 }
4153
4154 memset (&pfx_mac_buf, 0, sizeof (pfx_mac_buf));
4155 pfx_mac_buf.family = AF_ETHERNET;
4156 pfx_mac_buf.prefixlen = 48;
4157 memcpy (&pfx_mac_buf.u.prefix_eth.octet, prd->val + 2, 6);
4158
4159 /*
4160 * Find rt containing LNI (Logical Network ID), which
4161 * _should_ always be present when mac address is present
4162 */
4163 rc = rfapiEcommunityGetLNI (attr->extra->ecommunity, &lni);
4164
4165 vnc_zlog_debug_verbose
4166 ("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p, attr->extra=%p",
4167 __func__, rc, lni, attr, attr->extra);
4168 if (attr && attr->extra && !rc)
4169 {
4170 it = rfapiMacImportTableGet (bgp, lni);
4171
4172 rfapiBgpInfoFilteredImportVPN (
4173 it,
4174 FIF_ACTION_UPDATE,
4175 peer,
4176 rfd,
4177 &pfx_mac_buf, /* prefix */
4178 p, /* aux prefix: IP addr */
4179 AFI_L2VPN,
4180 prd,
4181 attr,
4182 type,
4183 sub_type,
4184 label);
4185 }
4186
4187 }
4188
4189 if (!has_ip_route)
4190 return;
4191
4192 /*
4193 * Iterate over all import tables; do a filtered import
4194 * for the afi/safi combination
4195 */
4196 for (it = h->imports; it; it = it->next)
4197 {
4198 (*rfapiBgpInfoFilteredImportFunction (safi)) (
4199 it,
4200 FIF_ACTION_UPDATE,
4201 peer,
4202 rfd,
4203 p, /* prefix */
4204 NULL,
4205 afi,
4206 prd,
4207 attr,
4208 type,
4209 sub_type,
4210 label);
4211 }
4212
4213 if (safi == SAFI_MPLS_VPN)
4214 {
4215 vnc_direct_bgp_rh_add_route (bgp, afi, p, peer, attr);
4216 }
4217
4218 if (safi == SAFI_MPLS_VPN)
4219 {
4220 rfapiBgpInfoFilteredImportVPN (
4221 bgp->rfapi->it_ce,
4222 FIF_ACTION_UPDATE,
4223 peer,
4224 rfd,
4225 p, /* prefix */
4226 NULL,
4227 afi,
4228 prd,
4229 attr,
4230 type,
4231 sub_type,
4232 label);
4233 }
4234 }
4235
4236
4237 void
4238 rfapiProcessWithdraw (
4239 struct peer *peer,
4240 void *rfd,
4241 struct prefix *p,
4242 struct prefix_rd *prd,
4243 struct attr *attr,
4244 afi_t afi,
4245 safi_t safi,
4246 u_char type,
4247 int kill)
4248 {
4249 struct bgp *bgp;
4250 struct rfapi *h;
4251 struct rfapi_import_table *it;
4252
4253 bgp = bgp_get_default (); /* assume 1 instance for now */
4254 assert (bgp);
4255
4256 h = bgp->rfapi;
4257 assert (h);
4258
4259 /*
4260 * look at high-order byte of RD. FF means MAC
4261 * address is present (VNC L2VPN)
4262 */
4263 if (h->import_mac != NULL && safi == SAFI_MPLS_VPN &&
4264 decode_rd_type(prd->val) == RD_TYPE_VNC_ETH)
4265 {
4266 struct prefix pfx_mac_buf;
4267 void *cursor = NULL;
4268 int rc;
4269
4270 memset (&pfx_mac_buf, 0, sizeof (pfx_mac_buf));
4271 pfx_mac_buf.family = AF_ETHERNET;
4272 pfx_mac_buf.prefixlen = 48;
4273 memcpy (&pfx_mac_buf.u.prefix_eth, prd->val + 2, 6);
4274
4275 /*
4276 * withdraw does not contain attrs, so we don't have
4277 * access to the route's LNI, which would ordinarily
4278 * select the specific mac-based import table. Instead,
4279 * we must iterate over all mac-based tables and rely
4280 * on the RD to match.
4281 *
4282 * If this approach is too slow, add an index where
4283 * key is {RD, peer} and value is the import table
4284 */
4285 for (rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor);
4286 rc == 0;
4287 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor))
4288 {
4289
4290 #if DEBUG_L2_EXTRA
4291 vnc_zlog_debug_verbose
4292 ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
4293 __func__, it);
4294 #endif
4295
4296 rfapiBgpInfoFilteredImportVPN (
4297 it,
4298 (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
4299 peer,
4300 rfd,
4301 &pfx_mac_buf, /* prefix */
4302 p, /* aux_prefix: IP */
4303 AFI_L2VPN,
4304 prd,
4305 attr,
4306 type,
4307 0,
4308 NULL); /* sub_type & label unused for withdraw */
4309 }
4310 }
4311
4312 /*
4313 * XXX For the case where the withdraw involves an L2
4314 * route with no IP information, we rely on the lack
4315 * of RT-list intersection to filter out the withdraw
4316 * from the IP-based import tables below
4317 */
4318
4319 /*
4320 * Iterate over all import tables; do a filtered import
4321 * for the afi/safi combination
4322 */
4323
4324 for (it = h->imports; it; it = it->next)
4325 {
4326 (*rfapiBgpInfoFilteredImportFunction (safi)) (
4327 it,
4328 (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
4329 peer,
4330 rfd,
4331 p, /* prefix */
4332 NULL,
4333 afi,
4334 prd,
4335 attr,
4336 type,
4337 0,
4338 NULL); /* sub_type & label unused for withdraw */
4339 }
4340
4341 /* TBD the deletion should happen after the lifetime expires */
4342 if (safi == SAFI_MPLS_VPN)
4343 vnc_direct_bgp_rh_del_route (bgp, afi, p, peer);
4344
4345 if (safi == SAFI_MPLS_VPN)
4346 {
4347 rfapiBgpInfoFilteredImportVPN (
4348 bgp->rfapi->it_ce,
4349 (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
4350 peer,
4351 rfd,
4352 p, /* prefix */
4353 NULL,
4354 afi,
4355 prd,
4356 attr,
4357 type,
4358 0,
4359 NULL); /* sub_type & label unused for withdraw */
4360 }
4361 }
4362
4363 /*
4364 * TBD optimized withdraw timer algorithm for case of many
4365 * routes expiring at the same time due to peer drop.
4366 */
4367 /*
4368 * 1. Visit all BIs in all ENCAP import tables.
4369 *
4370 * a. If a bi's peer is the failed peer, remove the bi.
4371 * b. If the removed ENCAP bi was first in the list of
4372 * BIs at this ENCAP node, loop over all monitors
4373 * at this node:
4374 *
4375 * (1) for each ENCAP monitor, loop over all its
4376 * VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
4377 * flags.
4378 *
4379 * 2. Visit all BIs in all VPN import tables.
4380 * a. If a bi's peer is the failed peer, remove the bi.
4381 * b. loop over all the VPN node monitors and set their
4382 * RFAPI_MON_FLAG_NEEDCALLBACK flags
4383 * c. If there are no BIs left at this VPN node,
4384 *
4385 */
4386
4387
4388 /* surprise, this gets called from peer_delete(), from rfapi_close() */
4389 static void
4390 rfapiProcessPeerDownRt (
4391 struct peer *peer,
4392 struct rfapi_import_table *import_table,
4393 afi_t afi,
4394 safi_t safi)
4395 {
4396 struct route_node *rn;
4397 struct bgp_info *bi;
4398 struct route_table *rt;
4399 int (*timer_service_func) (struct thread *);
4400
4401 assert (afi == AFI_IP || afi == AFI_IP6);
4402
4403 VNC_ITRCCK;
4404
4405 switch (safi)
4406 {
4407 case SAFI_MPLS_VPN:
4408 rt = import_table->imported_vpn[afi];
4409 timer_service_func = rfapiWithdrawTimerVPN;
4410 break;
4411 case SAFI_ENCAP:
4412 rt = import_table->imported_encap[afi];
4413 timer_service_func = rfapiWithdrawTimerEncap;
4414 break;
4415 default:
4416 assert (0);
4417 }
4418
4419
4420 for (rn = route_top (rt); rn; rn = route_next (rn))
4421 {
4422 for (bi = rn->info; bi; bi = bi->next)
4423 {
4424 if (bi->peer == peer)
4425 {
4426
4427 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
4428 {
4429 /* already in holddown, skip */
4430 continue;
4431 }
4432
4433 if (safi == SAFI_MPLS_VPN)
4434 {
4435 RFAPI_UPDATE_ITABLE_COUNT (bi, import_table, afi, -1);
4436 import_table->holddown_count[afi] += 1;
4437 }
4438 rfapiBiStartWithdrawTimer (import_table, rn, bi,
4439 afi, safi,
4440 timer_service_func);
4441 }
4442 }
4443 }
4444 VNC_ITRCCK;
4445 }
4446
4447 /*
4448 * This gets called when a peer connection drops. We have to remove
4449 * all the routes from this peer.
4450 *
4451 * Current approach is crude. TBD Optimize by setting fewer timers and
4452 * grouping withdrawn routes so we can generate callbacks more
4453 * efficiently.
4454 */
4455 void
4456 rfapiProcessPeerDown (struct peer *peer)
4457 {
4458 struct bgp *bgp;
4459 struct rfapi *h;
4460 struct rfapi_import_table *it;
4461
4462 /*
4463 * If this peer is a "dummy" peer structure atached to a RFAPI
4464 * nve_descriptor, we don't need to walk the import tables
4465 * because the routes are already withdrawn by rfapi_close()
4466 */
4467 if (CHECK_FLAG (peer->flags, PEER_FLAG_IS_RFAPI_HD))
4468 return;
4469
4470 /*
4471 * 1. Visit all BIs in all ENCAP import tables.
4472 * Start withdraw timer on the BIs that match peer.
4473 *
4474 * 2. Visit All BIs in all VPN import tables.
4475 * Start withdraw timer on the BIs that match peer.
4476 */
4477
4478 bgp = bgp_get_default (); /* assume 1 instance for now */
4479 if (!bgp)
4480 return;
4481
4482 h = bgp->rfapi;
4483 assert (h);
4484
4485 for (it = h->imports; it; it = it->next)
4486 {
4487 rfapiProcessPeerDownRt (peer, it, AFI_IP, SAFI_ENCAP);
4488 rfapiProcessPeerDownRt (peer, it, AFI_IP6, SAFI_ENCAP);
4489 rfapiProcessPeerDownRt (peer, it, AFI_IP, SAFI_MPLS_VPN);
4490 rfapiProcessPeerDownRt (peer, it, AFI_IP6, SAFI_MPLS_VPN);
4491 }
4492
4493 if (h->it_ce)
4494 {
4495 rfapiProcessPeerDownRt (peer, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
4496 rfapiProcessPeerDownRt (peer, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
4497 }
4498 }
4499
4500 /*
4501 * Import an entire RIB (for an afi/safi) to an import table RIB,
4502 * filtered according to the import table's RT list
4503 *
4504 * TBD: does this function need additions to match rfapiProcessUpdate()
4505 * for, e.g., L2 handling?
4506 */
4507 static void
4508 rfapiBgpTableFilteredImport (
4509 struct bgp *bgp,
4510 struct rfapi_import_table *it,
4511 afi_t afi,
4512 safi_t safi)
4513 {
4514 struct bgp_node *rn1;
4515 struct bgp_node *rn2;
4516
4517 /* Only these SAFIs have 2-level RIBS */
4518 assert (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP);
4519
4520 /*
4521 * Now visit all the rd nodes and the nodes of all the
4522 * route tables attached to them, and import the routes
4523 * if they have matching route targets
4524 */
4525 for (rn1 = bgp_table_top (bgp->rib[afi][safi]);
4526 rn1; rn1 = bgp_route_next (rn1))
4527 {
4528
4529 if (rn1->info)
4530 {
4531 for (rn2 = bgp_table_top (rn1->info);
4532 rn2; rn2 = bgp_route_next (rn2))
4533 {
4534
4535 struct bgp_info *bi;
4536
4537 for (bi = rn2->info; bi; bi = bi->next)
4538 {
4539 u_int32_t label = 0;
4540
4541 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
4542 continue;
4543
4544 if (bi->extra)
4545 label = decode_label (bi->extra->tag);
4546 (*rfapiBgpInfoFilteredImportFunction (safi)) (
4547 it, /* which import table */
4548 FIF_ACTION_UPDATE,
4549 bi->peer,
4550 NULL,
4551 &rn2->p, /* prefix */
4552 NULL,
4553 afi,
4554 (struct prefix_rd *) &rn1->p,
4555 bi->attr,
4556 bi->type,
4557 bi->sub_type,
4558 &label);
4559 }
4560 }
4561 }
4562 }
4563 }
4564
4565
4566 /* per-bgp-instance rfapi data */
4567 struct rfapi *
4568 bgp_rfapi_new (struct bgp *bgp)
4569 {
4570 struct rfapi *h;
4571 int afi;
4572 struct rfapi_rfp_cfg *cfg = NULL;
4573 struct rfapi_rfp_cb_methods *cbm = NULL;
4574
4575 assert (bgp->rfapi_cfg == NULL);
4576
4577 h = (struct rfapi *) XCALLOC (MTYPE_RFAPI, sizeof (struct rfapi));
4578
4579 for (afi = AFI_IP; afi < AFI_MAX; afi++)
4580 {
4581 /* ugly, to deal with addition of delegates, part of 0.99.24.1 merge */
4582 h->un[afi].delegate = route_table_get_default_delegate ();
4583 }
4584
4585 /*
4586 * initialize the ce import table
4587 */
4588 h->it_ce =
4589 XCALLOC (MTYPE_RFAPI_IMPORTTABLE, sizeof (struct rfapi_import_table));
4590 h->it_ce->imported_vpn[AFI_IP] = route_table_init ();
4591 h->it_ce->imported_vpn[AFI_IP6] = route_table_init ();
4592 h->it_ce->imported_encap[AFI_IP] = route_table_init ();
4593 h->it_ce->imported_encap[AFI_IP6] = route_table_init ();
4594 rfapiBgpTableFilteredImport (bgp, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
4595 rfapiBgpTableFilteredImport (bgp, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
4596
4597 /*
4598 * Set up work queue for deferred rfapi_close operations
4599 */
4600 h->deferred_close_q = work_queue_new (bm->master, "rfapi deferred close");
4601 h->deferred_close_q->spec.workfunc = rfapi_deferred_close_workfunc;
4602 h->deferred_close_q->spec.data = h;
4603
4604 h->rfp = rfp_start (bm->master, &cfg, &cbm);
4605 bgp->rfapi_cfg = bgp_rfapi_cfg_new (cfg);
4606 if (cbm != NULL)
4607 {
4608 h->rfp_methods = *cbm;
4609 }
4610 return h;
4611 }
4612
4613 void
4614 bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h)
4615 {
4616 if (bgp == NULL || h == NULL)
4617 return;
4618
4619 if (h->resolve_nve_nexthop)
4620 {
4621 skiplist_free (h->resolve_nve_nexthop);
4622 h->resolve_nve_nexthop = NULL;
4623 }
4624
4625 route_table_finish (h->it_ce->imported_vpn[AFI_IP]);
4626 route_table_finish (h->it_ce->imported_vpn[AFI_IP6]);
4627 route_table_finish (h->it_ce->imported_encap[AFI_IP]);
4628 route_table_finish (h->it_ce->imported_encap[AFI_IP6]);
4629
4630 if (h->import_mac)
4631 {
4632 struct rfapi_import_table *it;
4633 void *cursor;
4634 int rc;
4635
4636 for (cursor = NULL,
4637 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor);
4638 !rc;
4639 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor))
4640 {
4641
4642 rfapiImportTableFlush (it);
4643 XFREE (MTYPE_RFAPI_IMPORTTABLE, it);
4644 }
4645 skiplist_free (h->import_mac);
4646 h->import_mac = NULL;
4647 }
4648
4649 work_queue_free (h->deferred_close_q);
4650
4651 if (h->rfp != NULL)
4652 rfp_stop (h->rfp);
4653 XFREE (MTYPE_RFAPI_IMPORTTABLE, h->it_ce);
4654 XFREE (MTYPE_RFAPI, h);
4655 }
4656
4657 struct rfapi_import_table *
4658 rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list,
4659 struct rfapi_nve_group_cfg *rfg)
4660 {
4661 struct rfapi *h;
4662 struct rfapi_import_table *it;
4663 afi_t afi;
4664
4665 h = bgp->rfapi;
4666 assert (h);
4667
4668 for (it = h->imports; it; it = it->next)
4669 {
4670 if (ecommunity_cmp (it->rt_import_list, rt_import_list))
4671 break;
4672 }
4673
4674 vnc_zlog_debug_verbose ("%s: matched it=%p", __func__, it);
4675
4676 if (!it)
4677 {
4678 it =
4679 XCALLOC (MTYPE_RFAPI_IMPORTTABLE, sizeof (struct rfapi_import_table));
4680 assert (it);
4681 it->next = h->imports;
4682 h->imports = it;
4683
4684 it->rt_import_list = ecommunity_dup (rt_import_list);
4685 it->rfg = rfg;
4686 it->monitor_exterior_orphans =
4687 skiplist_new (0, NULL, (void (*)(void *)) prefix_free);
4688
4689 /*
4690 * fill import route tables from RIBs
4691 *
4692 * Potential area for optimization. If this occurs when
4693 * tables are large (e.g., the operator adds a nve group
4694 * with a new RT list to a running system), it could take
4695 * a while.
4696 *
4697 */
4698 for (afi = AFI_IP; afi < AFI_MAX; ++afi)
4699 {
4700
4701 it->imported_vpn[afi] = route_table_init ();
4702 it->imported_encap[afi] = route_table_init ();
4703
4704 rfapiBgpTableFilteredImport (bgp, it, afi, SAFI_MPLS_VPN);
4705 rfapiBgpTableFilteredImport (bgp, it, afi, SAFI_ENCAP);
4706
4707 vnc_import_bgp_exterior_redist_enable_it (bgp, afi, it);
4708 }
4709 }
4710
4711 it->refcount += 1;
4712
4713 return it;
4714 }
4715
4716 /*
4717 * skiplist element free function
4718 */
4719 static void
4720 delete_rem_pfx_na_free (void *na)
4721 {
4722 uint32_t *pCounter = ((struct rfapi_nve_addr *) na)->info;
4723
4724 *pCounter += 1;
4725 XFREE (MTYPE_RFAPI_NVE_ADDR, na);
4726 }
4727
4728 /*
4729 * Common deleter for IP and MAC import tables
4730 */
4731 static void
4732 rfapiDeleteRemotePrefixesIt (
4733 struct bgp *bgp,
4734 struct rfapi_import_table *it,
4735 struct prefix *un,
4736 struct prefix *vn,
4737 struct prefix *p,
4738 int delete_active,
4739 int delete_holddown,
4740 uint32_t *pARcount,
4741 uint32_t *pAHcount,
4742 uint32_t *pHRcount,
4743 uint32_t *pHHcount,
4744 struct skiplist *uniq_active_nves,
4745 struct skiplist *uniq_holddown_nves)
4746 {
4747 afi_t afi;
4748
4749 #if DEBUG_L2_EXTRA
4750 {
4751 char buf_pfx[BUFSIZ];
4752
4753 if (p)
4754 {
4755 prefix2str (p, buf_pfx, BUFSIZ);
4756 }
4757 else
4758 {
4759 buf_pfx[0] = '*';
4760 buf_pfx[1] = 0;
4761 }
4762
4763 vnc_zlog_debug_verbose ("%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
4764 __func__, buf_pfx, delete_active, delete_holddown);
4765 }
4766 #endif
4767
4768 for (afi = AFI_IP; afi < AFI_MAX; ++afi)
4769 {
4770
4771 struct route_table *rt;
4772 struct route_node *rn;
4773
4774 if (p && (family2afi (p->family) != afi))
4775 {
4776 continue;
4777 }
4778
4779 rt = it->imported_vpn[afi];
4780 if (!rt)
4781 continue;
4782
4783 vnc_zlog_debug_verbose ("%s: scanning rt for afi=%d", __func__, afi);
4784
4785 for (rn = route_top (rt); rn; rn = route_next (rn))
4786 {
4787 struct bgp_info *bi;
4788 struct bgp_info *next;
4789
4790 if (VNC_DEBUG(IMPORT_DEL_REMOTE))
4791 {
4792 char p1line[BUFSIZ];
4793 char p2line[BUFSIZ];
4794
4795 prefix2str (p, p1line, BUFSIZ);
4796 prefix2str (&rn->p, p2line, BUFSIZ);
4797 vnc_zlog_debug_any ("%s: want %s, have %s", __func__, p1line, p2line);
4798 }
4799
4800 if (p && prefix_cmp (p, &rn->p))
4801 continue;
4802
4803 {
4804 char buf_pfx[BUFSIZ];
4805 prefix2str (&rn->p, buf_pfx, BUFSIZ);
4806 vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__, buf_pfx);
4807 }
4808
4809 /* TBD is this valid for afi == AFI_L2VPN? */
4810 RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1);
4811
4812 for (bi = rn->info; bi; bi = next)
4813 {
4814 next = bi->next;
4815
4816 struct prefix qpt;
4817 struct prefix qct;
4818 int qpt_valid = 0;
4819 int qct_valid = 0;
4820 int is_active = 0;
4821
4822 vnc_zlog_debug_verbose ("%s: examining bi %p", __func__, bi);
4823
4824 if (bi->attr)
4825 {
4826 if (!rfapiGetNexthop (bi->attr, &qpt))
4827 qpt_valid = 1;
4828 }
4829 if (vn)
4830 {
4831 if (!qpt_valid || !prefix_match (vn, &qpt))
4832 {
4833 #if DEBUG_L2_EXTRA
4834 vnc_zlog_debug_verbose
4835 ("%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
4836 __func__);
4837 #endif
4838 continue;
4839 }
4840 }
4841
4842 if (!rfapiGetUnAddrOfVpnBi (bi, &qct))
4843 qct_valid = 1;
4844
4845 if (un)
4846 {
4847 if (!qct_valid || !prefix_match (un, &qct))
4848 {
4849 #if DEBUG_L2_EXTRA
4850 vnc_zlog_debug_verbose
4851 ("%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
4852 __func__);
4853 #endif
4854 continue;
4855 }
4856 }
4857
4858
4859 /*
4860 * Blow bi away
4861 */
4862 /*
4863 * If this route is waiting to be deleted because of
4864 * a previous withdraw, we must cancel its timer.
4865 */
4866 if (CHECK_FLAG (bi->flags, BGP_INFO_REMOVED))
4867 {
4868 if (!delete_holddown)
4869 continue;
4870 if (bi->extra->vnc.import.timer)
4871 {
4872
4873 struct thread *t =
4874 (struct thread *) bi->extra->vnc.import.timer;
4875 struct rfapi_withdraw *wcb = t->arg;
4876
4877 wcb->import_table->holddown_count[afi] -= 1;
4878 RFAPI_UPDATE_ITABLE_COUNT (bi, wcb->import_table, afi,
4879 1);
4880 XFREE (MTYPE_RFAPI_WITHDRAW, wcb);
4881 thread_cancel (t);
4882 }
4883 }
4884 else
4885 {
4886 if (!delete_active)
4887 continue;
4888 is_active = 1;
4889 }
4890
4891 vnc_zlog_debug_verbose
4892 ("%s: deleting bi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
4893 __func__, bi, qct_valid, qpt_valid, delete_holddown,
4894 delete_active);
4895
4896
4897 /*
4898 * add nve to list
4899 */
4900 if (qct_valid && qpt_valid)
4901 {
4902
4903 struct rfapi_nve_addr na;
4904 struct rfapi_nve_addr *nap;
4905
4906 memset (&na, 0, sizeof (na));
4907 assert (!rfapiQprefix2Raddr (&qct, &na.un));
4908 assert (!rfapiQprefix2Raddr (&qpt, &na.vn));
4909
4910 if (skiplist_search ((is_active ? uniq_active_nves :
4911 uniq_holddown_nves), &na,
4912 (void **) &nap))
4913 {
4914 char line[BUFSIZ];
4915
4916 nap = XCALLOC (MTYPE_RFAPI_NVE_ADDR,
4917 sizeof (struct rfapi_nve_addr));
4918 assert (nap);
4919 *nap = na;
4920 nap->info = is_active ? pAHcount : pHHcount;
4921 skiplist_insert ((is_active ? uniq_active_nves :
4922 uniq_holddown_nves), nap, nap);
4923
4924 rfapiNveAddr2Str (nap, line, BUFSIZ);
4925 }
4926 }
4927
4928 vnc_direct_bgp_rh_del_route (bgp, afi, &rn->p, bi->peer);
4929
4930 RFAPI_UPDATE_ITABLE_COUNT (bi, it, afi, -1);
4931 it->holddown_count[afi] += 1;
4932 rfapiExpireVpnNow (it, rn, bi, 1);
4933
4934 vnc_zlog_debug_verbose ("%s: incrementing count (is_active=%d)",
4935 __func__, is_active);
4936
4937 if (is_active)
4938 ++ * pARcount;
4939 else
4940 ++ * pHRcount;
4941 }
4942 }
4943 }
4944 }
4945
4946
4947 /*
4948 * For use by the "clear vnc prefixes" command
4949 */
4950 /*------------------------------------------
4951 * rfapiDeleteRemotePrefixes
4952 *
4953 * UI helper: For use by the "clear vnc prefixes" command
4954 *
4955 * input:
4956 * un if set, tunnel must match this prefix
4957 * vn if set, nexthop prefix must match this prefix
4958 * p if set, prefix must match this prefix
4959 * it if set, only look in this import table
4960 *
4961 * output
4962 * pARcount number of active routes deleted
4963 * pAHcount number of active nves deleted
4964 * pHRcount number of holddown routes deleted
4965 * pHHcount number of holddown nves deleted
4966 *
4967 * return value:
4968 * void
4969 --------------------------------------------*/
4970 void
4971 rfapiDeleteRemotePrefixes (
4972 struct prefix *un,
4973 struct prefix *vn,
4974 struct prefix *p,
4975 struct rfapi_import_table *arg_it,
4976 int delete_active,
4977 int delete_holddown,
4978 uint32_t *pARcount,
4979 uint32_t *pAHcount,
4980 uint32_t *pHRcount,
4981 uint32_t *pHHcount)
4982 {
4983 struct bgp *bgp;
4984 struct rfapi *h;
4985 struct rfapi_import_table *it;
4986 uint32_t deleted_holddown_route_count = 0;
4987 uint32_t deleted_active_route_count = 0;
4988 uint32_t deleted_holddown_nve_count = 0;
4989 uint32_t deleted_active_nve_count = 0;
4990 struct skiplist *uniq_holddown_nves;
4991 struct skiplist *uniq_active_nves;
4992
4993 VNC_ITRCCK;
4994
4995 bgp = bgp_get_default (); /* assume 1 instance for now */
4996 /* If no bgp instantiated yet, no vnc prefixes exist */
4997 if (!bgp)
4998 return;
4999
5000 h = bgp->rfapi;
5001 assert (h);
5002
5003 uniq_holddown_nves =
5004 skiplist_new (0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
5005 uniq_active_nves =
5006 skiplist_new (0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
5007
5008 /*
5009 * Iterate over all import tables; do a filtered import
5010 * for the afi/safi combination
5011 */
5012
5013 if (arg_it)
5014 it = arg_it;
5015 else
5016 it = h->imports;
5017 for (; it; )
5018 {
5019
5020 vnc_zlog_debug_verbose
5021 ("%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
5022 __func__, it);
5023
5024 rfapiDeleteRemotePrefixesIt (
5025 bgp,
5026 it,
5027 un,
5028 vn,
5029 p,
5030 delete_active,
5031 delete_holddown,
5032 &deleted_active_route_count,
5033 &deleted_active_nve_count,
5034 &deleted_holddown_route_count,
5035 &deleted_holddown_nve_count,
5036 uniq_active_nves,
5037 uniq_holddown_nves);
5038
5039 if (arg_it)
5040 it = NULL;
5041 else
5042 it = it->next;
5043 }
5044
5045 /*
5046 * Now iterate over L2 import tables
5047 */
5048 if (h->import_mac && !(p && (p->family != AF_ETHERNET)))
5049 {
5050
5051 void *cursor = NULL;
5052 int rc;
5053
5054 for (cursor = NULL,
5055 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor);
5056 !rc;
5057 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor))
5058 {
5059
5060 vnc_zlog_debug_verbose
5061 ("%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
5062 __func__, it);
5063
5064 rfapiDeleteRemotePrefixesIt (
5065 bgp,
5066 it,
5067 un,
5068 vn,
5069 p,
5070 delete_active,
5071 delete_holddown,
5072 &deleted_active_route_count,
5073 &deleted_active_nve_count,
5074 &deleted_holddown_route_count,
5075 &deleted_holddown_nve_count,
5076 uniq_active_nves,
5077 uniq_holddown_nves);
5078 }
5079 }
5080
5081 /*
5082 * our custom element freeing function above counts as it deletes
5083 */
5084 skiplist_free (uniq_holddown_nves);
5085 skiplist_free (uniq_active_nves);
5086
5087 if (pARcount)
5088 *pARcount = deleted_active_route_count;
5089 if (pAHcount)
5090 *pAHcount = deleted_active_nve_count;
5091 if (pHRcount)
5092 *pHRcount = deleted_holddown_route_count;
5093 if (pHHcount)
5094 *pHHcount = deleted_holddown_nve_count;
5095
5096 VNC_ITRCCK;
5097 }
5098
5099 /*------------------------------------------
5100 * rfapiCountRemoteRoutes
5101 *
5102 * UI helper: count VRF routes from BGP side
5103 *
5104 * input:
5105 *
5106 * output
5107 * pALRcount count of active local routes
5108 * pARRcount count of active remote routes
5109 * pHRcount count of holddown routes
5110 * pIRcount count of direct imported routes
5111 *
5112 * return value:
5113 * void
5114 --------------------------------------------*/
5115 void
5116 rfapiCountAllItRoutes (int *pALRcount, /* active local routes */
5117 int *pARRcount, /* active remote routes */
5118 int *pHRcount, /* holddown routes */
5119 int *pIRcount) /* imported routes */
5120 {
5121 struct bgp *bgp;
5122 struct rfapi *h;
5123 struct rfapi_import_table *it;
5124 afi_t afi;
5125
5126 int total_active_local = 0;
5127 int total_active_remote = 0;
5128 int total_holddown = 0;
5129 int total_imported = 0;
5130
5131 bgp = bgp_get_default (); /* assume 1 instance for now */
5132 assert (bgp);
5133
5134 h = bgp->rfapi;
5135 assert (h);
5136
5137 /*
5138 * Iterate over all import tables; do a filtered import
5139 * for the afi/safi combination
5140 */
5141
5142 for (it = h->imports; it; it = it->next)
5143 {
5144
5145 for (afi = AFI_IP; afi < AFI_MAX; ++afi)
5146 {
5147
5148 total_active_local += it->local_count[afi];
5149 total_active_remote += it->remote_count[afi];
5150 total_holddown += it->holddown_count[afi];
5151 total_imported += it->imported_count[afi];
5152
5153 }
5154 }
5155
5156 void *cursor;
5157 int rc;
5158
5159 if (h->import_mac)
5160 {
5161 for (cursor = NULL,
5162 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor);
5163 !rc;
5164 rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor))
5165 {
5166
5167 total_active_local += it->local_count[AFI_L2VPN];
5168 total_active_remote += it->remote_count[AFI_L2VPN];
5169 total_holddown += it->holddown_count[AFI_L2VPN];
5170 total_imported += it->imported_count[AFI_L2VPN];
5171
5172 }
5173 }
5174
5175
5176 if (pALRcount)
5177 {
5178 *pALRcount = total_active_local;
5179 }
5180 if (pARRcount)
5181 {
5182 *pARRcount = total_active_remote;
5183 }
5184 if (pHRcount)
5185 {
5186 *pHRcount = total_holddown;
5187 }
5188 if (pIRcount)
5189 {
5190 *pIRcount = total_imported;
5191 }
5192 }
5193
5194 /*------------------------------------------
5195 * rfapiGetHolddownFromLifetime
5196 *
5197 * calculate holddown value based on lifetime
5198 *
5199 * input:
5200 * lifetime lifetime
5201 *
5202 * return value:
5203 * Holddown value based on lifetime, holddown_factor,
5204 * and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
5205 *
5206 --------------------------------------------*/
5207 /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
5208 uint32_t
5209 rfapiGetHolddownFromLifetime (uint32_t lifetime)
5210 {
5211 uint32_t factor;
5212 struct bgp *bgp;
5213
5214 bgp = bgp_get_default ();
5215 if (bgp && bgp->rfapi_cfg)
5216 factor = bgp->rfapi_cfg->rfp_cfg.holddown_factor;
5217 else
5218 factor = RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR;
5219
5220 if (factor < 100 || lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
5221 lifetime = lifetime * factor / 100;
5222 if (lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
5223 return lifetime;
5224 else
5225 return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY;
5226 }