]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/vnc_export_bgp.c
* : update signature of thread_cancel api
[mirror_frr.git] / bgpd / rfapi / vnc_export_bgp.c
1 /*
2 *
3 * Copyright 2009-2016, LabN Consulting, L.L.C.
4 *
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 * File: vnc_export_bgp.c
23 * Purpose: Export routes to BGP directly (not via zebra)
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/log.h"
31 #include "lib/stream.h"
32 #include "lib/memory.h"
33 #include "lib/linklist.h"
34 #include "lib/plist.h"
35 #include "lib/routemap.h"
36 #include "lib/lib_errors.h"
37
38 #include "bgpd/bgpd.h"
39 #include "bgpd/bgp_ecommunity.h"
40 #include "bgpd/bgp_attr.h"
41 #include "bgpd/bgp_aspath.h"
42
43 #include "bgpd/rfapi/vnc_export_bgp.h"
44 #include "bgpd/rfapi/vnc_export_bgp_p.h"
45 #include "bgpd/rfapi/vnc_export_table.h"
46 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
47 #include "bgpd/rfapi/rfapi.h"
48 #include "bgpd/rfapi/rfapi_import.h"
49 #include "bgpd/rfapi/rfapi_private.h"
50 #include "bgpd/rfapi/rfapi_backend.h"
51 #include "bgpd/rfapi/rfapi_vty.h"
52 #include "bgpd/rfapi/vnc_debug.h"
53
54
55 static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
56 struct rfapi_nve_group_cfg *rfg,
57 struct agg_node *rn, struct attr *attr,
58 afi_t afi,
59 struct rfapi_descriptor *irfd);
60
61 /***********************************************************************
62 * Export methods that set nexthop to CE (from 5226 roo EC) BEGIN
63 ***********************************************************************/
64
65 /*
66 * Memory allocation approach: make a ghost attr that
67 * has non-interned parts for the modifications. ghost attr
68 * memory is allocated by caller.
69 *
70 * - extract ce (=5226) EC and use as new nexthop
71 * - strip Tunnel Encap attr
72 * - copy all ECs
73 */
74 static void encap_attr_export_ce(struct attr *new, struct attr *orig,
75 struct prefix *use_nexthop)
76 {
77 /*
78 * Make "new" a ghost attr copy of "orig"
79 */
80 memset(new, 0, sizeof(struct attr));
81 *new = *orig;
82
83 /*
84 * Set nexthop
85 */
86 switch (use_nexthop->family) {
87 case AF_INET:
88 new->nexthop = use_nexthop->u.prefix4;
89 new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
90 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
91 break;
92
93 case AF_INET6:
94 new->mp_nexthop_global = use_nexthop->u.prefix6;
95 new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
96 break;
97
98 default:
99 assert(0);
100 break;
101 }
102
103 /*
104 * Set MED
105 *
106 * Note that it will be deleted when BGP sends to any eBGP
107 * peer unless PEER_FLAG_MED_UNCHANGED is set:
108 *
109 * neighbor NEIGHBOR attribute-unchanged med
110 */
111 if (!CHECK_FLAG(new->flag, BGP_ATTR_MULTI_EXIT_DISC)) {
112 if (CHECK_FLAG(new->flag, BGP_ATTR_LOCAL_PREF)) {
113 if (new->local_pref > 255)
114 new->med = 0;
115 else
116 new->med = 255 - new->local_pref;
117 } else {
118 new->med = 255; /* shouldn't happen */
119 }
120 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
121 }
122
123 /*
124 * "new" is now a ghost attr:
125 * - it owns an "extra" struct
126 * - it owns any non-interned parts
127 * - any references to interned parts are not counted
128 *
129 * Caller should, after using the attr, call:
130 * - bgp_attr_flush() to free non-interned parts
131 */
132 }
133
134 static int getce(struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce)
135 {
136 uint8_t *ecp;
137 int i;
138 uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin;
139
140 for (ecp = attr->ecommunity->val, i = 0; i < attr->ecommunity->size;
141 ++i, ecp += ECOMMUNITY_SIZE) {
142
143 if (VNC_DEBUG(EXPORT_BGP_GETCE)) {
144 vnc_zlog_debug_any(
145 "%s: %02x %02x %02x %02x %02x %02x %02x %02x",
146 __func__, ecp[0], ecp[1], ecp[2], ecp[3],
147 ecp[4], ecp[5], ecp[6], ecp[7]);
148 }
149
150 /*
151 * is it ROO?
152 */
153 if (ecp[0] != 1 || ecp[1] != 3) {
154 continue;
155 }
156
157 /*
158 * Match local admin value?
159 */
160 if (ecp[6] != ((localadmin & 0xff00) >> 8)
161 || ecp[7] != (localadmin & 0xff))
162 continue;
163
164 memset((uint8_t *)pfx_ce, 0, sizeof(*pfx_ce));
165 memcpy(&pfx_ce->u.prefix4, ecp + 2, 4);
166 pfx_ce->family = AF_INET;
167 pfx_ce->prefixlen = 32;
168
169 return 0;
170 }
171 return -1;
172 }
173
174
175 void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct agg_node *rn,
176 struct bgp_path_info *bpi)
177 {
178 struct attr *attr = bpi->attr;
179 struct peer *peer = bpi->peer;
180 const struct prefix *prefix = agg_node_get_prefix(rn);
181 afi_t afi = family2afi(prefix->family);
182 struct bgp_dest *udest;
183 struct bgp_path_info *ubpi;
184 struct attr hattr;
185 struct attr *iattr;
186 struct prefix ce_nexthop;
187 struct prefix post_routemap_nexthop;
188
189
190 if (!afi) {
191 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node",
192 __func__);
193 return;
194 }
195
196 if ((bpi->type != ZEBRA_ROUTE_BGP)
197 || (bpi->sub_type != BGP_ROUTE_NORMAL
198 && bpi->sub_type != BGP_ROUTE_RFP
199 && bpi->sub_type != BGP_ROUTE_STATIC)) {
200
201 vnc_zlog_debug_verbose(
202 "%s: wrong route type/sub_type for export, skipping",
203 __func__);
204 return;
205 }
206
207 /* check bgp redist flag for vnc direct ("vpn") routes */
208 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
209 vnc_zlog_debug_verbose(
210 "%s: bgp redistribution of VNC direct routes is off",
211 __func__);
212 return;
213 }
214
215 if (!bgp->rfapi_cfg) {
216 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
217 __func__);
218 return;
219 }
220
221 if (!VNC_EXPORT_BGP_CE_ENABLED(bgp->rfapi_cfg)) {
222 vnc_zlog_debug_verbose(
223 "%s: export-to-bgp ce mode not enabled, skipping",
224 __func__);
225 return;
226 }
227
228 /*
229 * prefix list check
230 */
231 if (bgp->rfapi_cfg->plist_export_bgp[afi]) {
232 if (prefix_list_apply(bgp->rfapi_cfg->plist_export_bgp[afi],
233 prefix)
234 == PREFIX_DENY) {
235 vnc_zlog_debug_verbose(
236 "%s: prefix list denied, skipping", __func__);
237 return;
238 }
239 }
240
241
242 /*
243 * Extract CE
244 * This works only for IPv4 because IPv6 addresses are too big
245 * to fit in an extended community
246 */
247 if (getce(bgp, attr, &ce_nexthop)) {
248 vnc_zlog_debug_verbose("%s: EC has no encoded CE, skipping",
249 __func__);
250 return;
251 }
252
253 /*
254 * Is this route already represented in the unicast RIB?
255 * (look up prefix; compare route type, sub_type, peer, nexthop)
256 */
257 udest = bgp_afi_node_get(bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST,
258 prefix, NULL);
259 for (ubpi = bgp_dest_get_bgp_path_info(udest); ubpi;
260 ubpi = ubpi->next) {
261 struct prefix unicast_nexthop;
262
263 if (CHECK_FLAG(ubpi->flags, BGP_PATH_REMOVED))
264 continue;
265
266 rfapiUnicastNexthop2Prefix(afi, ubpi->attr, &unicast_nexthop);
267
268 if (ubpi->type == ZEBRA_ROUTE_VNC_DIRECT
269 && ubpi->sub_type == BGP_ROUTE_REDISTRIBUTE
270 && ubpi->peer == peer
271 && prefix_same(&unicast_nexthop, &ce_nexthop)) {
272
273 vnc_zlog_debug_verbose(
274 "%s: already have matching exported unicast route, skipping",
275 __func__);
276 return;
277 }
278 }
279
280 /*
281 * Construct new attribute set with CE addr as
282 * nexthop and without Tunnel Encap attr
283 */
284 encap_attr_export_ce(&hattr, attr, &ce_nexthop);
285 if (bgp->rfapi_cfg->routemap_export_bgp) {
286 struct bgp_path_info info;
287 route_map_result_t ret;
288
289 memset(&info, 0, sizeof(info));
290 info.peer = peer;
291 info.attr = &hattr;
292 ret = route_map_apply(bgp->rfapi_cfg->routemap_export_bgp,
293 prefix, RMAP_BGP, &info);
294 if (ret == RMAP_DENYMATCH) {
295 bgp_attr_flush(&hattr);
296 return;
297 }
298 }
299
300 iattr = bgp_attr_intern(&hattr);
301 bgp_attr_flush(&hattr);
302
303 /*
304 * Rule: disallow route-map alteration of next-hop, because it
305 * would make it too difficult to keep track of the correspondence
306 * between VPN routes and unicast routes.
307 */
308 rfapiUnicastNexthop2Prefix(afi, iattr, &post_routemap_nexthop);
309
310 if (!prefix_same(&ce_nexthop, &post_routemap_nexthop)) {
311 vnc_zlog_debug_verbose(
312 "%s: route-map modification of nexthop not allowed, skipping",
313 __func__);
314 bgp_attr_unintern(&iattr);
315 return;
316 }
317
318 bgp_update(peer, prefix, 0, /* addpath_id */
319 iattr, /* bgp_update copies this attr */
320 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
321 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
322 NULL, 0, /* tag not used for unicast */
323 0, NULL); /* EVPN not used */
324 bgp_attr_unintern(&iattr);
325 }
326
327
328 /*
329 * "Withdrawing a Route" export process
330 */
331 void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn,
332 struct bgp_path_info *bpi)
333 {
334 const struct prefix *p = agg_node_get_prefix(rn);
335 afi_t afi = family2afi(p->family);
336 struct bgp_path_info *vbpi;
337 struct prefix ce_nexthop;
338
339 if (!afi) {
340 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi", __func__);
341 return;
342 }
343
344 /* check bgp redist flag for vnc direct ("vpn") routes */
345 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
346 vnc_zlog_debug_verbose(
347 "%s: bgp redistribution of VNC direct routes is off",
348 __func__);
349 return;
350 }
351
352 if (!bgp->rfapi_cfg) {
353 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
354 __func__);
355 return;
356 }
357 if (!VNC_EXPORT_BGP_CE_ENABLED(bgp->rfapi_cfg)) {
358 vnc_zlog_debug_verbose(
359 "%s: export-to-bgp ce mode not enabled, skipping",
360 __func__);
361 return;
362 }
363
364 /*
365 * Extract CE
366 * This works only for IPv4 because IPv6 addresses are too big
367 * to fit in an extended community
368 */
369 if (getce(bgp, bpi->attr, &ce_nexthop)) {
370 vnc_zlog_debug_verbose("%s: EC has no encoded CE, skipping",
371 __func__);
372 return;
373 }
374
375 /*
376 * Look for other VPN routes with same prefix, same 5226 CE,
377 * same peer. If at least one is present, don't remove the
378 * route from the unicast RIB
379 */
380
381 for (vbpi = rn->info; vbpi; vbpi = vbpi->next) {
382 struct prefix ce;
383 if (bpi == vbpi)
384 continue;
385 if (bpi->peer != vbpi->peer)
386 continue;
387 if (getce(bgp, vbpi->attr, &ce))
388 continue;
389 if (prefix_same(&ce, &ce_nexthop)) {
390 vnc_zlog_debug_verbose(
391 "%s: still have a route via CE, not deleting unicast",
392 __func__);
393 return;
394 }
395 }
396
397 /*
398 * withdraw the route
399 */
400 bgp_withdraw(bpi->peer, p, 0, /* addpath_id */
401 NULL, /* attr, ignored */
402 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
403 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
404 NULL, 0, NULL); /* tag not used for unicast */
405 }
406
407 static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
408 {
409 struct agg_node *rn;
410 struct bgp_path_info *ri;
411
412 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
413
414 if (!bgp)
415 return;
416
417 if (!(bgp->rfapi_cfg))
418 return;
419
420 if (!VNC_EXPORT_BGP_CE_ENABLED(bgp->rfapi_cfg)) {
421 vnc_zlog_debug_verbose(
422 "%s: export of CE routes not enabled, skipping",
423 __func__);
424 return;
425 }
426
427 if (afi != AFI_IP && afi != AFI_IP6) {
428 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
429 return;
430 }
431
432 /*
433 * Go through entire ce import table and export to BGP unicast.
434 */
435 for (rn = agg_route_top(bgp->rfapi->it_ce->imported_vpn[afi]); rn;
436 rn = agg_route_next(rn)) {
437 if (!rn->info)
438 continue;
439
440 vnc_zlog_debug_verbose("%s: checking prefix %pRN", __func__,
441 rn);
442
443 for (ri = rn->info; ri; ri = ri->next) {
444
445 vnc_zlog_debug_verbose("%s: ri->sub_type: %d", __func__,
446 ri->sub_type);
447
448 if (ri->sub_type == BGP_ROUTE_NORMAL
449 || ri->sub_type == BGP_ROUTE_RFP
450 || ri->sub_type == BGP_ROUTE_STATIC) {
451
452 vnc_direct_bgp_add_route_ce(bgp, rn, ri);
453 }
454 }
455 }
456 }
457
458 static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
459 {
460 struct bgp_dest *dest;
461
462 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
463
464 if (!bgp)
465 return;
466
467 if (afi != AFI_IP && afi != AFI_IP6) {
468 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
469 return;
470 }
471
472 /*
473 * Go through the entire BGP unicast table and remove routes that
474 * originated from us
475 */
476 for (dest = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); dest;
477 dest = bgp_route_next(dest)) {
478
479 struct bgp_path_info *ri;
480 struct bgp_path_info *next;
481
482 for (ri = bgp_dest_get_bgp_path_info(dest), next = NULL; ri;
483 ri = next) {
484
485 next = ri->next;
486
487 if (ri->type == ZEBRA_ROUTE_VNC_DIRECT
488 && ri->sub_type == BGP_ROUTE_REDISTRIBUTE) {
489
490 bgp_withdraw(
491 ri->peer, bgp_dest_get_prefix(dest),
492 0, /* addpath_id */
493 NULL, /* ignored */
494 AFI_IP, SAFI_UNICAST,
495 ZEBRA_ROUTE_VNC_DIRECT,
496 BGP_ROUTE_REDISTRIBUTE,
497 NULL, /* RD not used for unicast */
498 NULL, 0,
499 NULL); /* tag not used for unicast */
500 }
501 }
502 }
503 }
504
505 /***********************************************************************
506 * Export methods that set nexthop to CE (from 5226 roo EC) END
507 ***********************************************************************/
508
509 /***********************************************************************
510 * Export methods that proxy nexthop BEGIN
511 ***********************************************************************/
512
513 static struct ecommunity *vnc_route_origin_ecom(struct agg_node *rn)
514 {
515 struct ecommunity *new;
516 struct bgp_path_info *bpi;
517
518 if (!rn->info)
519 return NULL;
520
521 new = ecommunity_new();
522
523 for (bpi = rn->info; bpi; bpi = bpi->next) {
524
525 struct ecommunity_val roec;
526
527 switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) {
528 case AF_INET:
529 memset(&roec, 0, sizeof(roec));
530 roec.val[0] = 0x01;
531 roec.val[1] = 0x03;
532 memcpy(roec.val + 2,
533 &bpi->attr->mp_nexthop_global_in.s_addr, 4);
534 roec.val[6] = 0;
535 roec.val[7] = 0;
536 ecommunity_add_val(new, &roec, false, false);
537 break;
538 case AF_INET6:
539 /* No support for IPv6 addresses in extended communities
540 */
541 break;
542 }
543 }
544
545 if (!new->size) {
546 ecommunity_free(&new);
547 new = NULL;
548 }
549
550 return new;
551 }
552
553 static struct ecommunity *vnc_route_origin_ecom_single(struct in_addr *origin)
554 {
555 struct ecommunity *new;
556 struct ecommunity_val roec;
557
558 memset(&roec, 0, sizeof(roec));
559 roec.val[0] = 0x01;
560 roec.val[1] = 0x03;
561 memcpy(roec.val + 2, &origin->s_addr, 4);
562 roec.val[6] = 0;
563 roec.val[7] = 0;
564
565 new = ecommunity_new();
566 assert(new);
567 ecommunity_add_val(new, &roec, false, false);
568
569 if (!new->size) {
570 ecommunity_free(&new);
571 new = NULL;
572 }
573
574 return new;
575 }
576
577
578 /*
579 * New memory allocation approach: make a ghost attr that
580 * has non-interned parts for the modifications. ghost attr
581 * memory is allocated by caller.
582 */
583 static int
584 encap_attr_export(struct attr *new, struct attr *orig,
585 struct prefix *new_nexthop,
586 struct agg_node *rn) /* for VN addrs for ecom list */
587 /* if rn is 0, use route's nexthop */
588 {
589 struct prefix orig_nexthop;
590 struct prefix *use_nexthop;
591 static struct ecommunity *ecom_ro;
592
593 if (new_nexthop) {
594 use_nexthop = new_nexthop;
595 } else {
596 use_nexthop = &orig_nexthop;
597 orig_nexthop.family =
598 BGP_MP_NEXTHOP_FAMILY(orig->mp_nexthop_len);
599 if (orig_nexthop.family == AF_INET) {
600 orig_nexthop.prefixlen = 32;
601 orig_nexthop.u.prefix4 = orig->mp_nexthop_global_in;
602 } else if (orig_nexthop.family == AF_INET6) {
603 orig_nexthop.prefixlen = 128;
604 orig_nexthop.u.prefix6 = orig->mp_nexthop_global;
605 } else {
606 return -1; /* FAIL - can't compute nexthop */
607 }
608 }
609
610
611 /*
612 * Make "new" a ghost attr copy of "orig"
613 */
614 memset(new, 0, sizeof(struct attr));
615 *new = *orig;
616
617 /*
618 * Set nexthop
619 */
620 switch (use_nexthop->family) {
621 case AF_INET:
622 new->nexthop = use_nexthop->u.prefix4;
623 new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
624 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
625 break;
626
627 case AF_INET6:
628 new->mp_nexthop_global = use_nexthop->u.prefix6;
629 new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
630 break;
631
632 default:
633 assert(0);
634 break;
635 }
636
637 if (rn) {
638 ecom_ro = vnc_route_origin_ecom(rn);
639 } else {
640 /* TBD use lcom for IPv6 */
641 ecom_ro = vnc_route_origin_ecom_single(&use_nexthop->u.prefix4);
642 }
643 if (new->ecommunity) {
644 if (ecom_ro)
645 new->ecommunity =
646 ecommunity_merge(ecom_ro, new->ecommunity);
647 } else {
648 new->ecommunity = ecom_ro;
649 }
650 if (ecom_ro) {
651 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
652 }
653
654 /*
655 * Set MED
656 *
657 * Note that it will be deleted when BGP sends to any eBGP
658 * peer unless PEER_FLAG_MED_UNCHANGED is set:
659 *
660 * neighbor NEIGHBOR attribute-unchanged med
661 */
662 if (!CHECK_FLAG(new->flag, BGP_ATTR_MULTI_EXIT_DISC)) {
663 if (CHECK_FLAG(new->flag, BGP_ATTR_LOCAL_PREF)) {
664 if (new->local_pref > 255)
665 new->med = 0;
666 else
667 new->med = 255 - new->local_pref;
668 } else {
669 new->med = 255; /* shouldn't happen */
670 }
671 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
672 }
673
674 /*
675 * "new" is now a ghost attr:
676 * - it owns an "extra" struct
677 * - it owns any non-interned parts
678 * - any references to interned parts are not counted
679 *
680 * Caller should, after using the attr, call:
681 * - bgp_attr_flush() to free non-interned parts
682 */
683
684 return 0;
685 }
686
687 /*
688 * "Adding a Route" export process
689 */
690 void vnc_direct_bgp_add_prefix(struct bgp *bgp,
691 struct rfapi_import_table *import_table,
692 struct agg_node *rn)
693 {
694 struct attr attr = {0};
695 struct listnode *node, *nnode;
696 struct rfapi_rfg_name *rfgn;
697 const struct prefix *p = agg_node_get_prefix(rn);
698 afi_t afi = family2afi(p->family);
699
700 if (!afi) {
701 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node",
702 __func__);
703 return;
704 }
705
706 /* check bgp redist flag for vnc direct ("vpn") routes */
707 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
708 vnc_zlog_debug_verbose(
709 "%s: bgp redistribution of VNC direct routes is off",
710 __func__);
711 return;
712 }
713
714 if (!bgp->rfapi_cfg) {
715 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
716 __func__);
717 return;
718 }
719
720 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
721 vnc_zlog_debug_verbose(
722 "%s: export-to-bgp group mode not enabled, skipping",
723 __func__);
724 return;
725 }
726
727 if (!listcount(bgp->rfapi_cfg->rfg_export_direct_bgp_l)) {
728 vnc_zlog_debug_verbose(
729 "%s: no bgp-direct export nve group, skipping",
730 __func__);
731 return;
732 }
733
734 bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
735 /* TBD set some configured med, see add_vnc_route() */
736
737 vnc_zlog_debug_verbose(
738 "%s: looping over nve-groups in direct-bgp export list",
739 __func__);
740
741 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
742 nnode, rfgn)) {
743
744 struct listnode *ln;
745
746 /*
747 * If nve group is not defined yet, skip it
748 */
749 if (!rfgn->rfg)
750 continue;
751
752 /*
753 * If the nve group uses a different import table, skip it
754 */
755 if (import_table != rfgn->rfg->rfapi_import_table)
756 continue;
757
758 /*
759 * if no NVEs currently associated with this group, skip it
760 */
761 if (rfgn->rfg->type != RFAPI_GROUP_CFG_VRF && !rfgn->rfg->nves)
762 continue;
763
764 /*
765 * per-nve-group prefix list check
766 */
767 if (rfgn->rfg->plist_export_bgp[afi]) {
768 if (prefix_list_apply(rfgn->rfg->plist_export_bgp[afi],
769 p)
770 == PREFIX_DENY)
771
772 continue;
773 }
774
775 if (rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
776 vnc_direct_add_rn_group_rd(bgp, rfgn->rfg, rn, &attr,
777 afi, rfgn->rfg->rfd);
778 /*
779 * yuck!
780 * - but consistent with rest of function
781 */
782 continue;
783 }
784 /*
785 * For each NVE that is assigned to the export nve group,
786 * generate
787 * a route with that NVE as its next hop
788 */
789 for (ln = listhead(rfgn->rfg->nves); ln;
790 ln = listnextnode(ln)) {
791 vnc_direct_add_rn_group_rd(bgp, rfgn->rfg, rn, &attr,
792 afi, listgetdata(ln));
793 }
794 }
795
796 aspath_unintern(&attr.aspath);
797 }
798
799 /*
800 * "Withdrawing a Route" export process
801 */
802 void vnc_direct_bgp_del_prefix(struct bgp *bgp,
803 struct rfapi_import_table *import_table,
804 struct agg_node *rn)
805 {
806 struct listnode *node, *nnode;
807 struct rfapi_rfg_name *rfgn;
808 const struct prefix *p = agg_node_get_prefix(rn);
809 afi_t afi = family2afi(p->family);
810
811 if (!afi) {
812 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi route node",
813 __func__);
814 return;
815 }
816
817 /* check bgp redist flag for vnc direct ("vpn") routes */
818 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
819 vnc_zlog_debug_verbose(
820 "%s: bgp redistribution of VNC direct routes is off",
821 __func__);
822 return;
823 }
824
825 if (!bgp->rfapi_cfg) {
826 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
827 __func__);
828 return;
829 }
830
831 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
832 vnc_zlog_debug_verbose(
833 "%s: export-to-bgp group mode not enabled, skipping",
834 __func__);
835 return;
836 }
837
838 if (!listcount(bgp->rfapi_cfg->rfg_export_direct_bgp_l)) {
839 vnc_zlog_debug_verbose(
840 "%s: no bgp-direct export nve group, skipping",
841 __func__);
842 return;
843 }
844
845 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
846 nnode, rfgn)) {
847
848 struct listnode *ln;
849
850 /*
851 * If nve group is not defined yet, skip it
852 */
853 if (!rfgn->rfg)
854 continue;
855
856 /*
857 * if no NVEs currently associated with this group, skip it
858 */
859 if (rfgn->rfg->type != RFAPI_GROUP_CFG_VRF && !rfgn->rfg->nves)
860 continue;
861
862 /*
863 * If the nve group uses a different import table,
864 * skip it
865 */
866 if (import_table != rfgn->rfg->rfapi_import_table)
867 continue;
868
869 if (rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
870 struct prefix nhp;
871 struct rfapi_descriptor *irfd;
872
873 irfd = rfgn->rfg->rfd;
874
875 if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
876 continue;
877
878 bgp_withdraw(irfd->peer, p, /* prefix */
879 0, /* addpath_id */
880 NULL, /* attr, ignored */
881 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
882 BGP_ROUTE_REDISTRIBUTE,
883 NULL, /* RD not used for unicast */
884 NULL, 0,
885 NULL); /* tag not used for unicast */
886 /*
887 * yuck!
888 * - but consistent with rest of function
889 */
890 continue;
891 }
892 /*
893 * For each NVE that is assigned to the export nve group,
894 * generate
895 * a route with that NVE as its next hop
896 */
897 for (ln = listhead(rfgn->rfg->nves); ln;
898 ln = listnextnode(ln)) {
899
900 struct prefix nhp;
901 struct rfapi_descriptor *irfd;
902
903 irfd = listgetdata(ln);
904
905 if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
906 continue;
907
908 bgp_withdraw(irfd->peer, p, /* prefix */
909 0, /* addpath_id */
910 NULL, /* attr, ignored */
911 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
912 BGP_ROUTE_REDISTRIBUTE,
913 NULL, /* RD not used for unicast */
914 NULL, 0,
915 NULL); /* tag not used for unicast */
916 }
917 }
918 }
919
920 void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
921 {
922 struct listnode *node, *nnode;
923 struct rfapi_rfg_name *rfgn;
924 struct rfapi_nve_group_cfg *rfg = rfd->rfg;
925 afi_t afi = family2afi(rfd->vn_addr.addr_family);
926
927 if (!afi) {
928 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of nve vn addr",
929 __func__);
930 return;
931 }
932
933 if (!bgp)
934 return;
935 if (!bgp->rfapi_cfg) {
936 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
937 __func__);
938 return;
939 }
940 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
941 vnc_zlog_debug_verbose(
942 "%s: export-to-bgp group mode not enabled, skipping",
943 __func__);
944 return;
945 }
946
947 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
948 vnc_zlog_debug_verbose(
949 "%s: bgp redistribution of VNC direct routes is off",
950 __func__);
951 return;
952 }
953
954 /*
955 * Loop over the list of NVE-Groups configured for
956 * exporting to direct-bgp and see if this new NVE's
957 * group is among them.
958 */
959 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
960 nnode, rfgn)) {
961
962 /*
963 * Yes, this NVE's group is configured for export to direct-bgp
964 */
965 if (rfgn->rfg == rfg) {
966
967 struct agg_table *rt = NULL;
968 struct agg_node *rn;
969 struct attr attr = {0};
970 struct rfapi_import_table *import_table;
971
972
973 import_table = rfg->rfapi_import_table;
974
975 bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
976 /* TBD set some configured med, see add_vnc_route() */
977
978 if (afi == AFI_IP || afi == AFI_IP6) {
979 rt = import_table->imported_vpn[afi];
980 } else {
981 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d",
982 __func__, afi);
983 return;
984 }
985
986 /*
987 * Walk the NVE-Group's VNC Import table
988 */
989 for (rn = agg_route_top(rt); rn;
990 rn = agg_route_next(rn)) {
991
992 if (rn->info) {
993
994 struct prefix nhp;
995 struct rfapi_descriptor *irfd = rfd;
996 struct attr hattr;
997 struct attr *iattr;
998 struct bgp_path_info info;
999 const struct prefix *p =
1000 agg_node_get_prefix(rn);
1001
1002 if (rfapiRaddr2Qprefix(&irfd->vn_addr,
1003 &nhp))
1004 continue;
1005
1006 /*
1007 * per-nve-group prefix list check
1008 */
1009 if (rfgn->rfg->plist_export_bgp[afi]) {
1010 if (prefix_list_apply(
1011 rfgn->rfg->plist_export_bgp
1012 [afi],
1013 p)
1014 == PREFIX_DENY)
1015
1016 continue;
1017 }
1018
1019
1020 /*
1021 * Construct new attribute set with
1022 * NVE's VN addr as
1023 * nexthop and without Tunnel Encap attr
1024 */
1025 if (encap_attr_export(&hattr, &attr,
1026 &nhp, rn))
1027 continue;
1028
1029 if (rfgn->rfg->routemap_export_bgp) {
1030 route_map_result_t ret;
1031 info.peer = irfd->peer;
1032 info.attr = &hattr;
1033 ret = route_map_apply(
1034 rfgn->rfg
1035 ->routemap_export_bgp,
1036 p, RMAP_BGP, &info);
1037 if (ret == RMAP_DENYMATCH) {
1038 bgp_attr_flush(&hattr);
1039 continue;
1040 }
1041 }
1042
1043 iattr = bgp_attr_intern(&hattr);
1044 bgp_attr_flush(&hattr);
1045 bgp_update(
1046 irfd->peer, p, /* prefix */
1047 0, /* addpath_id */
1048 iattr, /* bgp_update copies
1049 it */
1050 afi, SAFI_UNICAST,
1051 ZEBRA_ROUTE_VNC_DIRECT,
1052 BGP_ROUTE_REDISTRIBUTE, NULL,
1053 /* RD not used for unicast */
1054 NULL,
1055 /* tag not used for unicast */
1056 0, 0, NULL); /* EVPN not used */
1057
1058 bgp_attr_unintern(&iattr);
1059 }
1060 }
1061
1062 aspath_unintern(&attr.aspath);
1063 }
1064 }
1065 }
1066
1067
1068 void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
1069 {
1070 struct listnode *node, *nnode;
1071 struct rfapi_rfg_name *rfgn;
1072 struct rfapi_nve_group_cfg *rfg = rfd->rfg;
1073 afi_t afi = family2afi(rfd->vn_addr.addr_family);
1074
1075 if (!afi) {
1076 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of nve vn addr",
1077 __func__);
1078 return;
1079 }
1080
1081 if (!bgp)
1082 return;
1083 if (!bgp->rfapi_cfg) {
1084 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
1085 __func__);
1086 return;
1087 }
1088 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
1089 vnc_zlog_debug_verbose(
1090 "%s: export-to-bgp group mode not enabled, skipping",
1091 __func__);
1092 return;
1093 }
1094
1095 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
1096 vnc_zlog_debug_verbose(
1097 "%s: bgp redistribution of VNC direct routes is off",
1098 __func__);
1099 return;
1100 }
1101
1102 /*
1103 * Loop over the list of NVE-Groups configured for
1104 * exporting to direct-bgp and see if this new NVE's
1105 * group is among them.
1106 */
1107 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
1108 nnode, rfgn)) {
1109
1110 /*
1111 * Yes, this NVE's group is configured for export to direct-bgp
1112 */
1113 if (rfg && rfgn->rfg == rfg) {
1114
1115 struct agg_table *rt = NULL;
1116 struct agg_node *rn;
1117 struct rfapi_import_table *import_table;
1118
1119 import_table = rfg->rfapi_import_table;
1120
1121 if (afi == AFI_IP || afi == AFI_IP6) {
1122 rt = import_table->imported_vpn[afi];
1123 } else {
1124 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d",
1125 __func__, afi);
1126 return;
1127 }
1128
1129 /*
1130 * Walk the NVE-Group's VNC Import table
1131 */
1132 for (rn = agg_route_top(rt); rn;
1133 rn = agg_route_next(rn)) {
1134
1135 if (rn->info) {
1136 const struct prefix *p =
1137 agg_node_get_prefix(rn);
1138 struct prefix nhp;
1139 struct rfapi_descriptor *irfd = rfd;
1140
1141 if (rfapiRaddr2Qprefix(&irfd->vn_addr,
1142 &nhp))
1143 continue;
1144
1145 bgp_withdraw(irfd->peer, p, /* prefix */
1146 0, /* addpath_id */
1147 NULL, /* attr, ignored */
1148 afi, SAFI_UNICAST,
1149 ZEBRA_ROUTE_VNC_DIRECT,
1150 BGP_ROUTE_REDISTRIBUTE,
1151 NULL, /* RD not used for
1152 unicast */
1153 NULL, 0, NULL); /* tag not
1154 used for
1155 unicast */
1156 }
1157 }
1158 }
1159 }
1160 }
1161
1162 static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
1163 struct rfapi_nve_group_cfg *rfg,
1164 struct agg_node *rn, struct attr *attr,
1165 afi_t afi, struct rfapi_descriptor *irfd)
1166 {
1167 struct prefix nhp;
1168 struct bgp_path_info info;
1169 struct attr hattr;
1170 struct attr *iattr;
1171 const struct prefix *p = agg_node_get_prefix(rn);
1172
1173 if (irfd == NULL && rfg->type != RFAPI_GROUP_CFG_VRF) {
1174 /* need new rfapi_handle, for peer strcture
1175 * -- based on vnc_add_vrf_prefi */
1176 assert(rfg->rfd == NULL);
1177
1178 if (!rfg->rt_export_list || !rfg->rfapi_import_table) {
1179 vnc_zlog_debug_verbose(
1180 "%s: VRF \"%s\" is missing RT import/export configuration.\n",
1181 __func__, rfg->name);
1182 return;
1183 }
1184 if (!rfg->rd.prefixlen) {
1185 vnc_zlog_debug_verbose(
1186 "%s: VRF \"%s\" is missing RD configuration.\n",
1187 __func__, rfg->name);
1188 return;
1189 }
1190 if (rfg->label > MPLS_LABEL_MAX) {
1191 vnc_zlog_debug_verbose(
1192 "%s: VRF \"%s\" is missing default label configuration.\n",
1193 __func__, rfg->name);
1194 return;
1195 }
1196
1197 irfd = XCALLOC(MTYPE_RFAPI_DESC,
1198 sizeof(struct rfapi_descriptor));
1199 irfd->bgp = bgp;
1200 rfg->rfd = irfd;
1201 /*
1202 * leave most fields empty as will get from (dynamic) config
1203 * when needed
1204 */
1205 irfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS;
1206 irfd->cookie = rfg;
1207 if (rfg->vn_prefix.family
1208 && !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF)) {
1209 rfapiQprefix2Raddr(&rfg->vn_prefix, &irfd->vn_addr);
1210 } else {
1211 memset(&irfd->vn_addr, 0, sizeof(struct rfapi_ip_addr));
1212 irfd->vn_addr.addr_family = AF_INET;
1213 irfd->vn_addr.addr.v4 = bgp->router_id;
1214 }
1215 irfd->un_addr = irfd->vn_addr; /* sigh, need something in UN for
1216 lookups */
1217 vnc_zlog_debug_verbose("%s: Opening RFD for VRF %s", __func__,
1218 rfg->name);
1219 rfapi_init_and_open(bgp, irfd, rfg);
1220 }
1221
1222 if (irfd == NULL || rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
1223 return;
1224
1225 /*
1226 * Construct new attribute set with NVE's VN
1227 * addr as
1228 * nexthop and without Tunnel Encap attr
1229 */
1230 if (encap_attr_export(&hattr, attr, &nhp, rn))
1231 return;
1232
1233 if (VNC_DEBUG(EXPORT_BGP_DIRECT_ADD)) {
1234 vnc_zlog_debug_any("%s: attr follows", __func__);
1235 rfapiPrintAttrPtrs(NULL, attr);
1236 vnc_zlog_debug_any("%s: hattr follows", __func__);
1237 rfapiPrintAttrPtrs(NULL, &hattr);
1238 }
1239
1240 if (rfg->routemap_export_bgp) {
1241 route_map_result_t ret;
1242
1243 info.peer = irfd->peer;
1244 info.attr = &hattr;
1245 ret = route_map_apply(rfg->routemap_export_bgp, p, RMAP_BGP,
1246 &info);
1247 if (ret == RMAP_DENYMATCH) {
1248 bgp_attr_flush(&hattr);
1249 vnc_zlog_debug_verbose(
1250 "%s: route map says DENY, so not calling bgp_update",
1251 __func__);
1252 return;
1253 }
1254 }
1255
1256 if (VNC_DEBUG(EXPORT_BGP_DIRECT_ADD)) {
1257 vnc_zlog_debug_any("%s: hattr after route_map_apply:",
1258 __func__);
1259 rfapiPrintAttrPtrs(NULL, &hattr);
1260 }
1261 iattr = bgp_attr_intern(&hattr);
1262 bgp_attr_flush(&hattr);
1263
1264 bgp_update(irfd->peer, p, /* prefix */
1265 0, /* addpath_id */
1266 iattr, /* bgp_update copies it */
1267 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
1268 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
1269 NULL, /* tag not used for unicast */
1270 0, 0, NULL); /* EVPN not used */
1271
1272 bgp_attr_unintern(&iattr);
1273
1274 return;
1275 }
1276
1277 /*
1278 * Caller is responsible for ensuring that the specified nve-group
1279 * is actually part of the list of exported nve groups.
1280 */
1281 static void vnc_direct_bgp_add_group_afi(struct bgp *bgp,
1282 struct rfapi_nve_group_cfg *rfg,
1283 afi_t afi)
1284 {
1285 struct agg_table *rt = NULL;
1286 struct agg_node *rn;
1287 struct attr attr = {0};
1288 struct rfapi_import_table *import_table;
1289
1290 vnc_zlog_debug_verbose("%s: entry", __func__);
1291
1292 import_table = rfg->rfapi_import_table;
1293 if (!import_table) {
1294 vnc_zlog_debug_verbose(
1295 "%s: import table not defined, returning", __func__);
1296 return;
1297 }
1298
1299 if (afi == AFI_IP || afi == AFI_IP6) {
1300 rt = import_table->imported_vpn[afi];
1301 } else {
1302 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
1303 return;
1304 }
1305
1306 if (!rfg->nves && rfg->type != RFAPI_GROUP_CFG_VRF) {
1307 vnc_zlog_debug_verbose("%s: no NVEs in this group", __func__);
1308 return;
1309 }
1310
1311 bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
1312 /* TBD set some configured med, see add_vnc_route() */
1313
1314 /*
1315 * Walk the NVE-Group's VNC Import table
1316 */
1317 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1318
1319 if (rn->info) {
1320 const struct prefix *p = agg_node_get_prefix(rn);
1321 struct listnode *ln;
1322
1323 /*
1324 * per-nve-group prefix list check
1325 */
1326 if (rfg->plist_export_bgp[afi]) {
1327 if (prefix_list_apply(
1328 rfg->plist_export_bgp[afi], p)
1329 == PREFIX_DENY)
1330
1331 continue;
1332 }
1333 if (rfg->type == RFAPI_GROUP_CFG_VRF) {
1334 vnc_direct_add_rn_group_rd(bgp, rfg, rn, &attr,
1335 afi, rfg->rfd);
1336 /*
1337 * yuck!
1338 * - but consistent with rest of function
1339 */
1340 continue;
1341 }
1342 /*
1343 * For each NVE that is assigned to the export nve
1344 * group, generate
1345 * a route with that NVE as its next hop
1346 */
1347 for (ln = listhead(rfg->nves); ln;
1348 ln = listnextnode(ln)) {
1349 vnc_direct_add_rn_group_rd(bgp, rfg, rn, &attr,
1350 afi,
1351 listgetdata(ln));
1352 }
1353 }
1354 }
1355
1356 aspath_unintern(&attr.aspath);
1357 }
1358
1359
1360 /*
1361 * Caller is responsible for ensuring that the specified nve-group
1362 * is actually part of the list of exported nve groups.
1363 */
1364 void vnc_direct_bgp_add_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
1365 {
1366 vnc_direct_bgp_add_group_afi(bgp, rfg, AFI_IP);
1367 vnc_direct_bgp_add_group_afi(bgp, rfg, AFI_IP6);
1368 }
1369
1370 static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
1371 struct rfapi_nve_group_cfg *rfg,
1372 struct agg_node *rn, afi_t afi,
1373 struct rfapi_descriptor *irfd)
1374 {
1375 if (irfd == NULL)
1376 return;
1377
1378 bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), /* prefix */
1379 0, /* addpath_id */
1380 NULL, /* attr, ignored */
1381 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
1382 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
1383 NULL, 0, NULL); /* tag not used for unicast */
1384 return;
1385 }
1386
1387 /*
1388 * Caller is responsible for ensuring that the specified nve-group
1389 * was actually part of the list of exported nve groups.
1390 */
1391 static void vnc_direct_bgp_del_group_afi(struct bgp *bgp,
1392 struct rfapi_nve_group_cfg *rfg,
1393 afi_t afi)
1394 {
1395 struct agg_table *rt = NULL;
1396 struct agg_node *rn;
1397 struct rfapi_import_table *import_table;
1398
1399 vnc_zlog_debug_verbose("%s: entry", __func__);
1400
1401 import_table = rfg->rfapi_import_table;
1402 if (!import_table) {
1403 vnc_zlog_debug_verbose(
1404 "%s: import table not defined, returning", __func__);
1405 return;
1406 }
1407
1408 rt = import_table->imported_vpn[afi];
1409
1410 if (!rfg->nves && rfg->type != RFAPI_GROUP_CFG_VRF) {
1411 vnc_zlog_debug_verbose("%s: no NVEs in this group", __func__);
1412 return;
1413 }
1414
1415 /*
1416 * Walk the NVE-Group's VNC Import table
1417 */
1418 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn))
1419 if (rn->info) {
1420 if (rfg->type == RFAPI_GROUP_CFG_VRF)
1421 vnc_direct_del_rn_group_rd(bgp, rfg, rn, afi,
1422 rfg->rfd);
1423 else {
1424 struct listnode *ln;
1425
1426 /*
1427 * For each NVE that is assigned to the export
1428 * nve
1429 * group, generate
1430 * a route with that NVE as its next hop
1431 */
1432 for (ln = listhead(rfg->nves); ln;
1433 ln = listnextnode(ln))
1434 vnc_direct_del_rn_group_rd(
1435 bgp, rfg, rn, afi,
1436 listgetdata(ln));
1437 }
1438 }
1439 }
1440
1441 /*
1442 * Caller is responsible for ensuring that the specified nve-group
1443 * was actually part of the list of exported nve groups.
1444 */
1445 void vnc_direct_bgp_del_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
1446 {
1447 vnc_direct_bgp_del_group_afi(bgp, rfg, AFI_IP);
1448 vnc_direct_bgp_del_group_afi(bgp, rfg, AFI_IP6);
1449 }
1450
1451 void vnc_direct_bgp_reexport_group_afi(struct bgp *bgp,
1452 struct rfapi_nve_group_cfg *rfg,
1453 afi_t afi)
1454 {
1455 struct listnode *node;
1456 struct rfapi_rfg_name *rfgn;
1457
1458 if (VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
1459 /*
1460 * look in the list of currently-exported groups
1461 */
1462 for (ALL_LIST_ELEMENTS_RO(
1463 bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
1464 rfgn)) {
1465
1466 if (rfgn->rfg == rfg) {
1467 /*
1468 * If it matches, reexport it
1469 */
1470 vnc_direct_bgp_del_group_afi(bgp, rfg, afi);
1471 vnc_direct_bgp_add_group_afi(bgp, rfg, afi);
1472 break;
1473 }
1474 }
1475 }
1476 }
1477
1478
1479 static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
1480 struct list *nve_list)
1481 {
1482 if (nve_list) {
1483
1484 struct agg_node *rn;
1485
1486 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1487
1488 if (rn->info) {
1489
1490 struct listnode *hln;
1491 struct rfapi_descriptor *irfd;
1492
1493 for (ALL_LIST_ELEMENTS_RO(nve_list, hln,
1494 irfd)) {
1495
1496 bgp_withdraw(irfd->peer,
1497 agg_node_get_prefix(rn),
1498 0, /* addpath_id */
1499 NULL, /* attr, ignored */
1500 afi, SAFI_UNICAST,
1501 ZEBRA_ROUTE_VNC_DIRECT,
1502 BGP_ROUTE_REDISTRIBUTE,
1503 NULL, /* RD not used for
1504 unicast */
1505 NULL, 0, NULL); /* tag not
1506 used for
1507 unicast,
1508 EVPN
1509 neither */
1510 }
1511 }
1512 }
1513 }
1514 }
1515
1516 static void import_table_to_nve_list_direct_bgp(struct bgp *bgp,
1517 struct rfapi_import_table *it,
1518 struct list **nves,
1519 uint8_t family)
1520 {
1521 struct listnode *node;
1522 struct rfapi_rfg_name *rfgn;
1523
1524 /*
1525 * Loop over the list of NVE-Groups configured for
1526 * exporting to direct-bgp.
1527 *
1528 * Build a list of NVEs that use this import table
1529 */
1530 *nves = NULL;
1531 for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
1532 rfgn)) {
1533
1534 /*
1535 * If this NVE-Group's import table matches the current one
1536 */
1537 if (rfgn->rfg && rfgn->rfg->rfapi_import_table == it) {
1538 if (rfgn->rfg->nves)
1539 nve_group_to_nve_list(rfgn->rfg, nves, family);
1540 else if (rfgn->rfg->rfd
1541 && rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
1542 if (!*nves)
1543 *nves = list_new();
1544 listnode_add(*nves, rfgn->rfg->rfd);
1545 }
1546 }
1547 }
1548 }
1549
1550 void vnc_direct_bgp_vpn_enable(struct bgp *bgp, afi_t afi)
1551 {
1552 struct listnode *rfgn;
1553 struct rfapi_nve_group_cfg *rfg;
1554
1555 if (!bgp)
1556 return;
1557
1558 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
1559 vnc_zlog_debug_verbose(
1560 "%s: export-to-bgp group mode not enabled, skipping",
1561 __func__);
1562 return;
1563 }
1564
1565 if (afi != AFI_IP && afi != AFI_IP6) {
1566 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1567 return;
1568 }
1569
1570 /*
1571 * Policy is applied per-nve-group, so we need to iterate
1572 * over the groups to add everything.
1573 */
1574 for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->nve_groups_sequential, rfgn,
1575 rfg)) {
1576
1577 /*
1578 * contains policy management
1579 */
1580 vnc_direct_bgp_add_group_afi(bgp, rfg, afi);
1581 }
1582 }
1583
1584
1585 void vnc_direct_bgp_vpn_disable(struct bgp *bgp, afi_t afi)
1586 {
1587 struct rfapi_import_table *it;
1588 uint8_t family = afi2family(afi);
1589
1590 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
1591
1592 if (!bgp)
1593 return;
1594
1595 if (!bgp->rfapi) {
1596 vnc_zlog_debug_verbose("%s: rfapi not initialized", __func__);
1597 return;
1598 }
1599
1600 if (!family || (afi != AFI_IP && afi != AFI_IP6)) {
1601 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1602 return;
1603 }
1604
1605 for (it = bgp->rfapi->imports; it; it = it->next) {
1606
1607 struct list *nve_list = NULL;
1608
1609 import_table_to_nve_list_direct_bgp(bgp, it, &nve_list, family);
1610
1611 if (nve_list) {
1612 vnc_direct_bgp_unexport_table(
1613 afi, it->imported_vpn[afi], nve_list);
1614 list_delete(&nve_list);
1615 }
1616 }
1617 }
1618
1619
1620 /***********************************************************************
1621 * Export methods that proxy nexthop END
1622 ***********************************************************************/
1623
1624
1625 /***********************************************************************
1626 * Export methods that preserve original nexthop BEGIN
1627 * rh = "registering nve"
1628 ***********************************************************************/
1629
1630
1631 /*
1632 * "Adding a Route" export process
1633 * TBD do we need to check bpi->type and bpi->sub_type here, or does
1634 * caller do it?
1635 */
1636 void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
1637 const struct prefix *prefix, struct peer *peer,
1638 struct attr *attr)
1639 {
1640 struct vnc_export_info *eti;
1641 struct attr hattr;
1642 struct rfapi_cfg *hc;
1643 struct attr *iattr;
1644
1645 if (!afi) {
1646 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node",
1647 __func__);
1648 return;
1649 }
1650
1651 /* check bgp redist flag for vnc direct ("vpn") routes */
1652 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
1653 vnc_zlog_debug_verbose(
1654 "%s: bgp redistribution of VNC direct routes is off",
1655 __func__);
1656 return;
1657 }
1658
1659 if (!(hc = bgp->rfapi_cfg)) {
1660 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
1661 __func__);
1662 return;
1663 }
1664
1665 if (!VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
1666 vnc_zlog_debug_verbose(
1667 "%s: export-to-bgp RH mode not enabled, skipping",
1668 __func__);
1669 return;
1670 }
1671
1672 /*
1673 * prefix list check
1674 */
1675 if (hc->plist_export_bgp[afi]) {
1676 if (prefix_list_apply(hc->plist_export_bgp[afi], prefix)
1677 == PREFIX_DENY)
1678 return;
1679 }
1680
1681 /*
1682 * Construct new attribute set with NVE's VN addr as
1683 * nexthop and without Tunnel Encap attr
1684 */
1685 if (encap_attr_export(&hattr, attr, NULL, NULL))
1686 return;
1687 if (hc->routemap_export_bgp) {
1688 struct bgp_path_info info;
1689 route_map_result_t ret;
1690
1691 memset(&info, 0, sizeof(info));
1692 info.peer = peer;
1693 info.attr = &hattr;
1694 ret = route_map_apply(hc->routemap_export_bgp, prefix, RMAP_BGP,
1695 &info);
1696 if (ret == RMAP_DENYMATCH) {
1697 bgp_attr_flush(&hattr);
1698 return;
1699 }
1700 }
1701
1702 iattr = bgp_attr_intern(&hattr);
1703 bgp_attr_flush(&hattr);
1704
1705 /*
1706 * record route information that we will need to expire
1707 * this route
1708 */
1709 eti = vnc_eti_get(bgp, EXPORT_TYPE_BGP, prefix, peer,
1710 ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE);
1711 rfapiGetVncLifetime(attr, &eti->lifetime);
1712 eti->lifetime = rfapiGetHolddownFromLifetime(eti->lifetime);
1713
1714 /*
1715 * export expiration timer is already running on
1716 * this route: cancel it
1717 */
1718 thread_cancel(&eti->timer);
1719
1720 bgp_update(peer, prefix, /* prefix */
1721 0, /* addpath_id */
1722 iattr, /* bgp_update copies this attr */
1723 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH,
1724 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
1725 NULL, /* tag not used for unicast, EVPN neither */
1726 0, 0, NULL); /* EVPN not used */
1727 bgp_attr_unintern(&iattr);
1728 }
1729
1730 static int vncExportWithdrawTimer(struct thread *t)
1731 {
1732 struct vnc_export_info *eti = t->arg;
1733 const struct prefix *p = agg_node_get_prefix(eti->node);
1734
1735 /*
1736 * withdraw the route
1737 */
1738 bgp_withdraw(eti->peer, p, 0, /* addpath_id */
1739 NULL, /* attr, ignored */
1740 family2afi(p->family), SAFI_UNICAST, eti->type,
1741 eti->subtype, NULL, /* RD not used for unicast */
1742 NULL, 0,
1743 NULL); /* tag not used for unicast, EVPN neither */
1744
1745 /*
1746 * Free the eti
1747 */
1748 vnc_eti_delete(eti);
1749
1750 return 0;
1751 }
1752
1753 /*
1754 * "Withdrawing a Route" export process
1755 * TBD do we need to check bpi->type and bpi->sub_type here, or does
1756 * caller do it?
1757 */
1758 void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi,
1759 const struct prefix *prefix, struct peer *peer)
1760 {
1761 struct vnc_export_info *eti;
1762
1763 if (!afi) {
1764 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi route node",
1765 __func__);
1766 return;
1767 }
1768
1769 /* check bgp redist flag for vnc direct ("vpn") routes */
1770 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
1771 vnc_zlog_debug_verbose(
1772 "%s: bgp redistribution of VNC direct routes is off",
1773 __func__);
1774 return;
1775 }
1776
1777 if (!bgp->rfapi_cfg) {
1778 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
1779 __func__);
1780 return;
1781 }
1782 if (!VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
1783 vnc_zlog_debug_verbose(
1784 "%s: export-to-bgp group mode not enabled, skipping",
1785 __func__);
1786 return;
1787 }
1788
1789 eti = vnc_eti_get(bgp, EXPORT_TYPE_BGP, prefix, peer,
1790 ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE);
1791
1792 if (!eti->timer && eti->lifetime <= INT32_MAX) {
1793 eti->timer = NULL;
1794 thread_add_timer(bm->master, vncExportWithdrawTimer, eti,
1795 eti->lifetime, &eti->timer);
1796 vnc_zlog_debug_verbose(
1797 "%s: set expiration timer for %u seconds", __func__,
1798 eti->lifetime);
1799 }
1800 }
1801
1802
1803 void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
1804 {
1805 struct prefix_rd prd;
1806 struct bgp_dest *pdest;
1807 struct rfapi_cfg *hc;
1808
1809 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
1810
1811 if (!bgp)
1812 return;
1813
1814 if (!(hc = bgp->rfapi_cfg))
1815 return;
1816
1817 if (!VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
1818 vnc_zlog_debug_verbose(
1819 "%s: export of RH routes not enabled, skipping",
1820 __func__);
1821 return;
1822 }
1823
1824 if (afi != AFI_IP && afi != AFI_IP6) {
1825 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1826 return;
1827 }
1828
1829 /*
1830 * Go through the entire BGP VPN table and export to BGP unicast.
1831 */
1832
1833 vnc_zlog_debug_verbose("%s: starting RD loop", __func__);
1834
1835 /* Loop over all the RDs */
1836 for (pdest = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); pdest;
1837 pdest = bgp_route_next(pdest)) {
1838
1839 struct bgp_table *table;
1840 struct bgp_dest *dest;
1841 struct bgp_path_info *ri;
1842 const struct prefix *pdest_p = bgp_dest_get_prefix(pdest);
1843
1844 memset(&prd, 0, sizeof(prd));
1845 prd.family = AF_UNSPEC;
1846 prd.prefixlen = 64;
1847 memcpy(prd.val, pdest_p->u.val, 8);
1848
1849 /* This is the per-RD table of prefixes */
1850 table = bgp_dest_get_bgp_table_info(pdest);
1851
1852 if (!table)
1853 continue;
1854
1855 for (dest = bgp_table_top(table); dest;
1856 dest = bgp_route_next(dest)) {
1857 const struct prefix *dest_p;
1858
1859 /*
1860 * skip prefix list check if no routes here
1861 */
1862 if (!bgp_dest_has_bgp_path_info_data(dest))
1863 continue;
1864
1865 vnc_zlog_debug_verbose("%s: checking prefix %pBD",
1866 __func__, dest);
1867
1868 dest_p = bgp_dest_get_prefix(dest);
1869
1870 /*
1871 * prefix list check
1872 */
1873 if (hc->plist_export_bgp[afi]) {
1874 if (prefix_list_apply(hc->plist_export_bgp[afi],
1875 dest_p)
1876 == PREFIX_DENY) {
1877
1878 vnc_zlog_debug_verbose(
1879 "%s: prefix list says DENY",
1880 __func__);
1881 continue;
1882 }
1883 }
1884
1885 for (ri = bgp_dest_get_bgp_path_info(dest); ri;
1886 ri = ri->next) {
1887
1888 vnc_zlog_debug_verbose("%s: ri->sub_type: %d",
1889 __func__, ri->sub_type);
1890
1891 if (ri->sub_type == BGP_ROUTE_NORMAL
1892 || ri->sub_type == BGP_ROUTE_RFP) {
1893
1894 struct vnc_export_info *eti;
1895 struct attr hattr;
1896 struct attr *iattr;
1897
1898 /*
1899 * Construct new attribute set with
1900 * NVE's VN addr as
1901 * nexthop and without Tunnel Encap attr
1902 */
1903 if (encap_attr_export(&hattr, ri->attr,
1904 NULL, NULL)) {
1905 vnc_zlog_debug_verbose(
1906 "%s: encap_attr_export failed",
1907 __func__);
1908 continue;
1909 }
1910
1911 if (hc->routemap_export_bgp) {
1912 struct bgp_path_info info;
1913 route_map_result_t ret;
1914
1915 memset(&info, 0, sizeof(info));
1916 info.peer = ri->peer;
1917 info.attr = &hattr;
1918 ret = route_map_apply(
1919 hc->routemap_export_bgp,
1920 dest_p, RMAP_BGP,
1921 &info);
1922 if (ret == RMAP_DENYMATCH) {
1923 bgp_attr_flush(&hattr);
1924 vnc_zlog_debug_verbose(
1925 "%s: route map says DENY",
1926 __func__);
1927 continue;
1928 }
1929 }
1930
1931 iattr = bgp_attr_intern(&hattr);
1932 bgp_attr_flush(&hattr);
1933
1934 /*
1935 * record route information that we will
1936 * need to expire
1937 * this route
1938 */
1939 eti = vnc_eti_get(
1940 bgp, EXPORT_TYPE_BGP, dest_p,
1941 ri->peer,
1942 ZEBRA_ROUTE_VNC_DIRECT_RH,
1943 BGP_ROUTE_REDISTRIBUTE);
1944 rfapiGetVncLifetime(ri->attr,
1945 &eti->lifetime);
1946
1947 /*
1948 * export expiration timer is
1949 * already running on
1950 * this route: cancel it
1951 */
1952 thread_cancel(&eti->timer);
1953
1954 vnc_zlog_debug_verbose(
1955 "%s: calling bgp_update",
1956 __func__);
1957
1958 bgp_update(
1959 ri->peer, dest_p, /* prefix */
1960 0, /* addpath_id */
1961 iattr, /* bgp_update copies
1962 it */
1963 AFI_IP, SAFI_UNICAST,
1964 ZEBRA_ROUTE_VNC_DIRECT_RH,
1965 BGP_ROUTE_REDISTRIBUTE, NULL,
1966 /* RD not used for unicast */
1967 NULL,
1968 /* tag not used for unicast,
1969 or EVPN */
1970 0, 0, NULL); /* EVPN not used */
1971
1972 bgp_attr_unintern(&iattr);
1973 }
1974 }
1975 }
1976 }
1977 }
1978
1979 void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
1980 {
1981 struct bgp_dest *dest;
1982
1983 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
1984
1985 if (!bgp)
1986 return;
1987
1988 if (afi != AFI_IP && afi != AFI_IP6) {
1989 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1990 return;
1991 }
1992
1993 /*
1994 * Go through the entire BGP unicast table and remove routes that
1995 * originated from us
1996 */
1997 for (dest = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); dest;
1998 dest = bgp_route_next(dest)) {
1999 const struct prefix *dest_p = bgp_dest_get_prefix(dest);
2000 struct bgp_path_info *ri;
2001 struct bgp_path_info *next;
2002
2003 for (ri = bgp_dest_get_bgp_path_info(dest), next = NULL; ri;
2004 ri = next) {
2005
2006 next = ri->next;
2007
2008 if (ri->type == ZEBRA_ROUTE_VNC_DIRECT_RH
2009 && ri->sub_type == BGP_ROUTE_REDISTRIBUTE) {
2010
2011 struct vnc_export_info *eti;
2012
2013 /*
2014 * Delete routes immediately (no timer)
2015 */
2016 eti = vnc_eti_checktimer(
2017 bgp, EXPORT_TYPE_BGP, dest_p, ri->peer,
2018 ZEBRA_ROUTE_VNC_DIRECT_RH,
2019 BGP_ROUTE_REDISTRIBUTE);
2020 if (eti) {
2021 thread_cancel(&eti->timer);
2022 vnc_eti_delete(eti);
2023 }
2024
2025 bgp_withdraw(ri->peer, dest_p, /* prefix */
2026 0, /* addpath_id */
2027 NULL, /* ignored */
2028 AFI_IP, SAFI_UNICAST,
2029 ZEBRA_ROUTE_VNC_DIRECT_RH,
2030 BGP_ROUTE_REDISTRIBUTE,
2031 NULL, /* RD not used for unicast */
2032 NULL, 0, NULL); /* tag not used for
2033 unicast, EVPN
2034 neither */
2035 }
2036 }
2037 }
2038 }
2039
2040 void vnc_direct_bgp_rh_reexport(struct bgp *bgp, afi_t afi)
2041 {
2042 if (VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
2043 vnc_direct_bgp_rh_vpn_disable(bgp, afi);
2044 vnc_direct_bgp_rh_vpn_enable(bgp, afi);
2045 }
2046 }
2047
2048 /***********************************************************************
2049 * Generic Export methods
2050 ***********************************************************************/
2051
2052 /*
2053 * Assumes the correct mode bits are already turned on. Thus it
2054 * is OK to call this function from, e.g., bgp_redistribute_set()
2055 * without caring if export is enabled or not
2056 */
2057 void vnc_export_bgp_enable(struct bgp *bgp, afi_t afi)
2058 {
2059 if (!bgp->rfapi_cfg)
2060 return;
2061
2062 switch (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) {
2063 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_NONE:
2064 break;
2065
2066 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_GRP:
2067 vnc_direct_bgp_vpn_enable(bgp, afi);
2068 break;
2069
2070 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_RH:
2071 vnc_direct_bgp_rh_vpn_enable(bgp, afi);
2072 break;
2073
2074 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_CE:
2075 vnc_direct_bgp_vpn_enable_ce(bgp, afi);
2076 break;
2077 }
2078 }
2079
2080 void vnc_export_bgp_disable(struct bgp *bgp, afi_t afi)
2081 {
2082 if (!bgp->rfapi_cfg)
2083 return;
2084
2085 switch (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) {
2086 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_NONE:
2087 break;
2088
2089 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_GRP:
2090 vnc_direct_bgp_vpn_disable(bgp, afi);
2091 break;
2092
2093 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_RH:
2094 vnc_direct_bgp_rh_vpn_disable(bgp, afi);
2095 break;
2096
2097 case BGP_VNC_CONFIG_EXPORT_BGP_MODE_CE:
2098 vnc_direct_bgp_vpn_disable_ce(bgp, afi);
2099 break;
2100 }
2101 }
2102
2103 void vnc_export_bgp_prechange(struct bgp *bgp)
2104 {
2105 vnc_export_bgp_disable(bgp, AFI_IP);
2106 vnc_export_bgp_disable(bgp, AFI_IP6);
2107 }
2108
2109 void vnc_export_bgp_postchange(struct bgp *bgp)
2110 {
2111 vnc_export_bgp_enable(bgp, AFI_IP);
2112 vnc_export_bgp_enable(bgp, AFI_IP6);
2113 }
2114
2115 void vnc_direct_bgp_reexport(struct bgp *bgp, afi_t afi)
2116 {
2117 vnc_export_bgp_disable(bgp, afi);
2118 vnc_export_bgp_enable(bgp, afi);
2119 }