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