]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_evpn_vty.c
fix coding style
[mirror_frr.git] / bgpd / bgp_evpn_vty.c
1 /* Ethernet-VPN Packet and vty Processing File
2 * Copyright (C) 2017 6WIND
3 *
4 * This file is part of FRRouting
5 *
6 * FRRouting is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRRouting is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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 #include <zebra.h>
22 #include "command.h"
23 #include "prefix.h"
24 #include "lib/json.h"
25
26 #include "bgpd/bgpd.h"
27 #include "bgpd/bgp_table.h"
28 #include "bgpd/bgp_attr.h"
29 #include "bgpd/bgp_route.h"
30 #include "bgpd/bgp_mplsvpn.h"
31 #include "bgpd/bgp_vpn.h"
32 #include "bgpd/bgp_evpn_vty.h"
33 #include "bgpd/bgp_evpn.h"
34 #include "bgpd/bgp_evpn_private.h"
35 #include "bgpd/bgp_zebra.h"
36 #include "bgpd/bgp_vty.h"
37
38 #define SHOW_DISPLAY_STANDARD 0
39 #define SHOW_DISPLAY_TAGS 1
40 #define SHOW_DISPLAY_OVERLAY 2
41 #define VNI_STR_LEN 32
42
43 /*
44 * Context for VNI hash walk - used by callbacks.
45 */
46 struct vni_walk_ctx {
47 struct bgp *bgp;
48 struct vty *vty;
49 struct in_addr vtep_ip;
50 json_object *json;
51 };
52
53 struct evpn_config_write {
54 int write;
55 struct vty *vty;
56 };
57
58 #if defined(HAVE_CUMULUS)
59 static void display_import_rt(struct vty *vty, struct irt_node *irt,
60 json_object *json)
61 {
62 u_char *pnt;
63 u_char type, sub_type;
64 struct ecommunity_as {
65 as_t as;
66 u_int32_t val;
67 } eas;
68 struct ecommunity_ip {
69 struct in_addr ip;
70 u_int16_t val;
71 } eip;
72 struct listnode *node, *nnode;
73 struct bgpevpn *tmp_vpn;
74 json_object *json_rt = NULL;
75 json_object *json_vnis = NULL;
76 char rt_buf[RT_ADDRSTRLEN];
77
78 if (json) {
79 json_rt = json_object_new_object();
80 json_vnis = json_object_new_array();
81 }
82
83 /* TODO: This needs to go into a function */
84
85 pnt = (u_char *)&irt->rt.val;
86 type = *pnt++;
87 sub_type = *pnt++;
88 if (sub_type != ECOMMUNITY_ROUTE_TARGET)
89 return;
90
91 switch (type) {
92 case ECOMMUNITY_ENCODE_AS:
93 eas.as = (*pnt++ << 8);
94 eas.as |= (*pnt++);
95
96 eas.val = (*pnt++ << 24);
97 eas.val |= (*pnt++ << 16);
98 eas.val |= (*pnt++ << 8);
99 eas.val |= (*pnt++);
100
101 snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
102
103 if (json)
104 json_object_string_add(json_rt, "rt", rt_buf);
105 else
106 vty_out(vty, "Route-target: %s", rt_buf);
107
108 break;
109
110 case ECOMMUNITY_ENCODE_IP:
111 memcpy(&eip.ip, pnt, 4);
112 pnt += 4;
113 eip.val = (*pnt++ << 8);
114 eip.val |= (*pnt++);
115
116 snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
117 eip.val);
118
119 if (json)
120 json_object_string_add(json_rt, "rt", rt_buf);
121 else
122 vty_out(vty, "Route-target: %s", rt_buf);
123
124 break;
125
126 case ECOMMUNITY_ENCODE_AS4:
127 eas.as = (*pnt++ << 24);
128 eas.as |= (*pnt++ << 16);
129 eas.as |= (*pnt++ << 8);
130 eas.as |= (*pnt++);
131
132 eas.val = (*pnt++ << 8);
133 eas.val |= (*pnt++);
134
135 snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
136
137 if (json)
138 json_object_string_add(json_rt, "rt", rt_buf);
139 else
140 vty_out(vty, "Route-target: %s", rt_buf);
141
142 break;
143
144 default:
145 return;
146 }
147
148 if (!json) {
149 vty_out(vty,
150 "\nList of VNIs importing routes with this route-target:\n");
151 }
152
153 for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) {
154 if (json)
155 json_object_array_add(
156 json_vnis, json_object_new_int64(tmp_vpn->vni));
157 else
158 vty_out(vty, " %u\n", tmp_vpn->vni);
159 }
160
161 if (json) {
162 json_object_object_add(json_rt, "vnis", json_vnis);
163 json_object_object_add(json, rt_buf, json_rt);
164 }
165
166 }
167
168 static void show_import_rt_entry(struct hash_backet *backet, void *args[])
169 {
170 json_object *json = NULL;
171 struct vty *vty = NULL;
172 struct irt_node *irt = (struct irt_node *)backet->data;
173
174 vty = args[0];
175 json = args[1];
176
177 display_import_rt(vty, irt, json);
178
179 return;
180 }
181
182 static void bgp_evpn_show_route_rd_header(struct vty *vty,
183 struct bgp_node *rd_rn,
184 json_object *json)
185 {
186 u_int16_t type;
187 struct rd_as rd_as;
188 struct rd_ip rd_ip;
189 u_char *pnt;
190 char rd_str[RD_ADDRSTRLEN];
191
192 pnt = rd_rn->p.u.val;
193
194 /* Decode RD type. */
195 type = decode_rd_type(pnt);
196
197 if (json)
198 return;
199
200 vty_out(vty, "Route Distinguisher: ");
201
202 switch (type) {
203 case RD_TYPE_AS:
204 decode_rd_as(pnt + 2, &rd_as);
205 snprintf(rd_str, RD_ADDRSTRLEN, "%u:%d", rd_as.as, rd_as.val);
206 break;
207
208 case RD_TYPE_IP:
209 decode_rd_ip(pnt + 2, &rd_ip);
210 snprintf(rd_str, RD_ADDRSTRLEN, "%s:%d", inet_ntoa(rd_ip.ip),
211 rd_ip.val);
212 break;
213
214 default:
215 snprintf(rd_str, RD_ADDRSTRLEN, "Unknown RD type");
216 break;
217 }
218
219 vty_out(vty, "%s\n", rd_str);
220 }
221
222 static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
223 json_object *json)
224 {
225 char ri_header[] =
226 " Network Next Hop Metric LocPrf Weight Path\n";
227
228 if (json)
229 return;
230
231
232 vty_out(vty, "BGP table version is 0, local router ID is %s\n",
233 inet_ntoa(bgp->router_id));
234 vty_out(vty,
235 "Status codes: s suppressed, d damped, h history, "
236 "* valid, > best, i - internal\n");
237 vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
238 vty_out(vty,
239 "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
240 vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n\n");
241 vty_out(vty, "%s", ri_header);
242 }
243
244 static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
245 {
246 char buf1[INET6_ADDRSTRLEN];
247 char *ecom_str;
248 struct listnode *node, *nnode;
249 struct ecommunity *ecom;
250 json_object *json_import_rtl;
251 json_object *json_export_rtl;
252
253 if (json) {
254 json_import_rtl = json_object_new_array();
255 json_export_rtl = json_object_new_array();
256 json_object_int_add(json, "vni", vpn->vni);
257 json_object_string_add(json, "kernelFlag",
258 is_vni_live(vpn) ? "Yes" : "No");
259 json_object_string_add(
260 json, "rd",
261 prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
262 json_object_string_add(json, "originatorIp",
263 inet_ntoa(vpn->originator_ip));
264 json_object_string_add(json, "advertiseGatewayMacip",
265 vpn->advertise_gw_macip ? "Yes" : "No");
266 } else {
267 vty_out(vty, "VNI: %d", vpn->vni);
268 if (is_vni_live(vpn))
269 vty_out(vty, " (known to the kernel)");
270 vty_out(vty, "\n");
271
272 vty_out(vty, " RD: %s\n",
273 prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
274 vty_out(vty, " Originator IP: %s\n",
275 inet_ntoa(vpn->originator_ip));
276 vty_out(vty, " Advertise-gw-macip : %s\n",
277 vpn->advertise_gw_macip ? "Yes" : "No");
278 }
279
280 if (!json)
281 vty_out(vty, " Import Route Target:\n");
282
283 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
284 ecom_str = ecommunity_ecom2str(ecom,
285 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
286
287 if (json)
288 json_object_array_add(json_import_rtl,
289 json_object_new_string(ecom_str));
290 else
291 vty_out(vty, " %s\n", ecom_str);
292
293 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
294 }
295
296 if (json)
297 json_object_object_add(json, "importRts", json_import_rtl);
298 else
299 vty_out(vty, " Export Route Target:\n");
300
301 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
302 ecom_str = ecommunity_ecom2str(ecom,
303 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
304
305 if (json)
306 json_object_array_add(json_export_rtl,
307 json_object_new_string(ecom_str));
308 else
309 vty_out(vty, " %s\n", ecom_str);
310
311 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
312 }
313
314 if (json)
315 json_object_object_add(json, "exportRts", json_export_rtl);
316 }
317
318 static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
319 struct vty *vty, struct in_addr vtep_ip,
320 json_object *json)
321 {
322 struct bgp_node *rn;
323 struct bgp_info *ri;
324 int header = 1;
325 u_int32_t prefix_cnt, path_cnt;
326
327 prefix_cnt = path_cnt = 0;
328
329 for (rn = bgp_table_top(vpn->route_table); rn;
330 rn = bgp_route_next(rn)) {
331 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
332 int add_prefix_to_json = 0;
333 char prefix_str[BUFSIZ];
334 json_object *json_paths = NULL;
335 json_object *json_prefix = NULL;
336
337 bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
338 sizeof(prefix_str));
339
340 if (type && evp->prefix.route_type != type)
341 continue;
342
343 if (json)
344 json_prefix = json_object_new_object();
345
346 if (rn->info) {
347 /* Overall header/legend displayed once. */
348 if (header) {
349 bgp_evpn_show_route_header(vty, bgp, json);
350 header = 0;
351 }
352
353 prefix_cnt++;
354 }
355
356 if (json)
357 json_paths = json_object_new_array();
358
359 /* For EVPN, the prefix is displayed for each path (to fit in
360 * with code that already exists).
361 */
362 for (ri = rn->info; ri; ri = ri->next) {
363 json_object *json_path = NULL;
364
365 if (vtep_ip.s_addr
366 && !IPV4_ADDR_SAME(&(vtep_ip),
367 &(ri->attr->nexthop)))
368 continue;
369
370 if (json)
371 json_path = json_object_new_array();
372
373 route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, json_path);
374
375 if (json)
376 json_object_array_add(json_paths, json_path);
377
378 path_cnt++;
379 add_prefix_to_json = 1;
380 }
381
382 if (json && add_prefix_to_json) {
383 json_object_string_add(json_prefix, "prefix",
384 prefix_str);
385 json_object_int_add(json_prefix, "prefixLen",
386 rn->p.prefixlen);
387 json_object_object_add(json_prefix, "paths",
388 json_paths);
389 json_object_object_add(json, prefix_str, json_prefix);
390 }
391 }
392
393 if (json) {
394 json_object_int_add(json, "numPrefix", prefix_cnt);
395 json_object_int_add(json, "numPaths", path_cnt);
396 } else {
397 if (prefix_cnt == 0)
398 vty_out(vty, "No EVPN prefixes %sexist for this VNI",
399 type ? "(of requested type) " : "");
400 else
401 vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s",
402 prefix_cnt, path_cnt,
403 type ? " (of requested type)" : "");
404 }
405 }
406
407 static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
408 {
409 struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
410 struct vni_walk_ctx *wctx = arg;
411 struct vty *vty = wctx->vty;
412 json_object *json = wctx->json;
413 json_object *json_vni = NULL;
414 char vni_str[VNI_STR_LEN];
415
416 snprintf(vni_str, VNI_STR_LEN, "%d", vpn->vni);
417 if (json) {
418 json_vni = json_object_new_object();
419 json_object_int_add(json_vni, "vni", vpn->vni);
420 } else {
421 vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
422 }
423
424 show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni);
425
426 if (json)
427 json_object_object_add(json, vni_str, json_vni);
428 }
429
430 static void show_vni_entry(struct hash_backet *backet, void *args[])
431 {
432 struct vty *vty;
433 json_object *json;
434 json_object *json_vni;
435 json_object *json_import_rtl;
436 json_object *json_export_rtl;
437 struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
438 char buf1[10];
439 char buf2[INET6_ADDRSTRLEN];
440 char rt_buf[25];
441 char *ecom_str;
442 struct listnode *node, *nnode;
443 struct ecommunity *ecom;
444
445 vty = args[0];
446 json = args[1];
447
448 if (json) {
449 json_vni = json_object_new_object();
450 json_import_rtl = json_object_new_array();
451 json_export_rtl = json_object_new_array();
452 }
453
454 buf1[0] = '\0';
455 if (is_vni_live(vpn))
456 sprintf(buf1, "*");
457
458 if (json) {
459 json_object_int_add(json_vni, "vni", vpn->vni);
460 json_object_string_add(json_vni, "inKernel",
461 is_vni_live(vpn) ? "True" : "False");
462 json_object_string_add(json_vni, "originatorIp",
463 inet_ntoa(vpn->originator_ip));
464 json_object_string_add(
465 json_vni, "rd",
466 prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
467 } else {
468 vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
469 inet_ntoa(vpn->originator_ip),
470 prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
471 }
472
473 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
474 ecom_str = ecommunity_ecom2str(ecom,
475 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
476
477 if (json) {
478 json_object_array_add(json_import_rtl,
479 json_object_new_string(ecom_str));
480 } else {
481 if (listcount(vpn->import_rtl) > 1)
482 sprintf(rt_buf, "%s, ...", ecom_str);
483 else
484 sprintf(rt_buf, "%s", ecom_str);
485 vty_out(vty, " %-25s", rt_buf);
486 }
487
488 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
489
490 /* If there are multiple import RTs we break here and show only
491 * one */
492 if (!json)
493 break;
494 }
495
496 if (json)
497 json_object_object_add(json_vni, "importRTs", json_import_rtl);
498
499 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
500 ecom_str = ecommunity_ecom2str(ecom,
501 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
502
503 if (json) {
504 json_object_array_add(json_export_rtl,
505 json_object_new_string(ecom_str));
506 } else {
507 if (listcount(vpn->export_rtl) > 1)
508 sprintf(rt_buf, "%s, ...", ecom_str);
509 else
510 sprintf(rt_buf, "%s", ecom_str);
511 vty_out(vty, " %-25s", rt_buf);
512 }
513
514 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
515
516 /* If there are multiple export RTs we break here and show only
517 * one */
518 if (!json)
519 break;
520 }
521
522 if (json) {
523 char vni_str[VNI_STR_LEN];
524
525 json_object_object_add(json_vni, "exportRTs", json_export_rtl);
526 snprintf(vni_str, VNI_STR_LEN, "%u", vpn->vni);
527 json_object_object_add(json, vni_str, json_vni);
528 } else {
529 vty_out(vty, "\n");
530 }
531 }
532 #endif /* HAVE_CUMULUS */
533
534 static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
535 enum bgp_show_type type, void *output_arg,
536 int option, u_char use_json)
537 {
538 afi_t afi = AFI_L2VPN;
539 struct bgp *bgp;
540 struct bgp_table *table;
541 struct bgp_node *rn;
542 struct bgp_node *rm;
543 struct bgp_info *ri;
544 int rd_header;
545 int header = 1;
546
547 unsigned long output_count = 0;
548 unsigned long total_count = 0;
549 json_object *json = NULL;
550 json_object *json_nroute = NULL;
551 json_object *json_array = NULL;
552 json_object *json_scode = NULL;
553 json_object *json_ocode = NULL;
554
555 bgp = bgp_get_default();
556 if (bgp == NULL) {
557 if (!use_json)
558 vty_out(vty, "No BGP process is configured\n");
559 else
560 vty_out(vty, "{}\n");
561 return CMD_WARNING;
562 }
563
564 if (use_json) {
565 json_scode = json_object_new_object();
566 json_ocode = json_object_new_object();
567 json = json_object_new_object();
568 json_nroute = json_object_new_object();
569
570 json_object_string_add(json_scode, "suppressed", "s");
571 json_object_string_add(json_scode, "damped", "d");
572 json_object_string_add(json_scode, "history", "h");
573 json_object_string_add(json_scode, "valid", "*");
574 json_object_string_add(json_scode, "best", ">");
575 json_object_string_add(json_scode, "internal", "i");
576
577 json_object_string_add(json_ocode, "igp", "i");
578 json_object_string_add(json_ocode, "egp", "e");
579 json_object_string_add(json_ocode, "incomplete", "?");
580 }
581
582 for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
583 rn = bgp_route_next(rn)) {
584 if (use_json)
585 continue; /* XXX json TODO */
586
587 if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
588 continue;
589
590 if ((table = rn->info) != NULL) {
591 rd_header = 1;
592
593 for (rm = bgp_table_top(table); rm;
594 rm = bgp_route_next(rm))
595 for (ri = rm->info; ri; ri = ri->next) {
596 total_count++;
597 if (type == bgp_show_type_neighbor) {
598 union sockunion *su =
599 output_arg;
600
601 if (ri->peer->su_remote == NULL
602 || !sockunion_same(
603 ri->peer->su_remote,
604 su))
605 continue;
606 }
607 if (header == 0) {
608 if (use_json) {
609 if (option
610 == SHOW_DISPLAY_TAGS) {
611 json_object_int_add(
612 json,
613 "bgpTableVersion",
614 0);
615 json_object_string_add(
616 json,
617 "bgpLocalRouterId",
618 inet_ntoa(
619 bgp->router_id));
620 json_object_object_add(
621 json,
622 "bgpStatusCodes",
623 json_scode);
624 json_object_object_add(
625 json,
626 "bgpOriginCodes",
627 json_ocode);
628 }
629 } else {
630 if (option
631 == SHOW_DISPLAY_TAGS)
632 vty_out(vty,
633 V4_HEADER_TAG);
634 else if (
635 option
636 == SHOW_DISPLAY_OVERLAY)
637 vty_out(vty,
638 V4_HEADER_OVERLAY);
639 else {
640 vty_out(vty,
641 "BGP table version is 0, local router ID is %s\n",
642 inet_ntoa(
643 bgp->router_id));
644 vty_out(vty,
645 "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
646 vty_out(vty,
647 "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n");
648 vty_out(vty,
649 V4_HEADER);
650 }
651 }
652 header = 0;
653 }
654 if (rd_header) {
655 u_int16_t type;
656 struct rd_as rd_as;
657 struct rd_ip rd_ip;
658 u_char *pnt;
659
660 pnt = rn->p.u.val;
661
662 /* Decode RD type. */
663 type = decode_rd_type(pnt);
664 /* Decode RD value. */
665 if (type == RD_TYPE_AS)
666 decode_rd_as(pnt + 2,
667 &rd_as);
668 else if (type == RD_TYPE_AS4)
669 decode_rd_as4(pnt + 2,
670 &rd_as);
671 else if (type == RD_TYPE_IP)
672 decode_rd_ip(pnt + 2,
673 &rd_ip);
674 if (use_json) {
675 char buffer[BUFSIZ];
676 if (type == RD_TYPE_AS
677 || type == RD_TYPE_AS4)
678 sprintf(buffer,
679 "%u:%d",
680 rd_as.as,
681 rd_as.val);
682 else if (type
683 == RD_TYPE_IP)
684 sprintf(buffer,
685 "%s:%d",
686 inet_ntoa(
687 rd_ip.ip),
688 rd_ip.val);
689 json_object_string_add(
690 json_nroute,
691 "routeDistinguisher",
692 buffer);
693 } else {
694 vty_out(vty,
695 "Route Distinguisher: ");
696 if (type == RD_TYPE_AS)
697 vty_out(vty,
698 "as2 %u:%d",
699 rd_as.as,
700 rd_as.val);
701 else if (type
702 == RD_TYPE_AS4)
703 vty_out(vty,
704 "as4 %u:%d",
705 rd_as.as,
706 rd_as.val);
707 else if (type
708 == RD_TYPE_IP)
709 vty_out(vty,
710 "ip %s:%d",
711 inet_ntoa(
712 rd_ip.ip),
713 rd_ip.val);
714 vty_out(vty, "\n\n");
715 }
716 rd_header = 0;
717 }
718 if (use_json)
719 json_array =
720 json_object_new_array();
721 else
722 json_array = NULL;
723 if (option == SHOW_DISPLAY_TAGS)
724 route_vty_out_tag(
725 vty, &rm->p, ri, 0,
726 SAFI_EVPN, json_array);
727 else if (option == SHOW_DISPLAY_OVERLAY)
728 route_vty_out_overlay(
729 vty, &rm->p, ri, 0,
730 json_array);
731 else
732 route_vty_out(vty, &rm->p, ri,
733 0, SAFI_EVPN,
734 json_array);
735 output_count++;
736 }
737 /* XXX json */
738 }
739 }
740 if (output_count == 0)
741 vty_out(vty, "No prefixes displayed, %ld exist\n", total_count);
742 else
743 vty_out(vty, "\nDisplayed %ld out of %ld total prefixes\n",
744 output_count, total_count);
745 return CMD_SUCCESS;
746 }
747
748 DEFUN(show_ip_bgp_l2vpn_evpn,
749 show_ip_bgp_l2vpn_evpn_cmd,
750 "show [ip] bgp l2vpn evpn [json]",
751 SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR)
752 {
753 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0,
754 use_json(argc, argv));
755 }
756
757 DEFUN(show_ip_bgp_l2vpn_evpn_rd,
758 show_ip_bgp_l2vpn_evpn_rd_cmd,
759 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]",
760 SHOW_STR
761 IP_STR
762 BGP_STR
763 L2VPN_HELP_STR
764 EVPN_HELP_STR
765 "Display information for a route distinguisher\n"
766 "VPN Route Distinguisher\n" JSON_STR)
767 {
768 int idx_ext_community = 0;
769 int ret;
770 struct prefix_rd prd;
771
772 argv_find(argv, argc, "ASN:nn_or_IP-address:nn", &idx_ext_community);
773
774 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
775 if (!ret) {
776 vty_out(vty, "%% Malformed Route Distinguisher\n");
777 return CMD_WARNING;
778 }
779 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0,
780 use_json(argc, argv));
781 }
782
783 DEFUN(show_ip_bgp_l2vpn_evpn_all_tags,
784 show_ip_bgp_l2vpn_evpn_all_tags_cmd,
785 "show [ip] bgp l2vpn evpn all tags",
786 SHOW_STR
787 IP_STR
788 BGP_STR
789 L2VPN_HELP_STR
790 EVPN_HELP_STR
791 "Display information about all EVPN NLRIs\n"
792 "Display BGP tags for prefixes\n")
793 {
794 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1,
795 0);
796 }
797
798 DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags,
799 show_ip_bgp_l2vpn_evpn_rd_tags_cmd,
800 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags",
801 SHOW_STR
802 IP_STR
803 BGP_STR
804 L2VPN_HELP_STR
805 EVPN_HELP_STR
806 "Display information for a route distinguisher\n"
807 "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n")
808 {
809 int idx_ext_community = 0;
810 int ret;
811 struct prefix_rd prd;
812
813 argv_find(argv, argc, "ASN:nn_or_IP-address:nn", &idx_ext_community);
814
815 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
816 if (!ret) {
817 vty_out(vty, "%% Malformed Route Distinguisher\n");
818 return CMD_WARNING;
819 }
820 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1,
821 0);
822 }
823
824 DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
825 show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
826 "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
827 SHOW_STR
828 IP_STR
829 BGP_STR
830 L2VPN_HELP_STR
831 EVPN_HELP_STR
832 "Display information about all EVPN NLRIs\n"
833 "Detailed information on TCP and BGP neighbor connections\n"
834 "Neighbor to display information about\n"
835 "Display routes learned from neighbor\n" JSON_STR)
836 {
837 int idx_ipv4 = 0;
838 union sockunion su;
839 struct peer *peer;
840 int ret;
841 u_char uj = use_json(argc, argv);
842
843 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
844
845 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
846 if (ret < 0) {
847 if (uj) {
848 json_object *json_no = NULL;
849 json_no = json_object_new_object();
850 json_object_string_add(json_no, "warning",
851 "Malformed address");
852 vty_out(vty, "%s\n",
853 json_object_to_json_string(json_no));
854 json_object_free(json_no);
855 } else
856 vty_out(vty, "Malformed address: %s\n",
857 argv[idx_ipv4]->arg);
858 return CMD_WARNING;
859 }
860
861 peer = peer_lookup(NULL, &su);
862 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
863 if (uj) {
864 json_object *json_no = NULL;
865 json_no = json_object_new_object();
866 json_object_string_add(
867 json_no, "warning",
868 "No such neighbor or address family");
869 vty_out(vty, "%s\n",
870 json_object_to_json_string(json_no));
871 json_object_free(json_no);
872 } else
873 vty_out(vty, "%% No such neighbor or address family\n");
874 return CMD_WARNING;
875 }
876
877 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0,
878 uj);
879 }
880
881 DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
882 show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
883 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]",
884 SHOW_STR
885 IP_STR
886 BGP_STR
887 L2VPN_HELP_STR
888 EVPN_HELP_STR
889 "Display information for a route distinguisher\n"
890 "VPN Route Distinguisher\n"
891 "Detailed information on TCP and BGP neighbor connections\n"
892 "Neighbor to display information about\n"
893 "Display routes learned from neighbor\n" JSON_STR)
894 {
895 int idx_ext_community = 0;
896 int idx_ipv4 = 0;
897 int ret;
898 union sockunion su;
899 struct peer *peer;
900 struct prefix_rd prd;
901 u_char uj = use_json(argc, argv);
902
903 argv_find(argv, argc, "ASN:nn_or_IP-address:nn", &idx_ext_community);
904 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
905
906 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
907 if (!ret) {
908 if (uj) {
909 json_object *json_no = NULL;
910 json_no = json_object_new_object();
911 json_object_string_add(json_no, "warning",
912 "Malformed Route Distinguisher");
913 vty_out(vty, "%s\n",
914 json_object_to_json_string(json_no));
915 json_object_free(json_no);
916 } else
917 vty_out(vty, "%% Malformed Route Distinguisher\n");
918 return CMD_WARNING;
919 }
920
921 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
922 if (ret < 0) {
923 if (uj) {
924 json_object *json_no = NULL;
925 json_no = json_object_new_object();
926 json_object_string_add(json_no, "warning",
927 "Malformed address");
928 vty_out(vty, "%s\n",
929 json_object_to_json_string(json_no));
930 json_object_free(json_no);
931 } else
932 vty_out(vty, "Malformed address: %s\n",
933 argv[idx_ext_community]->arg);
934 return CMD_WARNING;
935 }
936
937 peer = peer_lookup(NULL, &su);
938 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
939 if (uj) {
940 json_object *json_no = NULL;
941 json_no = json_object_new_object();
942 json_object_string_add(
943 json_no, "warning",
944 "No such neighbor or address family");
945 vty_out(vty, "%s\n",
946 json_object_to_json_string(json_no));
947 json_object_free(json_no);
948 } else
949 vty_out(vty, "%% No such neighbor or address family\n");
950 return CMD_WARNING;
951 }
952
953 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0,
954 uj);
955 }
956
957 DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
958 show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
959 "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
960 SHOW_STR
961 IP_STR
962 BGP_STR
963 L2VPN_HELP_STR
964 EVPN_HELP_STR
965 "Display information about all EVPN NLRIs\n"
966 "Detailed information on TCP and BGP neighbor connections\n"
967 "Neighbor to display information about\n"
968 "Display the routes advertised to a BGP neighbor\n" JSON_STR)
969 {
970 int idx_ipv4 = 0;
971 int ret;
972 struct peer *peer;
973 union sockunion su;
974 u_char uj = use_json(argc, argv);
975
976 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
977
978 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
979 if (ret < 0) {
980 if (uj) {
981 json_object *json_no = NULL;
982 json_no = json_object_new_object();
983 json_object_string_add(json_no, "warning",
984 "Malformed address");
985 vty_out(vty, "%s\n",
986 json_object_to_json_string(json_no));
987 json_object_free(json_no);
988 } else
989 vty_out(vty, "Malformed address: %s\n",
990 argv[idx_ipv4]->arg);
991 return CMD_WARNING;
992 }
993 peer = peer_lookup(NULL, &su);
994 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
995 if (uj) {
996 json_object *json_no = NULL;
997 json_no = json_object_new_object();
998 json_object_string_add(
999 json_no, "warning",
1000 "No such neighbor or address family");
1001 vty_out(vty, "%s\n",
1002 json_object_to_json_string(json_no));
1003 json_object_free(json_no);
1004 } else
1005 vty_out(vty, "%% No such neighbor or address family\n");
1006 return CMD_WARNING;
1007 }
1008
1009 return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj);
1010 }
1011
1012 DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
1013 show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
1014 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]",
1015 SHOW_STR
1016 IP_STR
1017 BGP_STR
1018 L2VPN_HELP_STR
1019 EVPN_HELP_STR
1020 "Display information for a route distinguisher\n"
1021 "VPN Route Distinguisher\n"
1022 "Detailed information on TCP and BGP neighbor connections\n"
1023 "Neighbor to display information about\n"
1024 "Display the routes advertised to a BGP neighbor\n" JSON_STR)
1025 {
1026 int idx_ext_community = 0;
1027 int idx_ipv4 = 0;
1028 int ret;
1029 struct peer *peer;
1030 struct prefix_rd prd;
1031 union sockunion su;
1032 u_char uj = use_json(argc, argv);
1033
1034 argv_find(argv, argc, "ASN:nn_or_IP-address:nn", &idx_ext_community);
1035 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
1036
1037 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
1038 if (ret < 0) {
1039 if (uj) {
1040 json_object *json_no = NULL;
1041 json_no = json_object_new_object();
1042 json_object_string_add(json_no, "warning",
1043 "Malformed address");
1044 vty_out(vty, "%s\n",
1045 json_object_to_json_string(json_no));
1046 json_object_free(json_no);
1047 } else
1048 vty_out(vty, "Malformed address: %s\n",
1049 argv[idx_ext_community]->arg);
1050 return CMD_WARNING;
1051 }
1052 peer = peer_lookup(NULL, &su);
1053 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
1054 if (uj) {
1055 json_object *json_no = NULL;
1056 json_no = json_object_new_object();
1057 json_object_string_add(
1058 json_no, "warning",
1059 "No such neighbor or address family");
1060 vty_out(vty, "%s\n",
1061 json_object_to_json_string(json_no));
1062 json_object_free(json_no);
1063 } else
1064 vty_out(vty, "%% No such neighbor or address family\n");
1065 return CMD_WARNING;
1066 }
1067
1068 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1069 if (!ret) {
1070 if (uj) {
1071 json_object *json_no = NULL;
1072 json_no = json_object_new_object();
1073 json_object_string_add(json_no, "warning",
1074 "Malformed Route Distinguisher");
1075 vty_out(vty, "%s\n",
1076 json_object_to_json_string(json_no));
1077 json_object_free(json_no);
1078 } else
1079 vty_out(vty, "%% Malformed Route Distinguisher\n");
1080 return CMD_WARNING;
1081 }
1082
1083 return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj);
1084 }
1085
1086 DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay,
1087 show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
1088 "show [ip] bgp l2vpn evpn all overlay",
1089 SHOW_STR
1090 IP_STR
1091 BGP_STR
1092 L2VPN_HELP_STR
1093 EVPN_HELP_STR
1094 "Display information about all EVPN NLRIs\n"
1095 "Display BGP Overlay Information for prefixes\n")
1096 {
1097 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL,
1098 SHOW_DISPLAY_OVERLAY,
1099 use_json(argc, argv));
1100 }
1101
1102 DEFUN(show_ip_bgp_evpn_rd_overlay,
1103 show_ip_bgp_evpn_rd_overlay_cmd,
1104 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay",
1105 SHOW_STR
1106 IP_STR
1107 BGP_STR
1108 L2VPN_HELP_STR
1109 EVPN_HELP_STR
1110 "Display information for a route distinguisher\n"
1111 "VPN Route Distinguisher\n"
1112 "Display BGP Overlay Information for prefixes\n")
1113 {
1114 int idx_ext_community = 0;
1115 int ret;
1116 struct prefix_rd prd;
1117
1118 argv_find(argv, argc, "ASN:nn_or_IP-address:nn", &idx_ext_community);
1119
1120 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1121 if (!ret) {
1122 vty_out(vty, "%% Malformed Route Distinguisher\n");
1123 return CMD_WARNING;
1124 }
1125 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL,
1126 SHOW_DISPLAY_OVERLAY,
1127 use_json(argc, argv));
1128 }
1129
1130 /* For testing purpose, static route of MPLS-VPN. */
1131 DEFUN(evpnrt5_network,
1132 evpnrt5_network_cmd,
1133 "network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X> routermac WORD [route-map WORD]",
1134 "Specify a network to announce via BGP\n"
1135 "IP prefix\n"
1136 "IPv6 prefix\n"
1137 "Specify Route Distinguisher\n"
1138 "VPN Route Distinguisher\n"
1139 "Ethernet Tag\n"
1140 "Ethernet Tag Value\n"
1141 "BGP label\n"
1142 "label value\n"
1143 "Ethernet Segment Identifier\n"
1144 "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
1145 "Gateway IP\n"
1146 "Gateway IP ( A.B.C.D )\n"
1147 "Gateway IPv6 ( X:X::X:X )\n"
1148 "Router Mac Ext Comm\n"
1149 "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n"
1150 "Route-map to modify the attributes\n"
1151 "Name of the route map\n")
1152 {
1153 int idx_ipv4_prefixlen = 1;
1154 int idx_ext_community = 3;
1155 int idx_word = 7;
1156 int idx_esi = 9;
1157 int idx_gwip = 11;
1158 int idx_ethtag = 5;
1159 int idx_routermac = 13;
1160 int idx_rmap = 15;
1161 return bgp_static_set_safi(
1162 AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
1163 argv[idx_ext_community]->arg, argv[idx_word]->arg,
1164 argv[idx_rmap] ? argv[idx_gwip]->arg : NULL,
1165 BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
1166 argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
1167 argv[idx_routermac]->arg);
1168 }
1169
1170 /* For testing purpose, static route of MPLS-VPN. */
1171 DEFUN(no_evpnrt5_network,
1172 no_evpnrt5_network_cmd,
1173 "no network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X>",
1174 NO_STR
1175 "Specify a network to announce via BGP\n"
1176 "IP prefix\n"
1177 "IPv6 prefix\n"
1178 "Specify Route Distinguisher\n"
1179 "VPN Route Distinguisher\n"
1180 "Ethernet Tag\n"
1181 "Ethernet Tag Value\n"
1182 "BGP label\n"
1183 "label value\n"
1184 "Ethernet Segment Identifier\n"
1185 "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
1186 "Gateway IP\n" "Gateway IP ( A.B.C.D )\n" "Gateway IPv6 ( X:X::X:X )\n")
1187 {
1188 int idx_ipv4_prefixlen = 2;
1189 int idx_ext_community = 4;
1190 int idx_label = 8;
1191 int idx_ethtag = 6;
1192 int idx_esi = 10;
1193 int idx_gwip = 12;
1194 return bgp_static_unset_safi(
1195 AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
1196 argv[idx_ext_community]->arg, argv[idx_label]->arg,
1197 BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
1198 argv[idx_gwip]->arg, argv[idx_ethtag]->arg);
1199 }
1200
1201 #if defined(HAVE_CUMULUS)
1202 static void evpn_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn,
1203 struct list *rtl)
1204 {
1205 struct listnode *node, *nnode, *node_to_del;
1206 struct ecommunity *ecom, *ecom_auto;
1207 struct ecommunity_val eval;
1208
1209 encode_route_target_as((bgp->as & 0xFFFF), vpn->vni, &eval);
1210
1211 ecom_auto = ecommunity_new();
1212 ecommunity_add_val(ecom_auto, &eval);
1213 node_to_del = NULL;
1214
1215 for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
1216 if (ecommunity_match(ecom, ecom_auto)) {
1217 ecommunity_free(&ecom);
1218 node_to_del = node;
1219 }
1220 }
1221
1222 if (node_to_del)
1223 list_delete_node(rtl, node_to_del);
1224
1225 ecommunity_free(&ecom_auto);
1226 }
1227
1228 static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
1229 {
1230 evpn_rt_delete_auto(bgp, vpn, vpn->import_rtl);
1231 }
1232
1233 static void evpn_export_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
1234 {
1235 evpn_rt_delete_auto(bgp, vpn, vpn->export_rtl);
1236 }
1237
1238 /*
1239 * Configure the Import RTs for a VNI (vty handler). Caller expected to
1240 * check that this is a change.
1241 */
1242 static void evpn_configure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
1243 struct ecommunity *ecomadd)
1244 {
1245 /* If the VNI is "live", we need to uninstall routes using the current
1246 * import RT(s) first before we update the import RT, and subsequently
1247 * install routes.
1248 */
1249 if (is_vni_live(vpn))
1250 bgp_evpn_uninstall_routes(bgp, vpn);
1251
1252 /* Cleanup the RT to VNI mapping and get rid of existing import RT. */
1253 bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
1254
1255 /* If the auto route-target is in use we must remove it */
1256 evpn_import_rt_delete_auto(bgp, vpn);
1257
1258 /* Add new RT and rebuild the RT to VNI mapping */
1259 listnode_add_sort(vpn->import_rtl, ecomadd);
1260
1261 SET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
1262 bgp_evpn_map_vni_to_its_rts(bgp, vpn);
1263
1264 /* Install routes that match new import RT */
1265 if (is_vni_live(vpn))
1266 bgp_evpn_install_routes(bgp, vpn);
1267 }
1268
1269 /*
1270 * Unconfigure Import RT(s) for a VNI (vty handler).
1271 */
1272 static void evpn_unconfigure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
1273 struct ecommunity *ecomdel)
1274 {
1275 struct listnode *node, *nnode, *node_to_del;
1276 struct ecommunity *ecom;
1277
1278 /* Along the lines of "configure" except we have to reset to the
1279 * automatic value.
1280 */
1281 if (is_vni_live(vpn))
1282 bgp_evpn_uninstall_routes(bgp, vpn);
1283
1284 /* Cleanup the RT to VNI mapping and get rid of existing import RT. */
1285 bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
1286
1287 /* Delete all import RTs */
1288 if (ecomdel == NULL) {
1289 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom))
1290 ecommunity_free(&ecom);
1291
1292 list_delete_all_node(vpn->import_rtl);
1293 }
1294
1295 /* Delete a specific import RT */
1296 else {
1297 node_to_del = NULL;
1298
1299 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
1300 if (ecommunity_match(ecom, ecomdel)) {
1301 ecommunity_free(&ecom);
1302 node_to_del = node;
1303 break;
1304 }
1305 }
1306
1307 if (node_to_del)
1308 list_delete_node(vpn->import_rtl, node_to_del);
1309 }
1310
1311 /* Reset to auto RT - this also rebuilds the RT to VNI mapping */
1312 if (list_isempty(vpn->import_rtl)) {
1313 UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
1314 bgp_evpn_derive_auto_rt_import(bgp, vpn);
1315 }
1316 /* Rebuild the RT to VNI mapping */
1317 else
1318 bgp_evpn_map_vni_to_its_rts(bgp, vpn);
1319
1320 /* Install routes that match new import RT */
1321 if (is_vni_live(vpn))
1322 bgp_evpn_install_routes(bgp, vpn);
1323 }
1324
1325 /*
1326 * Configure the Export RT for a VNI (vty handler). Caller expected to
1327 * check that this is a change. Note that only a single export RT is
1328 * allowed for a VNI and any change to configuration is implemented as
1329 * a "replace" (similar to other configuration).
1330 */
1331 static void evpn_configure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
1332 struct ecommunity *ecomadd)
1333 {
1334 /* If the auto route-target is in use we must remove it */
1335 evpn_export_rt_delete_auto(bgp, vpn);
1336
1337 listnode_add_sort(vpn->export_rtl, ecomadd);
1338 SET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
1339
1340 if (is_vni_live(vpn))
1341 bgp_evpn_handle_export_rt_change(bgp, vpn);
1342 }
1343
1344 /*
1345 * Unconfigure the Export RT for a VNI (vty handler)
1346 */
1347 static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
1348 struct ecommunity *ecomdel)
1349 {
1350 struct listnode *node, *nnode, *node_to_del;
1351 struct ecommunity *ecom;
1352
1353 /* Delete all export RTs */
1354 if (ecomdel == NULL) {
1355 /* Reset to default and process all routes. */
1356 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
1357 ecommunity_free(&ecom);
1358
1359 list_delete_all_node(vpn->export_rtl);
1360 }
1361
1362 /* Delete a specific export RT */
1363 else {
1364 node_to_del = NULL;
1365
1366 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
1367 if (ecommunity_match(ecom, ecomdel)) {
1368 ecommunity_free(&ecom);
1369 node_to_del = node;
1370 break;
1371 }
1372 }
1373
1374 if (node_to_del)
1375 list_delete_node(vpn->export_rtl, node_to_del);
1376 }
1377
1378 if (list_isempty(vpn->export_rtl)) {
1379 UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
1380 bgp_evpn_derive_auto_rt_export(bgp, vpn);
1381 }
1382
1383 if (is_vni_live(vpn))
1384 bgp_evpn_handle_export_rt_change(bgp, vpn);
1385 }
1386
1387 /*
1388 * Configure RD for a VNI (vty handler)
1389 */
1390 static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
1391 struct prefix_rd *rd)
1392 {
1393 /* If the VNI is "live", we need to delete and withdraw this VNI's
1394 * local routes with the prior RD first. Then, after updating RD,
1395 * need to re-advertise.
1396 */
1397 if (is_vni_live(vpn))
1398 bgp_evpn_handle_rd_change(bgp, vpn, 1);
1399
1400 /* update RD */
1401 memcpy(&vpn->prd, rd, sizeof(struct prefix_rd));
1402 SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
1403
1404 if (is_vni_live(vpn))
1405 bgp_evpn_handle_rd_change(bgp, vpn, 0);
1406 }
1407
1408 /*
1409 * Unconfigure RD for a VNI (vty handler)
1410 */
1411 static void evpn_unconfigure_rd(struct bgp *bgp, struct bgpevpn *vpn)
1412 {
1413 /* If the VNI is "live", we need to delete and withdraw this VNI's
1414 * local routes with the prior RD first. Then, after resetting RD
1415 * to automatic value, need to re-advertise.
1416 */
1417 if (is_vni_live(vpn))
1418 bgp_evpn_handle_rd_change(bgp, vpn, 1);
1419
1420 /* reset RD to default */
1421 bgp_evpn_derive_auto_rd(bgp, vpn);
1422
1423 if (is_vni_live(vpn))
1424 bgp_evpn_handle_rd_change(bgp, vpn, 0);
1425 }
1426
1427 /*
1428 * Create VNI, if not already present (VTY handler). Mark as configured.
1429 */
1430 static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
1431 {
1432 struct bgpevpn *vpn;
1433
1434 if (!bgp->vnihash)
1435 return NULL;
1436
1437 vpn = bgp_evpn_lookup_vni(bgp, vni);
1438 if (!vpn) {
1439 vpn = bgp_evpn_new(bgp, vni, bgp->router_id);
1440 if (!vpn) {
1441 zlog_err(
1442 "%u: Failed to allocate VNI entry for VNI %u - at Config",
1443 bgp->vrf_id, vni);
1444 return NULL;
1445 }
1446 }
1447
1448 /* Mark as configured. */
1449 SET_FLAG(vpn->flags, VNI_FLAG_CFGD);
1450 return vpn;
1451 }
1452
1453 /*
1454 * Delete VNI. If VNI does not exist in the system (i.e., just
1455 * configuration), all that is needed is to free it. Otherwise,
1456 * any parameters configured for the VNI need to be reset (with
1457 * appropriate action) and the VNI marked as unconfigured; the
1458 * VNI will continue to exist, purely as a "learnt" entity.
1459 */
1460 static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn)
1461 {
1462 assert(bgp->vnihash);
1463
1464 if (!is_vni_live(vpn)) {
1465 bgp_evpn_free(bgp, vpn);
1466 return 0;
1467 }
1468
1469 /* We need to take the unconfigure action for each parameter of this VNI
1470 * that is configured. Some optimization is possible, but not worth the
1471 * additional code for an operation that should be pretty rare.
1472 */
1473 UNSET_FLAG(vpn->flags, VNI_FLAG_CFGD);
1474
1475 /* First, deal with the export side - RD and export RT changes. */
1476 if (is_rd_configured(vpn))
1477 evpn_unconfigure_rd(bgp, vpn);
1478 if (is_export_rt_configured(vpn))
1479 evpn_unconfigure_export_rt(bgp, vpn, NULL);
1480
1481 /* Next, deal with the import side. */
1482 if (is_import_rt_configured(vpn))
1483 evpn_unconfigure_import_rt(bgp, vpn, NULL);
1484
1485 return 0;
1486 }
1487
1488 /*
1489 * Display import RT mapping to VNIs (vty handler)
1490 */
1491 static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
1492 json_object *json)
1493 {
1494 void *args[2];
1495
1496 args[0] = vty;
1497 args[1] = json;
1498
1499 hash_iterate(
1500 bgp->import_rt_hash,
1501 (void (*)(struct hash_backet *, void *))show_import_rt_entry,
1502 args);
1503 }
1504
1505 /*
1506 * Display EVPN routes for all VNIs - vty handler.
1507 */
1508 static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
1509 struct in_addr vtep_ip,
1510 json_object *json)
1511 {
1512 u_int32_t num_vnis;
1513 struct vni_walk_ctx wctx;
1514
1515 num_vnis = hashcount(bgp->vnihash);
1516 if (!num_vnis)
1517 return;
1518 memset(&wctx, 0, sizeof(struct vni_walk_ctx));
1519 wctx.bgp = bgp;
1520 wctx.vty = vty;
1521 wctx.vtep_ip = vtep_ip;
1522 wctx.json = json;
1523 hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *,
1524 void *))show_vni_routes_hash,
1525 &wctx);
1526 }
1527
1528 /*
1529 * Display EVPN routes for a VNI -- for specific type-3 route (vty handler).
1530 */
1531 static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
1532 vni_t vni, struct in_addr orig_ip,
1533 json_object *json)
1534 {
1535 struct bgpevpn *vpn;
1536 struct prefix_evpn p;
1537 struct bgp_node *rn;
1538 struct bgp_info *ri;
1539 u_int32_t path_cnt = 0;
1540 afi_t afi;
1541 safi_t safi;
1542 json_object *json_paths = NULL;
1543
1544 afi = AFI_L2VPN;
1545 safi = SAFI_EVPN;
1546
1547 /* Locate VNI. */
1548 vpn = bgp_evpn_lookup_vni(bgp, vni);
1549 if (!vpn) {
1550 vty_out(vty, "VNI not found\n");
1551 return;
1552 }
1553
1554 /* See if route exists. */
1555 build_evpn_type3_prefix(&p, orig_ip);
1556 rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
1557 if (!rn || !rn->info) {
1558 if (!json)
1559 vty_out(vty, "%% Network not in table\n");
1560 return;
1561 }
1562
1563 if (json)
1564 json_paths = json_object_new_array();
1565
1566 /* Prefix and num paths displayed once per prefix. */
1567 route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json);
1568
1569 /* Display each path for this prefix. */
1570 for (ri = rn->info; ri; ri = ri->next) {
1571 json_object *json_path = NULL;
1572
1573 if (json)
1574 json_path = json_object_new_array();
1575
1576 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
1577 json_path);
1578
1579 if (json)
1580 json_object_array_add(json_paths, json_path);
1581
1582 path_cnt++;
1583 }
1584
1585 if (json) {
1586 if (path_cnt)
1587 json_object_object_add(json, "paths", json_paths);
1588
1589 json_object_int_add(json, "numPaths", path_cnt);
1590 } else {
1591 vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
1592 path_cnt);
1593 }
1594 }
1595
1596 /*
1597 * Display EVPN routes for a VNI -- for specific MAC and/or IP (vty handler).
1598 * By definition, only matching type-2 route will be displayed.
1599 */
1600 static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
1601 vni_t vni, struct ethaddr *mac,
1602 struct ipaddr *ip, json_object *json)
1603 {
1604 struct bgpevpn *vpn;
1605 struct prefix_evpn p;
1606 struct bgp_node *rn;
1607 struct bgp_info *ri;
1608 u_int32_t path_cnt = 0;
1609 afi_t afi;
1610 safi_t safi;
1611 json_object *json_paths = NULL;
1612
1613 afi = AFI_L2VPN;
1614 safi = SAFI_EVPN;
1615
1616 /* Locate VNI. */
1617 vpn = bgp_evpn_lookup_vni(bgp, vni);
1618 if (!vpn) {
1619 if (!json)
1620 vty_out(vty, "VNI not found\n");
1621 return;
1622 }
1623
1624 /* See if route exists. Look for both non-sticky and sticky. */
1625 build_evpn_type2_prefix(&p, mac, ip);
1626 rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
1627 if (!rn || !rn->info) {
1628 if (!json)
1629 vty_out(vty, "%% Network not in table\n");
1630 return;
1631 }
1632
1633 if (json)
1634 json_paths = json_object_new_array();
1635
1636 /* Prefix and num paths displayed once per prefix. */
1637 route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json);
1638
1639 /* Display each path for this prefix. */
1640 for (ri = rn->info; ri; ri = ri->next) {
1641 json_object *json_path = NULL;
1642
1643 if (json)
1644 json_path = json_object_new_array();
1645
1646 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
1647 json_path);
1648
1649 if (json)
1650 json_object_array_add(json_paths, json_path);
1651
1652 path_cnt++;
1653 }
1654
1655 if (json) {
1656 if (path_cnt)
1657 json_object_object_add(json, "paths", json_paths);
1658
1659 json_object_int_add(json, "numPaths", path_cnt);
1660 } else {
1661 vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
1662 path_cnt);
1663 }
1664 }
1665
1666 /*
1667 * Display EVPN routes for a VNI - vty handler.
1668 * If 'type' is non-zero, only routes matching that type are shown.
1669 * If the vtep_ip is non zero, only routes behind that vtep are shown
1670 */
1671 static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
1672 int type, struct in_addr vtep_ip,
1673 json_object *json)
1674 {
1675 struct bgpevpn *vpn;
1676
1677 /* Locate VNI. */
1678 vpn = bgp_evpn_lookup_vni(bgp, vni);
1679 if (!vpn) {
1680 if (!json)
1681 vty_out(vty, "VNI not found\n");
1682 return;
1683 }
1684
1685 /* Walk this VNI's route table and display appropriate routes. */
1686 show_vni_routes(bgp, vpn, type, vty, vtep_ip, json);
1687 }
1688
1689 /*
1690 * Display BGP EVPN routing table -- for specific RD and MAC and/or
1691 * IP (vty handler). By definition, only matching type-2 route will be
1692 * displayed.
1693 */
1694 static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
1695 struct prefix_rd *prd, struct ethaddr *mac,
1696 struct ipaddr *ip, json_object *json)
1697 {
1698 struct prefix_evpn p;
1699 struct bgp_node *rn;
1700 struct bgp_info *ri;
1701 afi_t afi;
1702 safi_t safi;
1703 u_int32_t path_cnt = 0;
1704 json_object *json_paths = NULL;
1705 char prefix_str[BUFSIZ];
1706
1707 afi = AFI_L2VPN;
1708 safi = SAFI_EVPN;
1709
1710 /* See if route exists. Look for both non-sticky and sticky. */
1711 build_evpn_type2_prefix(&p, mac, ip);
1712 rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
1713 (struct prefix *)&p, prd);
1714 if (!rn || !rn->info) {
1715 if (!json)
1716 vty_out(vty, "%% Network not in table\n");
1717 return;
1718 }
1719
1720 bgp_evpn_route2str((struct prefix_evpn *)&p, prefix_str,
1721 sizeof(prefix_str));
1722
1723 /* Prefix and num paths displayed once per prefix. */
1724 route_vty_out_detail_header(vty, bgp, rn, prd, afi, safi, json);
1725
1726 if (json)
1727 json_paths = json_object_new_array();
1728
1729 /* Display each path for this prefix. */
1730 for (ri = rn->info; ri; ri = ri->next) {
1731 json_object *json_path = NULL;
1732
1733 if (json)
1734 json_path = json_object_new_array();
1735
1736 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
1737 json_path);
1738
1739 if (json)
1740 json_object_array_add(json_paths, json_path);
1741
1742 path_cnt++;
1743 }
1744
1745 if (json && path_cnt) {
1746 if (path_cnt)
1747 json_object_object_add(json, prefix_str, json_paths);
1748 json_object_int_add(json, "numPaths", path_cnt);
1749 } else {
1750 vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
1751 path_cnt);
1752 }
1753 }
1754
1755 /*
1756 * Display BGP EVPN routing table -- for specific RD (vty handler)
1757 * If 'type' is non-zero, only routes matching that type are shown.
1758 */
1759 static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
1760 struct prefix_rd *prd, int type,
1761 json_object *json)
1762 {
1763 struct bgp_node *rd_rn;
1764 struct bgp_table *table;
1765 struct bgp_node *rn;
1766 struct bgp_info *ri;
1767 int rd_header = 1;
1768 afi_t afi;
1769 safi_t safi;
1770 u_int32_t prefix_cnt, path_cnt;
1771 char rd_str[RD_ADDRSTRLEN];
1772 json_object *json_rd = NULL;
1773 int add_rd_to_json = 0;
1774
1775 afi = AFI_L2VPN;
1776 safi = SAFI_EVPN;
1777 prefix_cnt = path_cnt = 0;
1778
1779 prefix_rd2str((struct prefix_rd *)prd, rd_str, sizeof(rd_str));
1780
1781 rd_rn = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)prd);
1782 if (!rd_rn)
1783 return;
1784
1785 table = (struct bgp_table *)rd_rn->info;
1786 if (table == NULL)
1787 return;
1788
1789 if (json) {
1790 json_rd = json_object_new_object();
1791 json_object_string_add(json_rd, "rd", rd_str);
1792 }
1793
1794 /* Display all prefixes with this RD. */
1795 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
1796 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
1797 json_object *json_prefix = NULL;
1798 json_object *json_paths = NULL;
1799 char prefix_str[BUFSIZ];
1800 int add_prefix_to_json = 0;
1801
1802 bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
1803 sizeof(prefix_str));
1804
1805 if (type && evp->prefix.route_type != type)
1806 continue;
1807
1808 if (json)
1809 json_prefix = json_object_new_object();
1810
1811 if (rn->info) {
1812 /* RD header and legend - once overall. */
1813 if (rd_header && !json) {
1814 vty_out(vty,
1815 "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:"
1816 "[MAC]\n");
1817 vty_out(vty,
1818 "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:"
1819 "[OrigIP]\n\n");
1820 rd_header = 0;
1821 }
1822
1823 /* Prefix and num paths displayed once per prefix. */
1824 route_vty_out_detail_header(vty, bgp, rn, prd, afi,
1825 safi, json_prefix);
1826
1827 prefix_cnt++;
1828 }
1829
1830 if (json)
1831 json_paths = json_object_new_array();
1832
1833 /* Display each path for this prefix. */
1834 for (ri = rn->info; ri; ri = ri->next) {
1835 json_object *json_path = NULL;
1836
1837 if (json)
1838 json_path = json_object_new_array();
1839
1840 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
1841 json_path);
1842
1843 if (json)
1844 json_object_array_add(json_paths, json_path);
1845
1846 path_cnt++;
1847 add_prefix_to_json = 1;
1848 add_rd_to_json = 1;
1849 }
1850
1851 if (json && add_prefix_to_json) {
1852 json_object_object_add(json_prefix, "paths",
1853 json_paths);
1854 json_object_object_add(json_rd, prefix_str,
1855 json_prefix);
1856 }
1857 }
1858
1859 if (json && add_rd_to_json)
1860 json_object_object_add(json, rd_str, json_rd);
1861
1862 if (json) {
1863 json_object_int_add(json, "numPrefix", prefix_cnt);
1864 json_object_int_add(json, "numPaths", path_cnt);
1865 } else {
1866 if (prefix_cnt == 0)
1867 vty_out(vty, "No prefixes exist with this RD%s\n",
1868 type ? " (of requested type)" : "");
1869 else
1870 vty_out(vty,
1871 "\nDisplayed %u prefixes (%u paths) with this RD%s\n",
1872 prefix_cnt, path_cnt,
1873 type ? " (of requested type)" : "");
1874 }
1875 }
1876
1877 /*
1878 * Display BGP EVPN routing table - all routes (vty handler).
1879 * If 'type' is non-zero, only routes matching that type are shown.
1880 */
1881 static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
1882 json_object *json)
1883 {
1884 struct bgp_node *rd_rn;
1885 struct bgp_table *table;
1886 struct bgp_node *rn;
1887 struct bgp_info *ri;
1888 int header = 1;
1889 int rd_header;
1890 afi_t afi;
1891 safi_t safi;
1892 u_int32_t prefix_cnt, path_cnt;
1893
1894 afi = AFI_L2VPN;
1895 safi = SAFI_EVPN;
1896 prefix_cnt = path_cnt = 0;
1897
1898 /* EVPN routing table is a 2-level table with the first level being
1899 * the RD.
1900 */
1901 for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn;
1902 rd_rn = bgp_route_next(rd_rn)) {
1903 char rd_str[RD_ADDRSTRLEN];
1904 json_object *json_rd = NULL; /* contains routes for an RD */
1905 int add_rd_to_json = 0;
1906
1907 table = (struct bgp_table *)rd_rn->info;
1908 if (table == NULL)
1909 continue;
1910
1911 prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str,
1912 sizeof(rd_str));
1913
1914 if (json) {
1915 json_rd = json_object_new_object();
1916 json_object_string_add(json_rd, "rd", rd_str);
1917 }
1918
1919 rd_header = 1;
1920
1921 /* Display all prefixes for an RD */
1922 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
1923 json_object *json_prefix =
1924 NULL; /* contains prefix under a RD */
1925 json_object *json_paths =
1926 NULL; /* array of paths under a prefix*/
1927 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
1928 char prefix_str[BUFSIZ];
1929 int add_prefix_to_json = 0;
1930
1931 bgp_evpn_route2str((struct prefix_evpn *)&rn->p,
1932 prefix_str, sizeof(prefix_str));
1933
1934 if (type && evp->prefix.route_type != type)
1935 continue;
1936
1937 if (rn->info) {
1938 /* Overall header/legend displayed once. */
1939 if (header) {
1940 bgp_evpn_show_route_header(vty, bgp,
1941 json);
1942 header = 0;
1943 }
1944
1945 /* RD header - per RD. */
1946 if (rd_header) {
1947 bgp_evpn_show_route_rd_header(
1948 vty, rd_rn, json);
1949 rd_header = 0;
1950 }
1951
1952 prefix_cnt++;
1953 }
1954
1955 if (json) {
1956 json_prefix = json_object_new_object();
1957 json_paths = json_object_new_array();
1958 json_object_string_add(json_prefix, "prefix",
1959 prefix_str);
1960 json_object_int_add(json_prefix, "prefixLen",
1961 rn->p.prefixlen);
1962 }
1963
1964 /* For EVPN, the prefix is displayed for each path (to
1965 * fit in
1966 * with code that already exists).
1967 */
1968 for (ri = rn->info; ri; ri = ri->next) {
1969 json_object *json_path = NULL;
1970 path_cnt++;
1971 add_prefix_to_json = 1;
1972 add_rd_to_json = 1;
1973
1974 if (json)
1975 json_path = json_object_new_array();
1976
1977 route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN,
1978 json_path);
1979
1980 if (json)
1981 json_object_array_add(json_paths,
1982 json_path);
1983 }
1984
1985 if (json && add_prefix_to_json) {
1986 json_object_object_add(json_prefix, "paths",
1987 json_paths);
1988 json_object_object_add(json_rd, prefix_str,
1989 json_prefix);
1990 }
1991 }
1992
1993 if (json && add_rd_to_json)
1994 json_object_object_add(json, rd_str, json_rd);
1995 }
1996
1997 if (json) {
1998 json_object_int_add(json, "numPrefix", prefix_cnt);
1999 json_object_int_add(json, "numPaths", path_cnt);
2000 } else {
2001 if (prefix_cnt == 0) {
2002 vty_out(vty, "No EVPN prefixes %sexist\n",
2003 type ? "(of requested type) " : "");
2004 } else {
2005 vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
2006 prefix_cnt, path_cnt,
2007 type ? " (of requested type)" : "");
2008 }
2009 }
2010 }
2011
2012 /*
2013 * Display specified VNI (vty handler)
2014 */
2015 static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
2016 json_object *json)
2017 {
2018 struct bgpevpn *vpn;
2019
2020 vpn = bgp_evpn_lookup_vni(bgp, vni);
2021 if (!vpn) {
2022 if (json) {
2023 vty_out(vty, "{}\n");
2024 } else {
2025 vty_out(vty, "VNI not found\n");
2026 return;
2027 }
2028 }
2029
2030 display_vni(vty, vpn, json);
2031 }
2032
2033 /*
2034 * Display a VNI (upon user query).
2035 */
2036 static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
2037 json_object *json)
2038 {
2039 u_int32_t num_vnis;
2040 void *args[2];
2041
2042 num_vnis = hashcount(bgp->vnihash);
2043 if (!num_vnis)
2044 return;
2045
2046 if (json) {
2047 json_object_int_add(json, "numVnis", num_vnis);
2048 } else {
2049 vty_out(vty, "Number of VNIs: %u\n", num_vnis);
2050 vty_out(vty, "Flags: * - Kernel\n");
2051 vty_out(vty, " %-10s %-15s %-21s %-25s %-25s\n", "VNI",
2052 "Orig IP", "RD", "Import RT", "Export RT");
2053 }
2054
2055 args[0] = vty;
2056 args[1] = json;
2057 hash_iterate(bgp->vnihash,
2058 (void (*)(struct hash_backet *, void *))show_vni_entry,
2059 args);
2060 }
2061
2062 /*
2063 * evpn - enable advertisement of default g/w
2064 */
2065 static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn)
2066 {
2067 if (!vpn) {
2068 if (bgp->advertise_gw_macip)
2069 return;
2070
2071 bgp->advertise_gw_macip = 1;
2072 bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
2073 } else {
2074 if (vpn->advertise_gw_macip)
2075 return;
2076
2077 vpn->advertise_gw_macip = 1;
2078 bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
2079 vpn->vni);
2080 }
2081 return;
2082 }
2083
2084 /*
2085 * evpn - disable advertisement of default g/w
2086 */
2087 static void evpn_unset_advertise_default_gw(struct bgp *bgp,
2088 struct bgpevpn *vpn)
2089 {
2090 if (!vpn) {
2091 if (!bgp->advertise_gw_macip)
2092 return;
2093
2094 bgp->advertise_gw_macip = 0;
2095 bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
2096 } else {
2097 if (!vpn->advertise_gw_macip)
2098 return;
2099
2100 vpn->advertise_gw_macip = 0;
2101 bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
2102 vpn->vni);
2103 }
2104 return;
2105 }
2106
2107 /*
2108 * EVPN (VNI advertisement) enabled. Register with zebra.
2109 */
2110 static void evpn_set_advertise_all_vni(struct bgp *bgp)
2111 {
2112 bgp->advertise_all_vni = 1;
2113 bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
2114 }
2115
2116 /*
2117 * EVPN (VNI advertisement) disabled. De-register with zebra. Cleanup VNI
2118 * cache, EVPN routes (delete and withdraw from peers).
2119 */
2120 static void evpn_unset_advertise_all_vni(struct bgp *bgp)
2121 {
2122 bgp->advertise_all_vni = 0;
2123 bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
2124 bgp_evpn_cleanup_on_disable(bgp);
2125 }
2126 #endif /* HAVE_CUMULUS */
2127
2128 static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write)
2129 {
2130 char buf1[INET6_ADDRSTRLEN];
2131 afi_t afi = AFI_L2VPN;
2132 safi_t safi = SAFI_EVPN;
2133 char *ecom_str;
2134 struct listnode *node, *nnode;
2135 struct ecommunity *ecom;
2136
2137 if (is_vni_configured(vpn)) {
2138 bgp_config_write_family_header(vty, afi, safi, write);
2139 vty_out(vty, " vni %d\n", vpn->vni);
2140 if (is_rd_configured(vpn))
2141 vty_out(vty, " rd %s\n",
2142 prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
2143
2144 if (is_import_rt_configured(vpn)) {
2145 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode,
2146 ecom)) {
2147 ecom_str = ecommunity_ecom2str(
2148 ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
2149 vty_out(vty, " route-target import %s\n",
2150 ecom_str);
2151 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
2152 }
2153 }
2154
2155 if (is_export_rt_configured(vpn)) {
2156 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode,
2157 ecom)) {
2158 ecom_str = ecommunity_ecom2str(
2159 ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
2160 vty_out(vty, " route-target export %s\n",
2161 ecom_str);
2162 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
2163 }
2164 }
2165
2166 if (vpn->advertise_gw_macip)
2167 vty_out(vty, " advertise-default-gw\n");
2168
2169 vty_out(vty, " exit-vni\n");
2170 }
2171 }
2172
2173 static void write_vni_config_for_entry(struct hash_backet *backet,
2174 struct evpn_config_write *cfg)
2175 {
2176 struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
2177 write_vni_config(cfg->vty, vpn, &cfg->write);
2178 }
2179
2180 #if defined(HAVE_CUMULUS)
2181 DEFUN (bgp_evpn_advertise_default_gw_vni,
2182 bgp_evpn_advertise_default_gw_vni_cmd,
2183 "advertise-default-gw",
2184 "Advertise defualt g/w mac-ip routes in EVPN for a VNI\n")
2185 {
2186 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2187 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
2188
2189 if (!bgp)
2190 return CMD_WARNING;
2191
2192 if (!vpn)
2193 return CMD_WARNING;
2194
2195 evpn_set_advertise_default_gw(bgp, vpn);
2196
2197 return CMD_SUCCESS;
2198 }
2199
2200 DEFUN (no_bgp_evpn_advertise_default_vni_gw,
2201 no_bgp_evpn_advertise_default_gw_vni_cmd,
2202 "no advertise-default-gw",
2203 NO_STR
2204 "Withdraw default g/w mac-ip routes from EVPN for a VNI\n")
2205 {
2206 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2207 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
2208
2209 if (!bgp)
2210 return CMD_WARNING;
2211
2212 if (!vpn)
2213 return CMD_WARNING;
2214
2215 evpn_unset_advertise_default_gw(bgp, vpn);
2216
2217 return CMD_SUCCESS;
2218 }
2219
2220
2221 DEFUN (bgp_evpn_advertise_default_gw,
2222 bgp_evpn_advertise_default_gw_cmd,
2223 "advertise-default-gw",
2224 "Advertise All defualt g/w mac-ip routes in EVPN\n")
2225 {
2226 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2227
2228 if (!bgp)
2229 return CMD_WARNING;
2230
2231 evpn_set_advertise_default_gw(bgp, NULL);
2232
2233 return CMD_SUCCESS;
2234 }
2235
2236 DEFUN (no_bgp_evpn_advertise_default_gw,
2237 no_bgp_evpn_advertise_default_gw_cmd,
2238 "no advertise-default-gw",
2239 NO_STR
2240 "Withdraw All default g/w mac-ip routes from EVPN\n")
2241 {
2242 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2243
2244 if (!bgp)
2245 return CMD_WARNING;
2246
2247 evpn_unset_advertise_default_gw(bgp, NULL);
2248
2249 return CMD_SUCCESS;
2250 }
2251
2252 DEFUN (bgp_evpn_advertise_all_vni,
2253 bgp_evpn_advertise_all_vni_cmd,
2254 "advertise-all-vni",
2255 "Advertise All local VNIs\n")
2256 {
2257 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2258
2259 if (!bgp)
2260 return CMD_WARNING;
2261 evpn_set_advertise_all_vni(bgp);
2262 return CMD_SUCCESS;
2263 }
2264
2265 DEFUN (no_bgp_evpn_advertise_all_vni,
2266 no_bgp_evpn_advertise_all_vni_cmd,
2267 "no advertise-all-vni",
2268 NO_STR
2269 "Advertise All local VNIs\n")
2270 {
2271 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2272
2273 if (!bgp)
2274 return CMD_WARNING;
2275 evpn_unset_advertise_all_vni(bgp);
2276 return CMD_SUCCESS;
2277 }
2278
2279 /*
2280 * Display VNI information - for all or a specific VNI
2281 */
2282 DEFUN(show_bgp_l2vpn_evpn_vni,
2283 show_bgp_l2vpn_evpn_vni_cmd,
2284 "show bgp l2vpn evpn vni [(1-16777215)] [json]",
2285 SHOW_STR
2286 BGP_STR
2287 L2VPN_HELP_STR
2288 EVPN_HELP_STR
2289 "Show VNI\n"
2290 "VNI number\n"
2291 JSON_STR)
2292 {
2293 struct bgp *bgp;
2294 vni_t vni;
2295 int idx = 0;
2296 u_char uj = 0;
2297 json_object *json = NULL;
2298
2299 uj = use_json(argc, argv);
2300
2301 bgp = bgp_get_default();
2302 if (!bgp)
2303 return CMD_WARNING;
2304
2305 if (!argv_find(argv, argc, "evpn", &idx))
2306 return CMD_WARNING;
2307
2308 if (uj)
2309 json = json_object_new_object();
2310
2311 if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
2312 if (uj) {
2313 json_object_string_add(json, "advertiseGatewayMacip",
2314 bgp->advertise_gw_macip
2315 ? "Enabled"
2316 : "Disabled");
2317 json_object_string_add(json, "advertiseAllVnis",
2318 bgp->advertise_all_vni
2319 ? "Enabled"
2320 : "Disabled");
2321 } else {
2322 vty_out(vty, "Advertise Gateway Macip: %s\n",
2323 bgp->advertise_gw_macip ? "Enabled"
2324 : "Disabled");
2325
2326 /* Display all VNIs */
2327 vty_out(vty, "Advertise All VNI flag: %s\n",
2328 bgp->advertise_all_vni ? "Enabled"
2329 : "Disabled");
2330 }
2331
2332 evpn_show_all_vnis(vty, bgp, json);
2333 } else {
2334 int vni_idx = 0;
2335
2336 if (!argv_find(argv, argc, "vni", &vni_idx))
2337 return CMD_WARNING;
2338
2339 /* Display specific VNI */
2340 vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
2341 evpn_show_vni(vty, bgp, vni, json);
2342 }
2343
2344 if (uj) {
2345 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2346 json, JSON_C_TO_STRING_PRETTY));
2347 json_object_free(json);
2348 }
2349
2350 return CMD_SUCCESS;
2351 }
2352
2353 /*
2354 * Display EVPN neighbor summary.
2355 */
2356 DEFUN(show_bgp_l2vpn_evpn_summary,
2357 show_bgp_l2vpn_evpn_summary_cmd,
2358 "show bgp l2vpn evpn summary [json]",
2359 SHOW_STR
2360 BGP_STR
2361 L2VPN_HELP_STR
2362 EVPN_HELP_STR
2363 "Summary of BGP neighbor status\n"
2364 JSON_STR)
2365 {
2366 u_char uj = use_json(argc, argv);
2367 return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj);
2368 }
2369
2370 /*
2371 * Display global EVPN routing table.
2372 */
2373 DEFUN(show_bgp_l2vpn_evpn_route, show_bgp_l2vpn_evpn_route_cmd,
2374 "show bgp l2vpn evpn route [type <macip|multicast>] [json]",
2375 SHOW_STR
2376 BGP_STR
2377 L2VPN_HELP_STR
2378 EVPN_HELP_STR
2379 "EVPN route information\n"
2380 "Specify Route type\n"
2381 "MAC-IP (Type-2) route\n"
2382 "Multicast (Type-3) route\n"
2383 JSON_STR)
2384 {
2385 struct bgp *bgp;
2386 int type_idx;
2387 int type = 0;
2388 u_char uj = 0;
2389 json_object *json = NULL;
2390
2391 uj = use_json(argc, argv);
2392
2393 bgp = bgp_get_default();
2394 if (!bgp)
2395 return CMD_WARNING;
2396
2397 if (uj)
2398 json = json_object_new_object();
2399
2400 /* get the type */
2401 if (argv_find(argv, argc, "type", &type_idx)) {
2402 /* Specific type is requested */
2403 if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
2404 type = BGP_EVPN_MAC_IP_ROUTE;
2405 else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
2406 type = BGP_EVPN_IMET_ROUTE;
2407 else
2408 return CMD_WARNING;
2409 }
2410
2411 evpn_show_all_routes(vty, bgp, type, json);
2412
2413 if (uj) {
2414 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2415 json, JSON_C_TO_STRING_PRETTY));
2416 json_object_free(json);
2417 }
2418
2419 return CMD_SUCCESS;
2420 }
2421
2422 /*
2423 * Display global EVPN routing table for specific RD.
2424 */
2425 DEFUN(show_bgp_l2vpn_evpn_route_rd, show_bgp_l2vpn_evpn_route_rd_cmd,
2426 "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>] [json]",
2427 SHOW_STR
2428 BGP_STR
2429 L2VPN_HELP_STR
2430 EVPN_HELP_STR
2431 "EVPN route information\n"
2432 "Route Distinguisher\n"
2433 "ASN:XX or A.B.C.D:XX\n"
2434 "Specify Route type\n"
2435 "MAC-IP (Type-2) route\n"
2436 "Multicast (Type-3) route\n"
2437 JSON_STR)
2438 {
2439 struct bgp *bgp;
2440 int ret;
2441 struct prefix_rd prd;
2442 int type = 0;
2443 int rd_idx = 0;
2444 int type_idx = 0;
2445 int uj = 0;
2446 json_object *json = NULL;
2447
2448 bgp = bgp_get_default();
2449 if (!bgp)
2450 return CMD_WARNING;
2451
2452 /* check if we need json output */
2453 uj = use_json(argc, argv);
2454 if (uj)
2455 json = json_object_new_object();
2456
2457 /* get the RD */
2458 if (argv_find(argv, argc, "rd", &rd_idx)) {
2459 ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd);
2460
2461 if (!ret) {
2462 vty_out(vty, "%% Malformed Route Distinguisher\n");
2463 return CMD_WARNING;
2464 }
2465 }
2466
2467 /* get the type */
2468 if (argv_find(argv, argc, "type", &type_idx)) {
2469 /* Specific type is requested */
2470 if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
2471 type = BGP_EVPN_MAC_IP_ROUTE;
2472 else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
2473 type = BGP_EVPN_IMET_ROUTE;
2474 else
2475 return CMD_WARNING;
2476 }
2477
2478 evpn_show_route_rd(vty, bgp, &prd, type, json);
2479
2480 if (uj) {
2481 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2482 json, JSON_C_TO_STRING_PRETTY));
2483 json_object_free(json);
2484 }
2485
2486 return CMD_SUCCESS;
2487 }
2488
2489 /*
2490 * Display global EVPN routing table for specific RD and MACIP.
2491 */
2492 DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
2493 show_bgp_l2vpn_evpn_route_rd_macip_cmd,
2494 "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD] [json]",
2495 SHOW_STR
2496 BGP_STR
2497 L2VPN_HELP_STR
2498 EVPN_HELP_STR
2499 "EVPN route information\n"
2500 "Route Distinguisher\n"
2501 "ASN:XX or A.B.C.D:XX\n"
2502 "MAC\n"
2503 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
2504 "IP\n"
2505 "IP address (IPv4 or IPv6)\n"
2506 JSON_STR)
2507 {
2508 struct bgp *bgp;
2509 int ret;
2510 struct prefix_rd prd;
2511 struct ethaddr mac;
2512 struct ipaddr ip;
2513 int rd_idx = 0;
2514 int mac_idx = 0;
2515 int ip_idx = 0;
2516 int uj = 0;
2517 json_object *json = NULL;
2518
2519 memset(&mac, 0, sizeof(struct ethaddr));
2520 memset(&ip, 0, sizeof(struct ipaddr));
2521
2522 bgp = bgp_get_default();
2523 if (!bgp)
2524 return CMD_WARNING;
2525
2526 /* check if we need json output */
2527 uj = use_json(argc, argv);
2528 if (uj)
2529 json = json_object_new_object();
2530
2531 /* get the prd */
2532 if (argv_find(argv, argc, "rd", &rd_idx)) {
2533 ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd);
2534 if (!ret) {
2535 vty_out(vty, "%% Malformed Route Distinguisher\n");
2536 return CMD_WARNING;
2537 }
2538 }
2539
2540 /* get the mac */
2541 if (argv_find(argv, argc, "mac", &mac_idx)) {
2542 if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) {
2543 vty_out(vty, "%% Malformed MAC address\n");
2544 return CMD_WARNING;
2545 }
2546 }
2547
2548 /* get the ip if specified */
2549 if (argv_find(argv, argc, "ip", &ip_idx)) {
2550 if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) {
2551 vty_out(vty, "%% Malformed IP address\n");
2552 return CMD_WARNING;
2553 }
2554 }
2555
2556 evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json);
2557
2558 if (uj) {
2559 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2560 json, JSON_C_TO_STRING_PRETTY));
2561 json_object_free(json);
2562 }
2563
2564 return CMD_SUCCESS;
2565 }
2566
2567 /*
2568 * Display per-VNI EVPN routing table.
2569 */
2570 DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd,
2571 "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>] [json]",
2572 SHOW_STR
2573 BGP_STR
2574 L2VPN_HELP_STR
2575 EVPN_HELP_STR
2576 "EVPN route information\n"
2577 "VXLAN Network Identifier\n"
2578 "VNI number\n"
2579 "Specify Route type\n"
2580 "MAC-IP (Type-2) route\n"
2581 "Multicast (Type-3) route\n"
2582 "Remote VTEP\n"
2583 "Remote VTEP IP address\n"
2584 JSON_STR)
2585 {
2586 vni_t vni;
2587 struct bgp *bgp;
2588 struct in_addr vtep_ip;
2589 int type = 0;
2590 int idx = 0;
2591 int uj = 0;
2592 json_object *json = NULL;
2593
2594 bgp = bgp_get_default();
2595 if (!bgp)
2596 return CMD_WARNING;
2597
2598 /* check if we need json output */
2599 uj = use_json(argc, argv);
2600 if (uj)
2601 json = json_object_new_object();
2602
2603 if (!argv_find(argv, argc, "evpn", &idx))
2604 return CMD_WARNING;
2605
2606 vtep_ip.s_addr = 0;
2607
2608 vni = strtoul(argv[idx + 3]->arg, NULL, 10);
2609
2610 if ((!uj && ((argc == (idx + 1 + 5)) && argv[idx + 4]->arg))
2611 || (uj && ((argc == (idx + 1 + 6)) && argv[idx + 4]->arg))) {
2612 if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) {
2613 if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0)
2614 type = BGP_EVPN_MAC_IP_ROUTE;
2615 else if (strncmp(argv[idx + 5]->arg, "mu", 2) == 0)
2616 type = BGP_EVPN_IMET_ROUTE;
2617 else
2618 return CMD_WARNING;
2619 } else if (strncmp(argv[idx + 4]->arg, "vtep", 4) == 0) {
2620 if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
2621 vty_out(vty, "%% Malformed VTEP IP address\n");
2622 return CMD_WARNING;
2623 }
2624 } else
2625 return CMD_WARNING;
2626 }
2627
2628 evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json);
2629
2630 if (uj) {
2631 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2632 json, JSON_C_TO_STRING_PRETTY));
2633 json_object_free(json);
2634 }
2635
2636 return CMD_SUCCESS;
2637 }
2638
2639 /*
2640 * Display per-VNI EVPN routing table for specific MACIP.
2641 */
2642 DEFUN(show_bgp_l2vpn_evpn_route_vni_macip,
2643 show_bgp_l2vpn_evpn_route_vni_macip_cmd,
2644 "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD] [json]",
2645 SHOW_STR
2646 BGP_STR
2647 L2VPN_HELP_STR
2648 EVPN_HELP_STR
2649 "EVPN route information\n"
2650 "VXLAN Network Identifier\n"
2651 "VNI number\n"
2652 "MAC\n"
2653 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
2654 "IP\n"
2655 "IP address (IPv4 or IPv6)\n"
2656 JSON_STR)
2657 {
2658 vni_t vni;
2659 struct bgp *bgp;
2660 struct ethaddr mac;
2661 struct ipaddr ip;
2662 int idx = 0;
2663 int uj = 0;
2664 json_object *json = NULL;
2665
2666 bgp = bgp_get_default();
2667 if (!bgp)
2668 return CMD_WARNING;
2669
2670 /* check if we need json output */
2671 uj = use_json(argc, argv);
2672 if (uj)
2673 json = json_object_new_object();
2674
2675 if (!argv_find(argv, argc, "evpn", &idx))
2676 return CMD_WARNING;
2677
2678 /* get the VNI */
2679 vni = strtoul(argv[idx + 3]->arg, NULL, 10);
2680
2681 /* get the mac */
2682 if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
2683 vty_out(vty, "%% Malformed MAC address\n");
2684 return CMD_WARNING;
2685 }
2686
2687 /* get the ip */
2688 memset(&ip, 0, sizeof(ip));
2689 if ((!uj && ((argc == (idx + 1 + 7)) && argv[idx + 7]->arg != NULL))
2690 || (uj
2691 && ((argc == (idx + 1 + 8)) && argv[idx + 7]->arg != NULL))) {
2692 if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) {
2693 vty_out(vty, "%% Malformed IP address\n");
2694 return CMD_WARNING;
2695 }
2696 }
2697
2698 evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip, json);
2699
2700 if (uj) {
2701 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2702 json, JSON_C_TO_STRING_PRETTY));
2703 json_object_free(json);
2704 }
2705
2706 return CMD_SUCCESS;
2707 }
2708
2709 /*
2710 * Display per-VNI EVPN routing table for specific multicast IP (remote VTEP).
2711 */
2712 DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast,
2713 show_bgp_l2vpn_evpn_route_vni_multicast_cmd,
2714 "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D [json]",
2715 SHOW_STR
2716 BGP_STR
2717 L2VPN_HELP_STR
2718 EVPN_HELP_STR
2719 "EVPN route information\n"
2720 "VXLAN Network Identifier\n"
2721 "VNI number\n"
2722 "Multicast (Type-3) route\n"
2723 "Originating Router IP address\n"
2724 JSON_STR)
2725 {
2726 vni_t vni;
2727 struct bgp *bgp;
2728 int ret;
2729 struct in_addr orig_ip;
2730 int idx = 0;
2731 int uj = 0;
2732 json_object *json = NULL;
2733
2734 bgp = bgp_get_default();
2735 if (!bgp)
2736 return CMD_WARNING;
2737
2738 /* check if we need json output */
2739 uj = use_json(argc, argv);
2740 if (uj)
2741 json = json_object_new_object();
2742
2743 if (!argv_find(argv, argc, "evpn", &idx))
2744 return CMD_WARNING;
2745
2746 /* get the VNI */
2747 vni = strtoul(argv[idx + 3]->arg, NULL, 10);
2748
2749 /* get the ip */
2750 ret = inet_aton(argv[idx + 5]->arg, &orig_ip);
2751 if (!ret) {
2752 vty_out(vty, "%% Malformed Originating Router IP address\n");
2753 return CMD_WARNING;
2754 }
2755
2756 evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip, json);
2757
2758 if (uj) {
2759 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2760 json, JSON_C_TO_STRING_PRETTY));
2761 json_object_free(json);
2762 }
2763
2764 return CMD_SUCCESS;
2765 }
2766
2767 /*
2768 * Display per-VNI EVPN routing table - for all VNIs.
2769 */
2770 DEFUN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_l2vpn_evpn_route_vni_all_cmd,
2771 "show bgp l2vpn evpn route vni all [vtep A.B.C.D] [json]",
2772 SHOW_STR
2773 BGP_STR
2774 L2VPN_HELP_STR
2775 EVPN_HELP_STR
2776 "EVPN route information\n"
2777 "VXLAN Network Identifier\n"
2778 "All VNIs\n"
2779 "Remote VTEP\n"
2780 "Remote VTEP IP address\n"
2781 JSON_STR)
2782 {
2783 struct bgp *bgp;
2784 struct in_addr vtep_ip;
2785 int idx = 0;
2786 int uj = 0;
2787 json_object *json = NULL;
2788
2789 bgp = bgp_get_default();
2790 if (!bgp)
2791 return CMD_WARNING;
2792
2793 /* check if we need json output */
2794 uj = use_json(argc, argv);
2795 if (uj)
2796 json = json_object_new_object();
2797
2798 if (!argv_find(argv, argc, "evpn", &idx))
2799 return CMD_WARNING;
2800
2801 vtep_ip.s_addr = 0;
2802 if ((!uj && (argc == (idx + 1 + 5) && argv[idx + 5]->arg))
2803 || (uj && (argc == (idx + 1 + 6) && argv[idx + 5]->arg))) {
2804 if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
2805 vty_out(vty, "%% Malformed VTEP IP address\n");
2806 return CMD_WARNING;
2807 }
2808 }
2809
2810 evpn_show_routes_vni_all(vty, bgp, vtep_ip, json);
2811
2812 if (uj) {
2813 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2814 json, JSON_C_TO_STRING_PRETTY));
2815 json_object_free(json);
2816 }
2817
2818 return CMD_SUCCESS;
2819 }
2820
2821 /*
2822 * Display EVPN import route-target hash table
2823 */
2824 DEFUN(show_bgp_l2vpn_evpn_import_rt, show_bgp_l2vpn_evpn_import_rt_cmd,
2825 "show bgp l2vpn evpn import-rt [json]",
2826 SHOW_STR
2827 BGP_STR
2828 L2VPN_HELP_STR
2829 EVPN_HELP_STR
2830 "Show import route target\n"
2831 JSON_STR)
2832 {
2833 struct bgp *bgp;
2834 u_char uj = 0;
2835 json_object *json = NULL;
2836
2837 bgp = bgp_get_default();
2838 if (!bgp)
2839 return CMD_WARNING;
2840
2841 uj = use_json(argc, argv);
2842 if (uj)
2843 json = json_object_new_object();
2844
2845 evpn_show_import_rts(vty, bgp, json);
2846
2847 if (uj) {
2848 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2849 json, JSON_C_TO_STRING_PRETTY));
2850 json_object_free(json);
2851 }
2852
2853 return CMD_SUCCESS;
2854 }
2855
2856 #if defined(HAVE_CUMULUS)
2857 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd,
2858 "show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR
2859 "Show VNI\n"
2860 "VNI number\n")
2861
2862 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd,
2863 "show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR
2864 "Summary of BGP neighbor status\n"
2865 JSON_STR)
2866
2867 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd,
2868 "show bgp evpn route [type <macip|multicast>]",
2869 SHOW_STR BGP_STR EVPN_HELP_STR
2870 "EVPN route information\n"
2871 "Specify Route type\n"
2872 "MAC-IP (Type-2) route\n"
2873 "Multicast (Type-3) route\n")
2874
2875 ALIAS_HIDDEN(
2876 show_bgp_l2vpn_evpn_route_rd, show_bgp_evpn_route_rd_cmd,
2877 "show bgp evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
2878 SHOW_STR BGP_STR EVPN_HELP_STR
2879 "EVPN route information\n"
2880 "Route Distinguisher\n"
2881 "ASN:XX or A.B.C.D:XX\n"
2882 "Specify Route type\n"
2883 "MAC-IP (Type-2) route\n"
2884 "Multicast (Type-3) route\n")
2885
2886 ALIAS_HIDDEN(
2887 show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_evpn_route_rd_macip_cmd,
2888 "show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
2889 SHOW_STR BGP_STR EVPN_HELP_STR
2890 "EVPN route information\n"
2891 "Route Distinguisher\n"
2892 "ASN:XX or A.B.C.D:XX\n"
2893 "MAC\n"
2894 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
2895 "IP\n"
2896 "IP address (IPv4 or IPv6)\n")
2897
2898 ALIAS_HIDDEN(
2899 show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd,
2900 "show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
2901 SHOW_STR BGP_STR EVPN_HELP_STR
2902 "EVPN route information\n"
2903 "VXLAN Network Identifier\n"
2904 "VNI number\n"
2905 "Specify Route type\n"
2906 "MAC-IP (Type-2) route\n"
2907 "Multicast (Type-3) route\n"
2908 "Remote VTEP\n"
2909 "Remote VTEP IP address\n")
2910
2911 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip,
2912 show_bgp_evpn_route_vni_macip_cmd,
2913 "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]",
2914 SHOW_STR BGP_STR EVPN_HELP_STR
2915 "EVPN route information\n"
2916 "VXLAN Network Identifier\n"
2917 "VNI number\n"
2918 "MAC\n"
2919 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
2920 "IP\n"
2921 "IP address (IPv4 or IPv6)\n")
2922
2923 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast,
2924 show_bgp_evpn_route_vni_multicast_cmd,
2925 "show bgp evpn route vni (1-16777215) multicast A.B.C.D",
2926 SHOW_STR BGP_STR EVPN_HELP_STR
2927 "EVPN route information\n"
2928 "VXLAN Network Identifier\n"
2929 "VNI number\n"
2930 "Multicast (Type-3) route\n"
2931 "Originating Router IP address\n")
2932
2933 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
2934 "show bgp evpn route vni all [vtep A.B.C.D]",
2935 SHOW_STR BGP_STR EVPN_HELP_STR
2936 "EVPN route information\n"
2937 "VXLAN Network Identifier\n"
2938 "All VNIs\n"
2939 "Remote VTEP\n"
2940 "Remote VTEP IP address\n")
2941
2942 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd,
2943 "show bgp evpn import-rt",
2944 SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n")
2945 #endif
2946
2947 DEFUN_NOSH (bgp_evpn_vni,
2948 bgp_evpn_vni_cmd,
2949 "vni (1-16777215)",
2950 "VXLAN Network Identifier\n"
2951 "VNI number\n")
2952 {
2953 vni_t vni;
2954 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2955 struct bgpevpn *vpn;
2956
2957 if (!bgp)
2958 return CMD_WARNING;
2959
2960 vni = strtoul(argv[1]->arg, NULL, 10);
2961
2962 /* Create VNI, or mark as configured. */
2963 vpn = evpn_create_update_vni(bgp, vni);
2964 if (!vpn) {
2965 vty_out(vty, "%% Failed to create VNI \n");
2966 return CMD_WARNING;
2967 }
2968
2969 VTY_PUSH_CONTEXT_SUB(BGP_EVPN_VNI_NODE, vpn);
2970 return CMD_SUCCESS;
2971 }
2972
2973 DEFUN (no_bgp_evpn_vni,
2974 no_bgp_evpn_vni_cmd,
2975 "no vni (1-16777215)",
2976 NO_STR
2977 "VXLAN Network Identifier\n"
2978 "VNI number\n")
2979 {
2980 vni_t vni;
2981 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2982 struct bgpevpn *vpn;
2983
2984 if (!bgp)
2985 return CMD_WARNING;
2986
2987 vni = strtoul(argv[2]->arg, NULL, 10);
2988
2989 /* Check if we should disallow. */
2990 vpn = bgp_evpn_lookup_vni(bgp, vni);
2991 if (!vpn) {
2992 vty_out(vty, "%% Specified VNI does not exist\n");
2993 return CMD_WARNING;
2994 }
2995 if (!is_vni_configured(vpn)) {
2996 vty_out(vty, "%% Specified VNI is not configured\n");
2997 return CMD_WARNING;
2998 }
2999
3000 evpn_delete_vni(bgp, vpn);
3001 return CMD_SUCCESS;
3002 }
3003
3004 DEFUN_NOSH (exit_vni,
3005 exit_vni_cmd,
3006 "exit-vni",
3007 "Exit from VNI mode\n")
3008 {
3009 if (vty->node == BGP_EVPN_VNI_NODE)
3010 vty->node = BGP_EVPN_NODE;
3011 return CMD_SUCCESS;
3012 }
3013
3014 DEFUN (bgp_evpn_vni_rd,
3015 bgp_evpn_vni_rd_cmd,
3016 "rd ASN:nn_or_IP-address:nn",
3017 "Route Distinguisher\n"
3018 "ASN:XX or A.B.C.D:XX\n")
3019 {
3020 struct prefix_rd prd;
3021 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
3022 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
3023 int ret;
3024
3025 if (!bgp || !vpn)
3026 return CMD_WARNING;
3027
3028 ret = str2prefix_rd(argv[1]->arg, &prd);
3029 if (!ret) {
3030 vty_out(vty, "%% Malformed Route Distinguisher\n");
3031 return CMD_WARNING;
3032 }
3033
3034 /* If same as existing value, there is nothing more to do. */
3035 if (bgp_evpn_rd_matches_existing(vpn, &prd))
3036 return CMD_SUCCESS;
3037
3038 /* Configure or update the RD. */
3039 evpn_configure_rd(bgp, vpn, &prd);
3040 return CMD_SUCCESS;
3041 }
3042
3043 DEFUN (no_bgp_evpn_vni_rd,
3044 no_bgp_evpn_vni_rd_cmd,
3045 "no rd ASN:nn_or_IP-address:nn",
3046 NO_STR
3047 "Route Distinguisher\n"
3048 "ASN:XX or A.B.C.D:XX\n")
3049 {
3050 struct prefix_rd prd;
3051 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
3052 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
3053 int ret;
3054
3055 if (!bgp || !vpn)
3056 return CMD_WARNING;
3057
3058 ret = str2prefix_rd(argv[2]->arg, &prd);
3059 if (!ret) {
3060 vty_out(vty, "%% Malformed Route Distinguisher\n");
3061 return CMD_WARNING;
3062 }
3063
3064 /* Check if we should disallow. */
3065 if (!is_rd_configured(vpn)) {
3066 vty_out(vty, "%% RD is not configured for this VNI\n");
3067 return CMD_WARNING;
3068 }
3069
3070 if (!bgp_evpn_rd_matches_existing(vpn, &prd)) {
3071 vty_out(vty,
3072 "%% RD specified does not match configuration for this VNI\n");
3073 return CMD_WARNING;
3074 }
3075
3076 evpn_unconfigure_rd(bgp, vpn);
3077 return CMD_SUCCESS;
3078 }
3079
3080 DEFUN (no_bgp_evpn_vni_rd_without_val,
3081 no_bgp_evpn_vni_rd_without_val_cmd,
3082 "no rd",
3083 NO_STR
3084 "Route Distinguisher\n")
3085 {
3086 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
3087 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
3088
3089 if (!bgp || !vpn)
3090 return CMD_WARNING;
3091
3092 /* Check if we should disallow. */
3093 if (!is_rd_configured(vpn)) {
3094 vty_out(vty, "%% RD is not configured for this VNI\n");
3095 return CMD_WARNING;
3096 }
3097
3098 evpn_unconfigure_rd(bgp, vpn);
3099 return CMD_SUCCESS;
3100 }
3101
3102 /*
3103 * Loop over all extended-communities in the route-target list rtl and
3104 * return 1 if we find ecomtarget
3105 */
3106 static int bgp_evpn_rt_matches_existing(struct list *rtl,
3107 struct ecommunity *ecomtarget)
3108 {
3109 struct listnode *node, *nnode;
3110 struct ecommunity *ecom;
3111
3112 for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
3113 if (ecommunity_match(ecom, ecomtarget))
3114 return 1;
3115 }
3116
3117 return 0;
3118 }
3119
3120
3121 DEFUN (bgp_evpn_vni_rt,
3122 bgp_evpn_vni_rt_cmd,
3123 "route-target <both|import|export> RT",
3124 "Route Target\n"
3125 "import and export\n"
3126 "import\n"
3127 "export\n"
3128 "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
3129 {
3130 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
3131 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
3132 int rt_type;
3133 struct ecommunity *ecomadd = NULL;
3134
3135 if (!bgp || !vpn)
3136 return CMD_WARNING;
3137
3138 if (!strcmp(argv[1]->arg, "import"))
3139 rt_type = RT_TYPE_IMPORT;
3140 else if (!strcmp(argv[1]->arg, "export"))
3141 rt_type = RT_TYPE_EXPORT;
3142 else if (!strcmp(argv[1]->arg, "both"))
3143 rt_type = RT_TYPE_BOTH;
3144 else {
3145 vty_out(vty, "%% Invalid Route Target type\n");
3146 return CMD_WARNING;
3147 }
3148
3149 /* Add/update the import route-target */
3150 if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
3151 ecomadd = ecommunity_str2com(argv[2]->arg,
3152 ECOMMUNITY_ROUTE_TARGET, 0);
3153 if (!ecomadd) {
3154 vty_out(vty, "%% Malformed Route Target list\n");
3155 return CMD_WARNING;
3156 }
3157 ecommunity_str(ecomadd);
3158
3159 /* Do nothing if we already have this import route-target */
3160 if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd))
3161 evpn_configure_import_rt(bgp, vpn, ecomadd);
3162 }
3163
3164 /* Add/update the export route-target */
3165 if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
3166 ecomadd = ecommunity_str2com(argv[2]->arg,
3167 ECOMMUNITY_ROUTE_TARGET, 0);
3168 if (!ecomadd) {
3169 vty_out(vty, "%% Malformed Route Target list\n");
3170 return CMD_WARNING;
3171 }
3172 ecommunity_str(ecomadd);
3173
3174 /* Do nothing if we already have this export route-target */
3175 if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd))
3176 evpn_configure_export_rt(bgp, vpn, ecomadd);
3177 }
3178
3179 return CMD_SUCCESS;
3180 }
3181
3182 DEFUN (no_bgp_evpn_vni_rt,
3183 no_bgp_evpn_vni_rt_cmd,
3184 "no route-target <both|import|export> RT",
3185 NO_STR
3186 "Route Target\n"
3187 "import and export\n"
3188 "import\n"
3189 "export\n"
3190 "ASN:XX or A.B.C.D:XX\n")
3191 {
3192 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
3193 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
3194 int rt_type, found_ecomdel;
3195 struct ecommunity *ecomdel = NULL;
3196
3197 if (!bgp || !vpn)
3198 return CMD_WARNING;
3199
3200 if (!strcmp(argv[2]->arg, "import"))
3201 rt_type = RT_TYPE_IMPORT;
3202 else if (!strcmp(argv[2]->arg, "export"))
3203 rt_type = RT_TYPE_EXPORT;
3204 else if (!strcmp(argv[2]->arg, "both"))
3205 rt_type = RT_TYPE_BOTH;
3206 else {
3207 vty_out(vty, "%% Invalid Route Target type\n");
3208 return CMD_WARNING;
3209 }
3210
3211 /* The user did "no route-target import", check to see if there are any
3212 * import route-targets configured. */
3213 if (rt_type == RT_TYPE_IMPORT) {
3214 if (!is_import_rt_configured(vpn)) {
3215 vty_out(vty,
3216 "%% Import RT is not configured for this VNI\n");
3217 return CMD_WARNING;
3218 }
3219 } else if (rt_type == RT_TYPE_EXPORT) {
3220 if (!is_export_rt_configured(vpn)) {
3221 vty_out(vty,
3222 "%% Export RT is not configured for this VNI\n");
3223 return CMD_WARNING;
3224 }
3225 } else if (rt_type == RT_TYPE_BOTH) {
3226 if (!is_import_rt_configured(vpn)
3227 && !is_export_rt_configured(vpn)) {
3228 vty_out(vty,
3229 "%% Import/Export RT is not configured for this VNI\n");
3230 return CMD_WARNING;
3231 }
3232 }
3233
3234 ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
3235 if (!ecomdel) {
3236 vty_out(vty, "%% Malformed Route Target list\n");
3237 return CMD_WARNING;
3238 }
3239 ecommunity_str(ecomdel);
3240
3241 if (rt_type == RT_TYPE_IMPORT) {
3242 if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
3243 vty_out(vty,
3244 "%% RT specified does not match configuration for this VNI\n");
3245 return CMD_WARNING;
3246 }
3247 evpn_unconfigure_import_rt(bgp, vpn, ecomdel);
3248 } else if (rt_type == RT_TYPE_EXPORT) {
3249 if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomdel)) {
3250 vty_out(vty,
3251 "%% RT specified does not match configuration for this VNI\n");
3252 return CMD_WARNING;
3253 }
3254 evpn_unconfigure_export_rt(bgp, vpn, ecomdel);
3255 } else if (rt_type == RT_TYPE_BOTH) {
3256 found_ecomdel = 0;
3257
3258 if (bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
3259 evpn_unconfigure_import_rt(bgp, vpn, ecomdel);
3260 found_ecomdel = 1;
3261 }
3262
3263 if (bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomdel)) {
3264 evpn_unconfigure_export_rt(bgp, vpn, ecomdel);
3265 found_ecomdel = 1;
3266 }
3267
3268 if (!found_ecomdel) {
3269 vty_out(vty,
3270 "%% RT specified does not match configuration for this VNI\n");
3271 return CMD_WARNING;
3272 }
3273 }
3274
3275 return CMD_SUCCESS;
3276 }
3277
3278 DEFUN (no_bgp_evpn_vni_rt_without_val,
3279 no_bgp_evpn_vni_rt_without_val_cmd,
3280 "no route-target <import|export>",
3281 NO_STR
3282 "Route Target\n"
3283 "import\n"
3284 "export\n")
3285 {
3286 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
3287 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
3288 int rt_type;
3289
3290 if (!bgp || !vpn)
3291 return CMD_WARNING;
3292
3293 if (!strcmp(argv[2]->arg, "import")) {
3294 rt_type = RT_TYPE_IMPORT;
3295 } else if (!strcmp(argv[2]->arg, "export")) {
3296 rt_type = RT_TYPE_EXPORT;
3297 } else {
3298 vty_out(vty, "%% Invalid Route Target type\n");
3299 return CMD_WARNING;
3300 }
3301
3302 /* Check if we should disallow. */
3303 if (rt_type == RT_TYPE_IMPORT) {
3304 if (!is_import_rt_configured(vpn)) {
3305 vty_out(vty,
3306 "%% Import RT is not configured for this VNI\n");
3307 return CMD_WARNING;
3308 }
3309 } else {
3310 if (!is_export_rt_configured(vpn)) {
3311 vty_out(vty,
3312 "%% Export RT is not configured for this VNI\n");
3313 return CMD_WARNING;
3314 }
3315 }
3316
3317 /* Unconfigure the RT. */
3318 if (rt_type == RT_TYPE_IMPORT)
3319 evpn_unconfigure_import_rt(bgp, vpn, NULL);
3320 else
3321 evpn_unconfigure_export_rt(bgp, vpn, NULL);
3322 return CMD_SUCCESS;
3323 }
3324 #endif
3325 /*
3326 * Output EVPN configuration information.
3327 */
3328 void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
3329 safi_t safi, int *write)
3330 {
3331 struct evpn_config_write cfg;
3332
3333 if (bgp->vnihash) {
3334 cfg.write = *write;
3335 cfg.vty = vty;
3336 hash_iterate(bgp->vnihash,
3337 (void (*)(struct hash_backet *,
3338 void *))write_vni_config_for_entry,
3339 &cfg);
3340 *write = cfg.write;
3341 }
3342
3343 if (bgp->advertise_all_vni) {
3344 bgp_config_write_family_header(vty, afi, safi, write);
3345 vty_out(vty, " advertise-all-vni\n");
3346 }
3347
3348 if (bgp->advertise_gw_macip) {
3349 bgp_config_write_family_header(vty, afi, safi, write);
3350 vty_out(vty, " advertise-default-gw\n");
3351 }
3352 }
3353
3354 void bgp_ethernetvpn_init(void)
3355 {
3356 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd);
3357 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd);
3358 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
3359 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
3360 install_element(VIEW_NODE,
3361 &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
3362 install_element(VIEW_NODE,
3363 &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
3364 install_element(
3365 VIEW_NODE,
3366 &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
3367 install_element(
3368 VIEW_NODE,
3369 &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
3370 install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd);
3371 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
3372 install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
3373 install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
3374 #if defined(HAVE_CUMULUS)
3375 install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
3376 install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
3377 install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
3378 install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
3379
3380 /* "show bgp l2vpn evpn" commands. */
3381 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
3382 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
3383 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
3384 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
3385 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
3386 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
3387 install_element(VIEW_NODE,
3388 &show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
3389 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
3390 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
3391 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
3392
3393 /* "show bgp evpn" commands. */
3394 install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
3395 install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
3396 install_element(VIEW_NODE, &show_bgp_evpn_route_cmd);
3397 install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd);
3398 install_element(VIEW_NODE, &show_bgp_evpn_route_rd_macip_cmd);
3399 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_cmd);
3400 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_multicast_cmd);
3401 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd);
3402 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd);
3403 install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd);
3404
3405 install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
3406 install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd);
3407 install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd);
3408 install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rd_cmd);
3409 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rd_cmd);
3410 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rd_without_val_cmd);
3411 install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
3412 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
3413 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
3414 install_element(BGP_EVPN_VNI_NODE,
3415 &bgp_evpn_advertise_default_gw_vni_cmd);
3416 install_element(BGP_EVPN_VNI_NODE,
3417 &no_bgp_evpn_advertise_default_gw_vni_cmd);
3418 #endif
3419 }