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