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