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