]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/vnc_export_bgp.c
Merge pull request #10558 from Jafaral/ospf-net-or-iface
[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 assert(new);
568 ecommunity_add_val(new, &roec, false, false);
569
570 if (!new->size) {
571 ecommunity_free(&new);
572 new = NULL;
573 }
574
575 return new;
576 }
577
578
579 /*
580 * New memory allocation approach: make a ghost attr that
581 * has non-interned parts for the modifications. ghost attr
582 * memory is allocated by caller.
583 */
584 static int
585 encap_attr_export(struct attr *new, struct attr *orig,
586 struct prefix *new_nexthop,
587 struct agg_node *rn) /* for VN addrs for ecom list */
588 /* if rn is 0, use route's nexthop */
589 {
590 struct prefix orig_nexthop;
591 struct prefix *use_nexthop;
592 static struct ecommunity *ecom_ro;
593
594 if (new_nexthop) {
595 use_nexthop = new_nexthop;
596 } else {
597 use_nexthop = &orig_nexthop;
598 orig_nexthop.family =
599 BGP_MP_NEXTHOP_FAMILY(orig->mp_nexthop_len);
600 if (orig_nexthop.family == AF_INET) {
601 orig_nexthop.prefixlen = IPV4_MAX_BITLEN;
602 orig_nexthop.u.prefix4 = orig->mp_nexthop_global_in;
603 } else if (orig_nexthop.family == AF_INET6) {
604 orig_nexthop.prefixlen = IPV6_MAX_BITLEN;
605 orig_nexthop.u.prefix6 = orig->mp_nexthop_global;
606 } else {
607 return -1; /* FAIL - can't compute nexthop */
608 }
609 }
610
611
612 /*
613 * Make "new" a ghost attr copy of "orig"
614 */
615 memset(new, 0, sizeof(struct attr));
616 *new = *orig;
617
618 /*
619 * Set nexthop
620 */
621 switch (use_nexthop->family) {
622 case AF_INET:
623 new->nexthop = use_nexthop->u.prefix4;
624 new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
625 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
626 break;
627
628 case AF_INET6:
629 new->mp_nexthop_global = use_nexthop->u.prefix6;
630 new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
631 break;
632
633 default:
634 assert(0);
635 break;
636 }
637
638 if (rn) {
639 ecom_ro = vnc_route_origin_ecom(rn);
640 } else {
641 /* TBD use lcom for IPv6 */
642 ecom_ro = vnc_route_origin_ecom_single(&use_nexthop->u.prefix4);
643 }
644 if (bgp_attr_get_ecommunity(new)) {
645 if (ecom_ro)
646 bgp_attr_set_ecommunity(
647 new,
648 ecommunity_merge(ecom_ro,
649 bgp_attr_get_ecommunity(new)));
650 } else {
651 bgp_attr_set_ecommunity(new, ecom_ro);
652 }
653 if (ecom_ro) {
654 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
655 }
656
657 /*
658 * Set MED
659 *
660 * Note that it will be deleted when BGP sends to any eBGP
661 * peer unless PEER_FLAG_MED_UNCHANGED is set:
662 *
663 * neighbor NEIGHBOR attribute-unchanged med
664 */
665 if (!CHECK_FLAG(new->flag, BGP_ATTR_MULTI_EXIT_DISC)) {
666 if (CHECK_FLAG(new->flag, BGP_ATTR_LOCAL_PREF)) {
667 if (new->local_pref > 255)
668 new->med = 0;
669 else
670 new->med = 255 - new->local_pref;
671 } else {
672 new->med = 255; /* shouldn't happen */
673 }
674 new->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
675 }
676
677 /*
678 * "new" is now a ghost attr:
679 * - it owns an "extra" struct
680 * - it owns any non-interned parts
681 * - any references to interned parts are not counted
682 *
683 * Caller should, after using the attr, call:
684 * - bgp_attr_flush() to free non-interned parts
685 */
686
687 return 0;
688 }
689
690 /*
691 * "Adding a Route" export process
692 */
693 void vnc_direct_bgp_add_prefix(struct bgp *bgp,
694 struct rfapi_import_table *import_table,
695 struct agg_node *rn)
696 {
697 struct attr attr = {0};
698 struct listnode *node, *nnode;
699 struct rfapi_rfg_name *rfgn;
700 const struct prefix *p = agg_node_get_prefix(rn);
701 afi_t afi = family2afi(p->family);
702
703 if (!afi) {
704 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node",
705 __func__);
706 return;
707 }
708
709 /* check bgp redist flag for vnc direct ("vpn") routes */
710 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
711 vnc_zlog_debug_verbose(
712 "%s: bgp redistribution of VNC direct routes is off",
713 __func__);
714 return;
715 }
716
717 if (!bgp->rfapi_cfg) {
718 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
719 __func__);
720 return;
721 }
722
723 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
724 vnc_zlog_debug_verbose(
725 "%s: export-to-bgp group mode not enabled, skipping",
726 __func__);
727 return;
728 }
729
730 if (!listcount(bgp->rfapi_cfg->rfg_export_direct_bgp_l)) {
731 vnc_zlog_debug_verbose(
732 "%s: no bgp-direct export nve group, skipping",
733 __func__);
734 return;
735 }
736
737 bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
738 /* TBD set some configured med, see add_vnc_route() */
739
740 vnc_zlog_debug_verbose(
741 "%s: looping over nve-groups in direct-bgp export list",
742 __func__);
743
744 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
745 nnode, rfgn)) {
746
747 struct listnode *ln;
748
749 /*
750 * If nve group is not defined yet, skip it
751 */
752 if (!rfgn->rfg)
753 continue;
754
755 /*
756 * If the nve group uses a different import table, skip it
757 */
758 if (import_table != rfgn->rfg->rfapi_import_table)
759 continue;
760
761 /*
762 * if no NVEs currently associated with this group, skip it
763 */
764 if (rfgn->rfg->type != RFAPI_GROUP_CFG_VRF && !rfgn->rfg->nves)
765 continue;
766
767 /*
768 * per-nve-group prefix list check
769 */
770 if (rfgn->rfg->plist_export_bgp[afi]) {
771 if (prefix_list_apply(rfgn->rfg->plist_export_bgp[afi],
772 p)
773 == PREFIX_DENY)
774
775 continue;
776 }
777
778 if (rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
779 vnc_direct_add_rn_group_rd(bgp, rfgn->rfg, rn, &attr,
780 afi, rfgn->rfg->rfd);
781 /*
782 * yuck!
783 * - but consistent with rest of function
784 */
785 continue;
786 }
787 /*
788 * For each NVE that is assigned to the export nve group,
789 * generate
790 * a route with that NVE as its next hop
791 */
792 for (ln = listhead(rfgn->rfg->nves); ln;
793 ln = listnextnode(ln)) {
794 vnc_direct_add_rn_group_rd(bgp, rfgn->rfg, rn, &attr,
795 afi, listgetdata(ln));
796 }
797 }
798
799 aspath_unintern(&attr.aspath);
800 }
801
802 /*
803 * "Withdrawing a Route" export process
804 */
805 void vnc_direct_bgp_del_prefix(struct bgp *bgp,
806 struct rfapi_import_table *import_table,
807 struct agg_node *rn)
808 {
809 struct listnode *node, *nnode;
810 struct rfapi_rfg_name *rfgn;
811 const struct prefix *p = agg_node_get_prefix(rn);
812 afi_t afi = family2afi(p->family);
813
814 if (!afi) {
815 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi route node",
816 __func__);
817 return;
818 }
819
820 /* check bgp redist flag for vnc direct ("vpn") routes */
821 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
822 vnc_zlog_debug_verbose(
823 "%s: bgp redistribution of VNC direct routes is off",
824 __func__);
825 return;
826 }
827
828 if (!bgp->rfapi_cfg) {
829 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
830 __func__);
831 return;
832 }
833
834 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
835 vnc_zlog_debug_verbose(
836 "%s: export-to-bgp group mode not enabled, skipping",
837 __func__);
838 return;
839 }
840
841 if (!listcount(bgp->rfapi_cfg->rfg_export_direct_bgp_l)) {
842 vnc_zlog_debug_verbose(
843 "%s: no bgp-direct export nve group, skipping",
844 __func__);
845 return;
846 }
847
848 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
849 nnode, rfgn)) {
850
851 struct listnode *ln;
852
853 /*
854 * If nve group is not defined yet, skip it
855 */
856 if (!rfgn->rfg)
857 continue;
858
859 /*
860 * if no NVEs currently associated with this group, skip it
861 */
862 if (rfgn->rfg->type != RFAPI_GROUP_CFG_VRF && !rfgn->rfg->nves)
863 continue;
864
865 /*
866 * If the nve group uses a different import table,
867 * skip it
868 */
869 if (import_table != rfgn->rfg->rfapi_import_table)
870 continue;
871
872 if (rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
873 struct prefix nhp;
874 struct rfapi_descriptor *irfd;
875
876 irfd = rfgn->rfg->rfd;
877
878 if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
879 continue;
880
881 bgp_withdraw(irfd->peer, p, /* prefix */
882 0, /* addpath_id */
883 NULL, /* attr, ignored */
884 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
885 BGP_ROUTE_REDISTRIBUTE,
886 NULL, /* RD not used for unicast */
887 NULL, 0,
888 NULL); /* tag not used for unicast */
889 /*
890 * yuck!
891 * - but consistent with rest of function
892 */
893 continue;
894 }
895 /*
896 * For each NVE that is assigned to the export nve group,
897 * generate
898 * a route with that NVE as its next hop
899 */
900 for (ln = listhead(rfgn->rfg->nves); ln;
901 ln = listnextnode(ln)) {
902
903 struct prefix nhp;
904 struct rfapi_descriptor *irfd;
905
906 irfd = listgetdata(ln);
907
908 if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
909 continue;
910
911 bgp_withdraw(irfd->peer, p, /* prefix */
912 0, /* addpath_id */
913 NULL, /* attr, ignored */
914 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
915 BGP_ROUTE_REDISTRIBUTE,
916 NULL, /* RD not used for unicast */
917 NULL, 0,
918 NULL); /* tag not used for unicast */
919 }
920 }
921 }
922
923 void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
924 {
925 struct listnode *node, *nnode;
926 struct rfapi_rfg_name *rfgn;
927 struct rfapi_nve_group_cfg *rfg = rfd->rfg;
928 afi_t afi = family2afi(rfd->vn_addr.addr_family);
929
930 if (!afi) {
931 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of nve vn addr",
932 __func__);
933 return;
934 }
935
936 if (!bgp)
937 return;
938 if (!bgp->rfapi_cfg) {
939 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
940 __func__);
941 return;
942 }
943 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
944 vnc_zlog_debug_verbose(
945 "%s: export-to-bgp group mode not enabled, skipping",
946 __func__);
947 return;
948 }
949
950 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
951 vnc_zlog_debug_verbose(
952 "%s: bgp redistribution of VNC direct routes is off",
953 __func__);
954 return;
955 }
956
957 /*
958 * Loop over the list of NVE-Groups configured for
959 * exporting to direct-bgp and see if this new NVE's
960 * group is among them.
961 */
962 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
963 nnode, rfgn)) {
964
965 /*
966 * Yes, this NVE's group is configured for export to direct-bgp
967 */
968 if (rfgn->rfg == rfg) {
969
970 struct agg_table *rt = NULL;
971 struct agg_node *rn;
972 struct attr attr = {0};
973 struct rfapi_import_table *import_table;
974
975
976 import_table = rfg->rfapi_import_table;
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 bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
987 /* TBD set some configured med, see add_vnc_route() */
988
989 /*
990 * Walk the NVE-Group's VNC Import table
991 */
992 for (rn = agg_route_top(rt); rn;
993 rn = agg_route_next(rn)) {
994
995 if (rn->info) {
996
997 struct prefix nhp;
998 struct rfapi_descriptor *irfd = rfd;
999 struct attr hattr;
1000 struct attr *iattr;
1001 struct bgp_path_info info;
1002 const struct prefix *p =
1003 agg_node_get_prefix(rn);
1004
1005 if (rfapiRaddr2Qprefix(&irfd->vn_addr,
1006 &nhp))
1007 continue;
1008
1009 /*
1010 * per-nve-group prefix list check
1011 */
1012 if (rfgn->rfg->plist_export_bgp[afi]) {
1013 if (prefix_list_apply(
1014 rfgn->rfg->plist_export_bgp
1015 [afi],
1016 p)
1017 == PREFIX_DENY)
1018
1019 continue;
1020 }
1021
1022
1023 /*
1024 * Construct new attribute set with
1025 * NVE's VN addr as
1026 * nexthop and without Tunnel Encap attr
1027 */
1028 if (encap_attr_export(&hattr, &attr,
1029 &nhp, rn))
1030 continue;
1031
1032 if (rfgn->rfg->routemap_export_bgp) {
1033 route_map_result_t ret;
1034 info.peer = irfd->peer;
1035 info.attr = &hattr;
1036 ret = route_map_apply(
1037 rfgn->rfg
1038 ->routemap_export_bgp,
1039 p, &info);
1040 if (ret == RMAP_DENYMATCH) {
1041 bgp_attr_flush(&hattr);
1042 continue;
1043 }
1044 }
1045
1046 iattr = bgp_attr_intern(&hattr);
1047 bgp_attr_flush(&hattr);
1048 bgp_update(
1049 irfd->peer, p, /* prefix */
1050 0, /* addpath_id */
1051 iattr, /* bgp_update copies
1052 it */
1053 afi, SAFI_UNICAST,
1054 ZEBRA_ROUTE_VNC_DIRECT,
1055 BGP_ROUTE_REDISTRIBUTE, NULL,
1056 /* RD not used for unicast */
1057 NULL,
1058 /* tag not used for unicast */
1059 0, 0, NULL); /* EVPN not used */
1060
1061 bgp_attr_unintern(&iattr);
1062 }
1063 }
1064
1065 aspath_unintern(&attr.aspath);
1066 }
1067 }
1068 }
1069
1070
1071 void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
1072 {
1073 struct listnode *node, *nnode;
1074 struct rfapi_rfg_name *rfgn;
1075 struct rfapi_nve_group_cfg *rfg = rfd->rfg;
1076 afi_t afi = family2afi(rfd->vn_addr.addr_family);
1077
1078 if (!afi) {
1079 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of nve vn addr",
1080 __func__);
1081 return;
1082 }
1083
1084 if (!bgp)
1085 return;
1086 if (!bgp->rfapi_cfg) {
1087 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
1088 __func__);
1089 return;
1090 }
1091 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
1092 vnc_zlog_debug_verbose(
1093 "%s: export-to-bgp group mode not enabled, skipping",
1094 __func__);
1095 return;
1096 }
1097
1098 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
1099 vnc_zlog_debug_verbose(
1100 "%s: bgp redistribution of VNC direct routes is off",
1101 __func__);
1102 return;
1103 }
1104
1105 /*
1106 * Loop over the list of NVE-Groups configured for
1107 * exporting to direct-bgp and see if this new NVE's
1108 * group is among them.
1109 */
1110 for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
1111 nnode, rfgn)) {
1112
1113 /*
1114 * Yes, this NVE's group is configured for export to direct-bgp
1115 */
1116 if (rfg && rfgn->rfg == rfg) {
1117
1118 struct agg_table *rt = NULL;
1119 struct agg_node *rn;
1120 struct rfapi_import_table *import_table;
1121
1122 import_table = rfg->rfapi_import_table;
1123
1124 if (afi == AFI_IP || afi == AFI_IP6) {
1125 rt = import_table->imported_vpn[afi];
1126 } else {
1127 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d",
1128 __func__, afi);
1129 return;
1130 }
1131
1132 /*
1133 * Walk the NVE-Group's VNC Import table
1134 */
1135 for (rn = agg_route_top(rt); rn;
1136 rn = agg_route_next(rn)) {
1137
1138 if (rn->info) {
1139 const struct prefix *p =
1140 agg_node_get_prefix(rn);
1141 struct prefix nhp;
1142 struct rfapi_descriptor *irfd = rfd;
1143
1144 if (rfapiRaddr2Qprefix(&irfd->vn_addr,
1145 &nhp))
1146 continue;
1147
1148 bgp_withdraw(irfd->peer, p, /* prefix */
1149 0, /* addpath_id */
1150 NULL, /* attr, ignored */
1151 afi, SAFI_UNICAST,
1152 ZEBRA_ROUTE_VNC_DIRECT,
1153 BGP_ROUTE_REDISTRIBUTE,
1154 NULL, /* RD not used for
1155 unicast */
1156 NULL, 0, NULL); /* tag not
1157 used for
1158 unicast */
1159 }
1160 }
1161 }
1162 }
1163 }
1164
1165 static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
1166 struct rfapi_nve_group_cfg *rfg,
1167 struct agg_node *rn, struct attr *attr,
1168 afi_t afi, struct rfapi_descriptor *irfd)
1169 {
1170 struct prefix nhp;
1171 struct bgp_path_info info;
1172 struct attr hattr;
1173 struct attr *iattr;
1174 const struct prefix *p = agg_node_get_prefix(rn);
1175
1176 if (irfd == NULL && rfg->type != RFAPI_GROUP_CFG_VRF) {
1177 /* need new rfapi_handle, for peer strcture
1178 * -- based on vnc_add_vrf_prefi */
1179 assert(rfg->rfd == NULL);
1180
1181 if (!rfg->rt_export_list || !rfg->rfapi_import_table) {
1182 vnc_zlog_debug_verbose(
1183 "%s: VRF \"%s\" is missing RT import/export configuration.",
1184 __func__, rfg->name);
1185 return;
1186 }
1187 if (!rfg->rd.prefixlen) {
1188 vnc_zlog_debug_verbose(
1189 "%s: VRF \"%s\" is missing RD configuration.",
1190 __func__, rfg->name);
1191 return;
1192 }
1193 if (rfg->label > MPLS_LABEL_MAX) {
1194 vnc_zlog_debug_verbose(
1195 "%s: VRF \"%s\" is missing default label configuration.",
1196 __func__, rfg->name);
1197 return;
1198 }
1199
1200 irfd = XCALLOC(MTYPE_RFAPI_DESC,
1201 sizeof(struct rfapi_descriptor));
1202 irfd->bgp = bgp;
1203 rfg->rfd = irfd;
1204 /*
1205 * leave most fields empty as will get from (dynamic) config
1206 * when needed
1207 */
1208 irfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS;
1209 irfd->cookie = rfg;
1210 if (rfg->vn_prefix.family
1211 && !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF)) {
1212 rfapiQprefix2Raddr(&rfg->vn_prefix, &irfd->vn_addr);
1213 } else {
1214 memset(&irfd->vn_addr, 0, sizeof(struct rfapi_ip_addr));
1215 irfd->vn_addr.addr_family = AF_INET;
1216 irfd->vn_addr.addr.v4 = bgp->router_id;
1217 }
1218 irfd->un_addr = irfd->vn_addr; /* sigh, need something in UN for
1219 lookups */
1220 vnc_zlog_debug_verbose("%s: Opening RFD for VRF %s", __func__,
1221 rfg->name);
1222 rfapi_init_and_open(bgp, irfd, rfg);
1223 }
1224
1225 if (irfd == NULL || rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
1226 return;
1227
1228 /*
1229 * Construct new attribute set with NVE's VN
1230 * addr as
1231 * nexthop and without Tunnel Encap attr
1232 */
1233 if (encap_attr_export(&hattr, attr, &nhp, rn))
1234 return;
1235
1236 if (VNC_DEBUG(EXPORT_BGP_DIRECT_ADD)) {
1237 vnc_zlog_debug_any("%s: attr follows", __func__);
1238 rfapiPrintAttrPtrs(NULL, attr);
1239 vnc_zlog_debug_any("%s: hattr follows", __func__);
1240 rfapiPrintAttrPtrs(NULL, &hattr);
1241 }
1242
1243 if (rfg->routemap_export_bgp) {
1244 route_map_result_t ret;
1245
1246 info.peer = irfd->peer;
1247 info.attr = &hattr;
1248 ret = route_map_apply(rfg->routemap_export_bgp, p, &info);
1249 if (ret == RMAP_DENYMATCH) {
1250 bgp_attr_flush(&hattr);
1251 vnc_zlog_debug_verbose(
1252 "%s: route map says DENY, so not calling bgp_update",
1253 __func__);
1254 return;
1255 }
1256 }
1257
1258 if (VNC_DEBUG(EXPORT_BGP_DIRECT_ADD)) {
1259 vnc_zlog_debug_any("%s: hattr after route_map_apply:",
1260 __func__);
1261 rfapiPrintAttrPtrs(NULL, &hattr);
1262 }
1263 iattr = bgp_attr_intern(&hattr);
1264 bgp_attr_flush(&hattr);
1265
1266 bgp_update(irfd->peer, p, /* prefix */
1267 0, /* addpath_id */
1268 iattr, /* bgp_update copies it */
1269 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
1270 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
1271 NULL, /* tag not used for unicast */
1272 0, 0, NULL); /* EVPN not used */
1273
1274 bgp_attr_unintern(&iattr);
1275
1276 return;
1277 }
1278
1279 /*
1280 * Caller is responsible for ensuring that the specified nve-group
1281 * is actually part of the list of exported nve groups.
1282 */
1283 static void vnc_direct_bgp_add_group_afi(struct bgp *bgp,
1284 struct rfapi_nve_group_cfg *rfg,
1285 afi_t afi)
1286 {
1287 struct agg_table *rt = NULL;
1288 struct agg_node *rn;
1289 struct attr attr = {0};
1290 struct rfapi_import_table *import_table;
1291
1292 vnc_zlog_debug_verbose("%s: entry", __func__);
1293
1294 import_table = rfg->rfapi_import_table;
1295 if (!import_table) {
1296 vnc_zlog_debug_verbose(
1297 "%s: import table not defined, returning", __func__);
1298 return;
1299 }
1300
1301 if (afi == AFI_IP || afi == AFI_IP6) {
1302 rt = import_table->imported_vpn[afi];
1303 } else {
1304 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
1305 return;
1306 }
1307
1308 if (!rfg->nves && rfg->type != RFAPI_GROUP_CFG_VRF) {
1309 vnc_zlog_debug_verbose("%s: no NVEs in this group", __func__);
1310 return;
1311 }
1312
1313 bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
1314 /* TBD set some configured med, see add_vnc_route() */
1315
1316 /*
1317 * Walk the NVE-Group's VNC Import table
1318 */
1319 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1320
1321 if (rn->info) {
1322 const struct prefix *p = agg_node_get_prefix(rn);
1323 struct listnode *ln;
1324
1325 /*
1326 * per-nve-group prefix list check
1327 */
1328 if (rfg->plist_export_bgp[afi]) {
1329 if (prefix_list_apply(
1330 rfg->plist_export_bgp[afi], p)
1331 == PREFIX_DENY)
1332
1333 continue;
1334 }
1335 if (rfg->type == RFAPI_GROUP_CFG_VRF) {
1336 vnc_direct_add_rn_group_rd(bgp, rfg, rn, &attr,
1337 afi, rfg->rfd);
1338 /*
1339 * yuck!
1340 * - but consistent with rest of function
1341 */
1342 continue;
1343 }
1344 /*
1345 * For each NVE that is assigned to the export nve
1346 * group, generate
1347 * a route with that NVE as its next hop
1348 */
1349 for (ln = listhead(rfg->nves); ln;
1350 ln = listnextnode(ln)) {
1351 vnc_direct_add_rn_group_rd(bgp, rfg, rn, &attr,
1352 afi,
1353 listgetdata(ln));
1354 }
1355 }
1356 }
1357
1358 aspath_unintern(&attr.aspath);
1359 }
1360
1361
1362 /*
1363 * Caller is responsible for ensuring that the specified nve-group
1364 * is actually part of the list of exported nve groups.
1365 */
1366 void vnc_direct_bgp_add_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
1367 {
1368 vnc_direct_bgp_add_group_afi(bgp, rfg, AFI_IP);
1369 vnc_direct_bgp_add_group_afi(bgp, rfg, AFI_IP6);
1370 }
1371
1372 static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
1373 struct rfapi_nve_group_cfg *rfg,
1374 struct agg_node *rn, afi_t afi,
1375 struct rfapi_descriptor *irfd)
1376 {
1377 if (irfd == NULL)
1378 return;
1379
1380 bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), /* prefix */
1381 0, /* addpath_id */
1382 NULL, /* attr, ignored */
1383 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
1384 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
1385 NULL, 0, NULL); /* tag not used for unicast */
1386 return;
1387 }
1388
1389 /*
1390 * Caller is responsible for ensuring that the specified nve-group
1391 * was actually part of the list of exported nve groups.
1392 */
1393 static void vnc_direct_bgp_del_group_afi(struct bgp *bgp,
1394 struct rfapi_nve_group_cfg *rfg,
1395 afi_t afi)
1396 {
1397 struct agg_table *rt = NULL;
1398 struct agg_node *rn;
1399 struct rfapi_import_table *import_table;
1400
1401 vnc_zlog_debug_verbose("%s: entry", __func__);
1402
1403 import_table = rfg->rfapi_import_table;
1404 if (!import_table) {
1405 vnc_zlog_debug_verbose(
1406 "%s: import table not defined, returning", __func__);
1407 return;
1408 }
1409
1410 rt = import_table->imported_vpn[afi];
1411
1412 if (!rfg->nves && rfg->type != RFAPI_GROUP_CFG_VRF) {
1413 vnc_zlog_debug_verbose("%s: no NVEs in this group", __func__);
1414 return;
1415 }
1416
1417 /*
1418 * Walk the NVE-Group's VNC Import table
1419 */
1420 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn))
1421 if (rn->info) {
1422 if (rfg->type == RFAPI_GROUP_CFG_VRF)
1423 vnc_direct_del_rn_group_rd(bgp, rfg, rn, afi,
1424 rfg->rfd);
1425 else {
1426 struct listnode *ln;
1427
1428 /*
1429 * For each NVE that is assigned to the export
1430 * nve
1431 * group, generate
1432 * a route with that NVE as its next hop
1433 */
1434 for (ln = listhead(rfg->nves); ln;
1435 ln = listnextnode(ln))
1436 vnc_direct_del_rn_group_rd(
1437 bgp, rfg, rn, afi,
1438 listgetdata(ln));
1439 }
1440 }
1441 }
1442
1443 /*
1444 * Caller is responsible for ensuring that the specified nve-group
1445 * was actually part of the list of exported nve groups.
1446 */
1447 void vnc_direct_bgp_del_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
1448 {
1449 vnc_direct_bgp_del_group_afi(bgp, rfg, AFI_IP);
1450 vnc_direct_bgp_del_group_afi(bgp, rfg, AFI_IP6);
1451 }
1452
1453 void vnc_direct_bgp_reexport_group_afi(struct bgp *bgp,
1454 struct rfapi_nve_group_cfg *rfg,
1455 afi_t afi)
1456 {
1457 struct listnode *node;
1458 struct rfapi_rfg_name *rfgn;
1459
1460 if (VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
1461 /*
1462 * look in the list of currently-exported groups
1463 */
1464 for (ALL_LIST_ELEMENTS_RO(
1465 bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
1466 rfgn)) {
1467
1468 if (rfgn->rfg == rfg) {
1469 /*
1470 * If it matches, reexport it
1471 */
1472 vnc_direct_bgp_del_group_afi(bgp, rfg, afi);
1473 vnc_direct_bgp_add_group_afi(bgp, rfg, afi);
1474 break;
1475 }
1476 }
1477 }
1478 }
1479
1480
1481 static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
1482 struct list *nve_list)
1483 {
1484 if (nve_list) {
1485
1486 struct agg_node *rn;
1487
1488 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1489
1490 if (rn->info) {
1491
1492 struct listnode *hln;
1493 struct rfapi_descriptor *irfd;
1494
1495 for (ALL_LIST_ELEMENTS_RO(nve_list, hln,
1496 irfd)) {
1497
1498 bgp_withdraw(irfd->peer,
1499 agg_node_get_prefix(rn),
1500 0, /* addpath_id */
1501 NULL, /* attr, ignored */
1502 afi, SAFI_UNICAST,
1503 ZEBRA_ROUTE_VNC_DIRECT,
1504 BGP_ROUTE_REDISTRIBUTE,
1505 NULL, /* RD not used for
1506 unicast */
1507 NULL, 0, NULL); /* tag not
1508 used for
1509 unicast,
1510 EVPN
1511 neither */
1512 }
1513 }
1514 }
1515 }
1516 }
1517
1518 static void import_table_to_nve_list_direct_bgp(struct bgp *bgp,
1519 struct rfapi_import_table *it,
1520 struct list **nves,
1521 uint8_t family)
1522 {
1523 struct listnode *node;
1524 struct rfapi_rfg_name *rfgn;
1525
1526 /*
1527 * Loop over the list of NVE-Groups configured for
1528 * exporting to direct-bgp.
1529 *
1530 * Build a list of NVEs that use this import table
1531 */
1532 *nves = NULL;
1533 for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node,
1534 rfgn)) {
1535
1536 /*
1537 * If this NVE-Group's import table matches the current one
1538 */
1539 if (rfgn->rfg && rfgn->rfg->rfapi_import_table == it) {
1540 if (rfgn->rfg->nves)
1541 nve_group_to_nve_list(rfgn->rfg, nves, family);
1542 else if (rfgn->rfg->rfd
1543 && rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
1544 if (!*nves)
1545 *nves = list_new();
1546 listnode_add(*nves, rfgn->rfg->rfd);
1547 }
1548 }
1549 }
1550 }
1551
1552 void vnc_direct_bgp_vpn_enable(struct bgp *bgp, afi_t afi)
1553 {
1554 struct listnode *rfgn;
1555 struct rfapi_nve_group_cfg *rfg;
1556
1557 if (!bgp)
1558 return;
1559
1560 if (!VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) {
1561 vnc_zlog_debug_verbose(
1562 "%s: export-to-bgp group mode not enabled, skipping",
1563 __func__);
1564 return;
1565 }
1566
1567 if (afi != AFI_IP && afi != AFI_IP6) {
1568 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1569 return;
1570 }
1571
1572 /*
1573 * Policy is applied per-nve-group, so we need to iterate
1574 * over the groups to add everything.
1575 */
1576 for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->nve_groups_sequential, rfgn,
1577 rfg)) {
1578
1579 /*
1580 * contains policy management
1581 */
1582 vnc_direct_bgp_add_group_afi(bgp, rfg, afi);
1583 }
1584 }
1585
1586
1587 void vnc_direct_bgp_vpn_disable(struct bgp *bgp, afi_t afi)
1588 {
1589 struct rfapi_import_table *it;
1590 uint8_t family = afi2family(afi);
1591
1592 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
1593
1594 if (!bgp)
1595 return;
1596
1597 if (!bgp->rfapi) {
1598 vnc_zlog_debug_verbose("%s: rfapi not initialized", __func__);
1599 return;
1600 }
1601
1602 if (!family || (afi != AFI_IP && afi != AFI_IP6)) {
1603 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1604 return;
1605 }
1606
1607 for (it = bgp->rfapi->imports; it; it = it->next) {
1608
1609 struct list *nve_list = NULL;
1610
1611 import_table_to_nve_list_direct_bgp(bgp, it, &nve_list, family);
1612
1613 if (nve_list) {
1614 vnc_direct_bgp_unexport_table(
1615 afi, it->imported_vpn[afi], nve_list);
1616 list_delete(&nve_list);
1617 }
1618 }
1619 }
1620
1621
1622 /***********************************************************************
1623 * Export methods that proxy nexthop END
1624 ***********************************************************************/
1625
1626
1627 /***********************************************************************
1628 * Export methods that preserve original nexthop BEGIN
1629 * rh = "registering nve"
1630 ***********************************************************************/
1631
1632
1633 /*
1634 * "Adding a Route" export process
1635 * TBD do we need to check bpi->type and bpi->sub_type here, or does
1636 * caller do it?
1637 */
1638 void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
1639 const struct prefix *prefix, struct peer *peer,
1640 struct attr *attr)
1641 {
1642 struct vnc_export_info *eti;
1643 struct attr hattr;
1644 struct rfapi_cfg *hc;
1645 struct attr *iattr;
1646
1647 if (!afi) {
1648 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node",
1649 __func__);
1650 return;
1651 }
1652
1653 /* check bgp redist flag for vnc direct ("vpn") routes */
1654 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
1655 vnc_zlog_debug_verbose(
1656 "%s: bgp redistribution of VNC direct routes is off",
1657 __func__);
1658 return;
1659 }
1660
1661 if (!(hc = bgp->rfapi_cfg)) {
1662 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
1663 __func__);
1664 return;
1665 }
1666
1667 if (!VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
1668 vnc_zlog_debug_verbose(
1669 "%s: export-to-bgp RH mode not enabled, skipping",
1670 __func__);
1671 return;
1672 }
1673
1674 /*
1675 * prefix list check
1676 */
1677 if (hc->plist_export_bgp[afi]) {
1678 if (prefix_list_apply(hc->plist_export_bgp[afi], prefix)
1679 == PREFIX_DENY)
1680 return;
1681 }
1682
1683 /*
1684 * Construct new attribute set with NVE's VN addr as
1685 * nexthop and without Tunnel Encap attr
1686 */
1687 if (encap_attr_export(&hattr, attr, NULL, NULL))
1688 return;
1689 if (hc->routemap_export_bgp) {
1690 struct bgp_path_info info;
1691 route_map_result_t ret;
1692
1693 memset(&info, 0, sizeof(info));
1694 info.peer = peer;
1695 info.attr = &hattr;
1696 ret = route_map_apply(hc->routemap_export_bgp, prefix, &info);
1697 if (ret == RMAP_DENYMATCH) {
1698 bgp_attr_flush(&hattr);
1699 return;
1700 }
1701 }
1702
1703 iattr = bgp_attr_intern(&hattr);
1704 bgp_attr_flush(&hattr);
1705
1706 /*
1707 * record route information that we will need to expire
1708 * this route
1709 */
1710 eti = vnc_eti_get(bgp, EXPORT_TYPE_BGP, prefix, peer,
1711 ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE);
1712 rfapiGetVncLifetime(attr, &eti->lifetime);
1713 eti->lifetime = rfapiGetHolddownFromLifetime(eti->lifetime);
1714
1715 /*
1716 * export expiration timer is already running on
1717 * this route: cancel it
1718 */
1719 thread_cancel(&eti->timer);
1720
1721 bgp_update(peer, prefix, /* prefix */
1722 0, /* addpath_id */
1723 iattr, /* bgp_update copies this attr */
1724 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH,
1725 BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
1726 NULL, /* tag not used for unicast, EVPN neither */
1727 0, 0, NULL); /* EVPN not used */
1728 bgp_attr_unintern(&iattr);
1729 }
1730
1731 static int vncExportWithdrawTimer(struct thread *t)
1732 {
1733 struct vnc_export_info *eti = t->arg;
1734 const struct prefix *p = agg_node_get_prefix(eti->node);
1735
1736 /*
1737 * withdraw the route
1738 */
1739 bgp_withdraw(eti->peer, p, 0, /* addpath_id */
1740 NULL, /* attr, ignored */
1741 family2afi(p->family), SAFI_UNICAST, eti->type,
1742 eti->subtype, NULL, /* RD not used for unicast */
1743 NULL, 0,
1744 NULL); /* tag not used for unicast, EVPN neither */
1745
1746 /*
1747 * Free the eti
1748 */
1749 vnc_eti_delete(eti);
1750
1751 return 0;
1752 }
1753
1754 /*
1755 * "Withdrawing a Route" export process
1756 * TBD do we need to check bpi->type and bpi->sub_type here, or does
1757 * caller do it?
1758 */
1759 void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi,
1760 const struct prefix *prefix, struct peer *peer)
1761 {
1762 struct vnc_export_info *eti;
1763
1764 if (!afi) {
1765 flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi route node",
1766 __func__);
1767 return;
1768 }
1769
1770 /* check bgp redist flag for vnc direct ("vpn") routes */
1771 if (!bgp->redist[afi][ZEBRA_ROUTE_VNC_DIRECT]) {
1772 vnc_zlog_debug_verbose(
1773 "%s: bgp redistribution of VNC direct routes is off",
1774 __func__);
1775 return;
1776 }
1777
1778 if (!bgp->rfapi_cfg) {
1779 vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
1780 __func__);
1781 return;
1782 }
1783 if (!VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
1784 vnc_zlog_debug_verbose(
1785 "%s: export-to-bgp group mode not enabled, skipping",
1786 __func__);
1787 return;
1788 }
1789
1790 eti = vnc_eti_get(bgp, EXPORT_TYPE_BGP, prefix, peer,
1791 ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE);
1792
1793 if (!eti->timer && eti->lifetime <= INT32_MAX) {
1794 eti->timer = NULL;
1795 thread_add_timer(bm->master, vncExportWithdrawTimer, eti,
1796 eti->lifetime, &eti->timer);
1797 vnc_zlog_debug_verbose(
1798 "%s: set expiration timer for %u seconds", __func__,
1799 eti->lifetime);
1800 }
1801 }
1802
1803
1804 void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
1805 {
1806 struct prefix_rd prd;
1807 struct bgp_dest *pdest;
1808 struct rfapi_cfg *hc;
1809
1810 vnc_zlog_debug_verbose("%s: entry, afi=%d", __func__, afi);
1811
1812 if (!bgp)
1813 return;
1814
1815 if (!(hc = bgp->rfapi_cfg))
1816 return;
1817
1818 if (!VNC_EXPORT_BGP_RH_ENABLED(bgp->rfapi_cfg)) {
1819 vnc_zlog_debug_verbose(
1820 "%s: export of RH routes not enabled, skipping",
1821 __func__);
1822 return;
1823 }
1824
1825 if (afi != AFI_IP && afi != AFI_IP6) {
1826 vnc_zlog_debug_verbose("%s: bad afi: %d", __func__, afi);
1827 return;
1828 }
1829
1830 /*
1831 * Go through the entire BGP VPN table and export to BGP unicast.
1832 */
1833
1834 vnc_zlog_debug_verbose("%s: starting RD loop", __func__);
1835
1836 /* Loop over all the RDs */
1837 for (pdest = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); pdest;
1838 pdest = bgp_route_next(pdest)) {
1839
1840 struct bgp_table *table;
1841 struct bgp_dest *dest;
1842 struct bgp_path_info *ri;
1843 const struct prefix *pdest_p = bgp_dest_get_prefix(pdest);
1844
1845 memset(&prd, 0, sizeof(prd));
1846 prd.family = AF_UNSPEC;
1847 prd.prefixlen = 64;
1848 memcpy(prd.val, pdest_p->u.val, 8);
1849
1850 /* This is the per-RD table of prefixes */
1851 table = bgp_dest_get_bgp_table_info(pdest);
1852
1853 if (!table)
1854 continue;
1855
1856 for (dest = bgp_table_top(table); dest;
1857 dest = bgp_route_next(dest)) {
1858 const struct prefix *dest_p;
1859
1860 /*
1861 * skip prefix list check if no routes here
1862 */
1863 if (!bgp_dest_has_bgp_path_info_data(dest))
1864 continue;
1865
1866 vnc_zlog_debug_verbose("%s: checking prefix %pBD",
1867 __func__, dest);
1868
1869 dest_p = bgp_dest_get_prefix(dest);
1870
1871 /*
1872 * prefix list check
1873 */
1874 if (hc->plist_export_bgp[afi]) {
1875 if (prefix_list_apply(hc->plist_export_bgp[afi],
1876 dest_p)
1877 == PREFIX_DENY) {
1878
1879 vnc_zlog_debug_verbose(
1880 "%s: prefix list says DENY",
1881 __func__);
1882 continue;
1883 }
1884 }
1885
1886 for (ri = bgp_dest_get_bgp_path_info(dest); ri;
1887 ri = ri->next) {
1888
1889 vnc_zlog_debug_verbose("%s: ri->sub_type: %d",
1890 __func__, ri->sub_type);
1891
1892 if (ri->sub_type == BGP_ROUTE_NORMAL
1893 || ri->sub_type == BGP_ROUTE_RFP) {
1894
1895 struct vnc_export_info *eti;
1896 struct attr hattr;
1897 struct attr *iattr;
1898
1899 /*
1900 * Construct new attribute set with
1901 * NVE's VN addr as
1902 * nexthop and without Tunnel Encap attr
1903 */
1904 if (encap_attr_export(&hattr, ri->attr,
1905 NULL, NULL)) {
1906 vnc_zlog_debug_verbose(
1907 "%s: encap_attr_export failed",
1908 __func__);
1909 continue;
1910 }
1911
1912 if (hc->routemap_export_bgp) {
1913 struct bgp_path_info info;
1914 route_map_result_t ret;
1915
1916 memset(&info, 0, sizeof(info));
1917 info.peer = ri->peer;
1918 info.attr = &hattr;
1919 ret = route_map_apply(
1920 hc->routemap_export_bgp,
1921 dest_p, &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 }