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