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