]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_evpn_vty.c
bgpd: Remove HAVE_CUMULUS from evpn commands
[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
996c9314 55static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
10ebe1ab
MK
56 json_object *json)
57{
d7c0a89a
QY
58 uint8_t *pnt;
59 uint8_t type, sub_type;
10ebe1ab
MK
60 struct ecommunity_as eas;
61 struct ecommunity_ip eip;
62 struct listnode *node, *nnode;
63 struct bgp *tmp_bgp_vrf = NULL;
64 json_object *json_rt = NULL;
65 json_object *json_vrfs = NULL;
66 char rt_buf[RT_ADDRSTRLEN];
67
68 if (json) {
69 json_rt = json_object_new_object();
70 json_vrfs = json_object_new_array();
71 }
72
d7c0a89a 73 pnt = (uint8_t *)&irt->rt.val;
10ebe1ab
MK
74 type = *pnt++;
75 sub_type = *pnt++;
76 if (sub_type != ECOMMUNITY_ROUTE_TARGET)
77 return;
78
79 memset(&eas, 0, sizeof(eas));
80 switch (type) {
81 case ECOMMUNITY_ENCODE_AS:
82 eas.as = (*pnt++ << 8);
83 eas.as |= (*pnt++);
100cb793 84 ptr_get_be32(pnt, &eas.val);
10ebe1ab
MK
85
86 snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
87
88 if (json)
89 json_object_string_add(json_rt, "rt", rt_buf);
90 else
91 vty_out(vty, "Route-target: %s", rt_buf);
92
93 break;
94
95 case ECOMMUNITY_ENCODE_IP:
96 memcpy(&eip.ip, pnt, 4);
97 pnt += 4;
98 eip.val = (*pnt++ << 8);
99 eip.val |= (*pnt++);
100
101 snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
102 eip.val);
103
104 if (json)
105 json_object_string_add(json_rt, "rt", rt_buf);
106 else
107 vty_out(vty, "Route-target: %s", rt_buf);
108
109 break;
110
111 case ECOMMUNITY_ENCODE_AS4:
112 pnt = ptr_get_be32(pnt, &eas.val);
113 eas.val = (*pnt++ << 8);
114 eas.val |= (*pnt++);
115
116 snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
117
118 if (json)
119 json_object_string_add(json_rt, "rt", rt_buf);
120 else
121 vty_out(vty, "Route-target: %s", rt_buf);
122
123 break;
124
125 default:
126 return;
127 }
128
129 if (!json) {
130 vty_out(vty,
131 "\nList of VRFs importing routes with this route-target:\n");
132 }
133
134 for (ALL_LIST_ELEMENTS(irt->vrfs, node, nnode, tmp_bgp_vrf)) {
135 if (json)
136 json_object_array_add(
137 json_vrfs,
138 json_object_new_string(
996c9314 139 vrf_id_to_name(tmp_bgp_vrf->vrf_id)));
10ebe1ab
MK
140 else
141 vty_out(vty, " %s\n",
142 vrf_id_to_name(tmp_bgp_vrf->vrf_id));
143 }
144
145 if (json) {
146 json_object_object_add(json_rt, "vrfs", json_vrfs);
147 json_object_object_add(json, rt_buf, json_rt);
148 }
149}
150
996c9314 151static void show_vrf_import_rt_entry(struct hash_backet *backet, void *args[])
10ebe1ab
MK
152{
153 json_object *json = NULL;
154 struct vty *vty = NULL;
155 struct vrf_irt_node *irt = (struct vrf_irt_node *)backet->data;
156
181c08c6
MK
157 vty = (struct vty *)args[0];
158 json = (struct json_object *)args[1];
10ebe1ab
MK
159
160 display_vrf_import_rt(vty, irt, json);
161}
162
9c92b5f7
MK
163static void display_import_rt(struct vty *vty, struct irt_node *irt,
164 json_object *json)
d62a17ae 165{
d7c0a89a
QY
166 uint8_t *pnt;
167 uint8_t type, sub_type;
5a0ccebf
QY
168 struct ecommunity_as eas;
169 struct ecommunity_ip eip;
d62a17ae 170 struct listnode *node, *nnode;
171 struct bgpevpn *tmp_vpn;
9c92b5f7
MK
172 json_object *json_rt = NULL;
173 json_object *json_vnis = NULL;
174 char rt_buf[RT_ADDRSTRLEN];
d62a17ae 175
9c92b5f7 176 if (json) {
b682f6de 177 json_rt = json_object_new_object();
178 json_vnis = json_object_new_array();
9c92b5f7 179 }
d62a17ae 180
181 /* TODO: This needs to go into a function */
182
d7c0a89a 183 pnt = (uint8_t *)&irt->rt.val;
d62a17ae 184 type = *pnt++;
185 sub_type = *pnt++;
186 if (sub_type != ECOMMUNITY_ROUTE_TARGET)
187 return;
188
88a837f6 189 memset(&eas, 0, sizeof(eas));
d62a17ae 190 switch (type) {
191 case ECOMMUNITY_ENCODE_AS:
192 eas.as = (*pnt++ << 8);
193 eas.as |= (*pnt++);
100cb793 194 ptr_get_be32(pnt, &eas.val);
d62a17ae 195
9c92b5f7
MK
196 snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
197
198 if (json)
199 json_object_string_add(json_rt, "rt", rt_buf);
200 else
201 vty_out(vty, "Route-target: %s", rt_buf);
202
d62a17ae 203 break;
204
205 case ECOMMUNITY_ENCODE_IP:
206 memcpy(&eip.ip, pnt, 4);
207 pnt += 4;
208 eip.val = (*pnt++ << 8);
209 eip.val |= (*pnt++);
210
9c92b5f7
MK
211 snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
212 eip.val);
213
214 if (json)
215 json_object_string_add(json_rt, "rt", rt_buf);
216 else
217 vty_out(vty, "Route-target: %s", rt_buf);
218
d62a17ae 219 break;
220
221 case ECOMMUNITY_ENCODE_AS4:
937652c6 222 pnt = ptr_get_be32(pnt, &eas.val);
d62a17ae 223 eas.val = (*pnt++ << 8);
224 eas.val |= (*pnt++);
225
9c92b5f7
MK
226 snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
227
228 if (json)
229 json_object_string_add(json_rt, "rt", rt_buf);
230 else
231 vty_out(vty, "Route-target: %s", rt_buf);
232
d62a17ae 233 break;
234
235 default:
236 return;
237 }
238
9c92b5f7
MK
239 if (!json) {
240 vty_out(vty,
241 "\nList of VNIs importing routes with this route-target:\n");
242 }
243
244 for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) {
245 if (json)
246 json_object_array_add(
247 json_vnis, json_object_new_int64(tmp_vpn->vni));
248 else
249 vty_out(vty, " %u\n", tmp_vpn->vni);
250 }
251
252 if (json) {
253 json_object_object_add(json_rt, "vnis", json_vnis);
254 json_object_object_add(json, rt_buf, json_rt);
255 }
d62a17ae 256}
257
9c92b5f7 258static void show_import_rt_entry(struct hash_backet *backet, void *args[])
520d5d76 259{
9c92b5f7
MK
260 json_object *json = NULL;
261 struct vty *vty = NULL;
d62a17ae 262 struct irt_node *irt = (struct irt_node *)backet->data;
9c92b5f7
MK
263
264 vty = args[0];
265 json = args[1];
266
dff8f48d 267 display_import_rt(vty, irt, json);
9c92b5f7
MK
268
269 return;
d62a17ae 270}
520d5d76 271
d62a17ae 272static void bgp_evpn_show_route_rd_header(struct vty *vty,
9c92b5f7
MK
273 struct bgp_node *rd_rn,
274 json_object *json)
d62a17ae 275{
d7c0a89a 276 uint16_t type;
d62a17ae 277 struct rd_as rd_as;
278 struct rd_ip rd_ip;
d7c0a89a 279 uint8_t *pnt;
9c92b5f7 280 char rd_str[RD_ADDRSTRLEN];
520d5d76 281
d62a17ae 282 pnt = rd_rn->p.u.val;
520d5d76 283
d62a17ae 284 /* Decode RD type. */
285 type = decode_rd_type(pnt);
520d5d76 286
9c92b5f7
MK
287 if (json)
288 return;
289
d62a17ae 290 vty_out(vty, "Route Distinguisher: ");
520d5d76 291
d62a17ae 292 switch (type) {
293 case RD_TYPE_AS:
294 decode_rd_as(pnt + 2, &rd_as);
9c92b5f7 295 snprintf(rd_str, RD_ADDRSTRLEN, "%u:%d", rd_as.as, rd_as.val);
d62a17ae 296 break;
520d5d76 297
d62a17ae 298 case RD_TYPE_IP:
299 decode_rd_ip(pnt + 2, &rd_ip);
9c92b5f7
MK
300 snprintf(rd_str, RD_ADDRSTRLEN, "%s:%d", inet_ntoa(rd_ip.ip),
301 rd_ip.val);
d62a17ae 302 break;
520d5d76 303
d62a17ae 304 default:
9c92b5f7 305 snprintf(rd_str, RD_ADDRSTRLEN, "Unknown RD type");
d62a17ae 306 break;
307 }
308
9c92b5f7 309 vty_out(vty, "%s\n", rd_str);
d62a17ae 310}
311
9c92b5f7 312static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
2dd32217 313 uint64_t tbl_ver, json_object *json)
d62a17ae 314{
315 char ri_header[] =
316 " Network Next Hop Metric LocPrf Weight Path\n";
520d5d76 317
9c92b5f7
MK
318 if (json)
319 return;
320
2dd32217 321 vty_out(vty, "BGP table version is %" PRIu64 ", local router ID is %s\n",
322 tbl_ver, inet_ntoa(bgp->router_id));
d62a17ae 323 vty_out(vty,
324 "Status codes: s suppressed, d damped, h history, "
325 "* valid, > best, i - internal\n");
326 vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
327 vty_out(vty,
554cd77a 328 "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
b3628c70 329 vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
50f74cf1 330 vty_out(vty, "EVPN type-4 prefix: [4]:[ESI]:[IPlen]:[OrigIP]\n");
554cd77a 331 vty_out(vty, "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
d62a17ae 332 vty_out(vty, "%s", ri_header);
333}
520d5d76 334
4cce389e
MK
335static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
336 json_object *json)
337{
338 char buf1[INET6_ADDRSTRLEN];
339 char *ecom_str;
340 struct listnode *node, *nnode;
341 struct ecommunity *ecom;
342 json_object *json_import_rtl = NULL;
343 json_object *json_export_rtl = NULL;
344
345 json_import_rtl = json_export_rtl = 0;
346
347 if (json) {
348 json_import_rtl = json_object_new_array();
349 json_export_rtl = json_object_new_array();
350 json_object_int_add(json, "vni", bgp_vrf->l3vni);
351 json_object_string_add(json, "type", "L3");
352 json_object_string_add(json, "kernelFlag", "Yes");
353 json_object_string_add(
354 json, "rd",
355 prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
356 json_object_string_add(json, "originatorIp",
357 inet_ntoa(bgp_vrf->originator_ip));
358 json_object_string_add(json, "advertiseGatewayMacip", "n/a");
359 } else {
360 vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
361 vty_out(vty, " (known to the kernel)");
362 vty_out(vty, "\n");
363
364 vty_out(vty, " Type: %s\n", "L3");
365 vty_out(vty, " Tenant VRF: %s\n",
366 vrf_id_to_name(bgp_vrf->vrf_id));
367 vty_out(vty, " RD: %s\n",
368 prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
369 vty_out(vty, " Originator IP: %s\n",
370 inet_ntoa(bgp_vrf->originator_ip));
371 vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
372 }
373
374 if (!json)
375 vty_out(vty, " Import Route Target:\n");
376
377 for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
378 ecom_str = ecommunity_ecom2str(ecom,
379 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
380
381 if (json)
382 json_object_array_add(json_import_rtl,
383 json_object_new_string(ecom_str));
384 else
385 vty_out(vty, " %s\n", ecom_str);
386
387 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
388 }
389
390 if (json)
391 json_object_object_add(json, "importRts", json_import_rtl);
392 else
393 vty_out(vty, " Export Route Target:\n");
394
395 for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
396 ecom_str = ecommunity_ecom2str(ecom,
397 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
398
399 if (json)
400 json_object_array_add(json_export_rtl,
401 json_object_new_string(ecom_str));
402 else
403 vty_out(vty, " %s\n", ecom_str);
404
405 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
406 }
407
408 if (json)
409 json_object_object_add(json, "exportRts", json_export_rtl);
410}
411
50f74cf1 412static void display_es(struct vty *vty, struct evpnes *es, json_object *json)
413{
414 struct in_addr *vtep;
415 char buf[ESI_STR_LEN];
416 char buf1[RD_ADDRSTRLEN];
417 char buf2[INET6_ADDRSTRLEN];
418 struct listnode *node = NULL;
419 json_object *json_vteps = NULL;
420
421 if (json) {
422 json_vteps = json_object_new_array();
423 json_object_string_add(json, "esi",
424 esi_to_str(&es->esi, buf, sizeof(buf)));
425 json_object_string_add(json, "rd",
426 prefix_rd2str(&es->prd, buf1,
427 sizeof(buf1)));
2bb9eff4
DS
428 json_object_string_add(
429 json, "originatorIp",
50f74cf1 430 ipaddr2str(&es->originator_ip, buf2, sizeof(buf2)));
431 if (es->vtep_list) {
432 for (ALL_LIST_ELEMENTS_RO(es->vtep_list, node, vtep))
2bb9eff4
DS
433 json_object_array_add(
434 json_vteps, json_object_new_string(
435 inet_ntoa(*vtep)));
50f74cf1 436 }
437 json_object_object_add(json, "vteps", json_vteps);
438 } else {
439 vty_out(vty, "ESI: %s\n",
440 esi_to_str(&es->esi, buf, sizeof(buf)));
441 vty_out(vty, " RD: %s\n", prefix_rd2str(&es->prd, buf1,
442 sizeof(buf1)));
443 vty_out(vty, " Originator-IP: %s\n",
444 ipaddr2str(&es->originator_ip, buf2, sizeof(buf2)));
445 if (es->vtep_list) {
446 vty_out(vty, " VTEP List:\n");
447 for (ALL_LIST_ELEMENTS_RO(es->vtep_list, node, vtep))
2bb9eff4 448 vty_out(vty, " %s\n", inet_ntoa(*vtep));
50f74cf1 449 }
450 }
451}
452
9c92b5f7 453static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
d62a17ae 454{
06b9f471 455 char buf1[RD_ADDRSTRLEN];
d62a17ae 456 char *ecom_str;
457 struct listnode *node, *nnode;
458 struct ecommunity *ecom;
f57514e1
DS
459 json_object *json_import_rtl = NULL;
460 json_object *json_export_rtl = NULL;
9c92b5f7
MK
461
462 if (json) {
463 json_import_rtl = json_object_new_array();
464 json_export_rtl = json_object_new_array();
465 json_object_int_add(json, "vni", vpn->vni);
4cce389e 466 json_object_string_add(json, "type", "L2");
9c92b5f7
MK
467 json_object_string_add(json, "kernelFlag",
468 is_vni_live(vpn) ? "Yes" : "No");
469 json_object_string_add(
470 json, "rd",
06b9f471 471 prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
9c92b5f7
MK
472 json_object_string_add(json, "originatorIp",
473 inet_ntoa(vpn->originator_ip));
474 json_object_string_add(json, "advertiseGatewayMacip",
475 vpn->advertise_gw_macip ? "Yes" : "No");
476 } else {
477 vty_out(vty, "VNI: %d", vpn->vni);
478 if (is_vni_live(vpn))
479 vty_out(vty, " (known to the kernel)");
480 vty_out(vty, "\n");
481
4cce389e 482 vty_out(vty, " Type: %s\n", "L2");
29c53922
MK
483 vty_out(vty, " Tenant-Vrf: %s\n",
484 vrf_id_to_name(vpn->tenant_vrf_id));
9c92b5f7 485 vty_out(vty, " RD: %s\n",
06b9f471 486 prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
9c92b5f7
MK
487 vty_out(vty, " Originator IP: %s\n",
488 inet_ntoa(vpn->originator_ip));
489 vty_out(vty, " Advertise-gw-macip : %s\n",
490 vpn->advertise_gw_macip ? "Yes" : "No");
491 }
520d5d76 492
9c92b5f7
MK
493 if (!json)
494 vty_out(vty, " Import Route Target:\n");
520d5d76 495
d62a17ae 496 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
497 ecom_str = ecommunity_ecom2str(ecom,
498 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
9c92b5f7
MK
499
500 if (json)
501 json_object_array_add(json_import_rtl,
502 json_object_new_string(ecom_str));
503 else
504 vty_out(vty, " %s\n", ecom_str);
505
d62a17ae 506 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
507 }
520d5d76 508
9c92b5f7
MK
509 if (json)
510 json_object_object_add(json, "importRts", json_import_rtl);
511 else
512 vty_out(vty, " Export Route Target:\n");
513
d62a17ae 514 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
515 ecom_str = ecommunity_ecom2str(ecom,
516 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
9c92b5f7
MK
517
518 if (json)
519 json_object_array_add(json_export_rtl,
520 json_object_new_string(ecom_str));
521 else
522 vty_out(vty, " %s\n", ecom_str);
523
d62a17ae 524 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
525 }
9c92b5f7
MK
526
527 if (json)
528 json_object_object_add(json, "exportRts", json_export_rtl);
520d5d76 529}
d62a17ae 530
50f74cf1 531static void show_esi_routes(struct bgp *bgp,
532 struct evpnes *es,
533 struct vty *vty,
534 json_object *json)
535{
536 int header = 1;
537 struct bgp_node *rn;
538 struct bgp_info *ri;
539 uint32_t prefix_cnt, path_cnt;
540 uint64_t tbl_ver;
541
542 prefix_cnt = path_cnt = 0;
543
544 tbl_ver = es->route_table->version;
545 for (rn = bgp_table_top(es->route_table); rn;
546 rn = bgp_route_next(rn)) {
547 int add_prefix_to_json = 0;
548 char prefix_str[BUFSIZ];
549 json_object *json_paths = NULL;
550 json_object *json_prefix = NULL;
551
552 bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
553 sizeof(prefix_str));
554
555 if (json)
556 json_prefix = json_object_new_object();
557
558 if (rn->info) {
559 /* Overall header/legend displayed once. */
560 if (header) {
561 bgp_evpn_show_route_header(vty, bgp,
562 tbl_ver, json);
563 header = 0;
564 }
565
566 prefix_cnt++;
567 }
568
569 if (json)
570 json_paths = json_object_new_array();
571
572 /* For EVPN, the prefix is displayed for each path (to fit in
573 * with code that already exists).
574 */
575 for (ri = rn->info; ri; ri = ri->next) {
576 json_object *json_path = NULL;
577
578 if (json)
579 json_path = json_object_new_array();
580
581 route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, json_path);
582
583 if (json)
584 json_object_array_add(json_paths, json_path);
585
586 path_cnt++;
587 add_prefix_to_json = 1;
588 }
589
590 if (json && add_prefix_to_json) {
591 json_object_string_add(json_prefix, "prefix",
592 prefix_str);
593 json_object_int_add(json_prefix, "prefixLen",
594 rn->p.prefixlen);
595 json_object_object_add(json_prefix, "paths",
596 json_paths);
597 json_object_object_add(json, prefix_str, json_prefix);
598 }
599 }
600
601 if (json) {
602 json_object_int_add(json, "numPrefix", prefix_cnt);
603 json_object_int_add(json, "numPaths", path_cnt);
604 } else {
605 if (prefix_cnt == 0)
a2a8153f 606 vty_out(vty, "No EVPN prefixes exist for this ESI\n");
50f74cf1 607 else
608 vty_out(vty, "\nDisplayed %u prefixes (%u paths)\n",
609 prefix_cnt, path_cnt);
610 }
611}
612
d62a17ae 613static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
9c92b5f7
MK
614 struct vty *vty, struct in_addr vtep_ip,
615 json_object *json)
520d5d76 616{
d62a17ae 617 struct bgp_node *rn;
618 struct bgp_info *ri;
2dd32217 619 struct bgp_table *table;
d62a17ae 620 int header = 1;
2dd32217 621 uint64_t tbl_ver;
d7c0a89a 622 uint32_t prefix_cnt, path_cnt;
d62a17ae 623
624 prefix_cnt = path_cnt = 0;
625
2dd32217 626 table = vpn->route_table;
627 tbl_ver = table->version;
628 for (rn = bgp_table_top(table); rn;
d62a17ae 629 rn = bgp_route_next(rn)) {
630 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
9c92b5f7
MK
631 int add_prefix_to_json = 0;
632 char prefix_str[BUFSIZ];
633 json_object *json_paths = NULL;
634 json_object *json_prefix = NULL;
635
636 bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
637 sizeof(prefix_str));
d62a17ae 638
639 if (type && evp->prefix.route_type != type)
640 continue;
641
9c92b5f7
MK
642 if (json)
643 json_prefix = json_object_new_object();
644
d62a17ae 645 if (rn->info) {
646 /* Overall header/legend displayed once. */
647 if (header) {
2dd32217 648 bgp_evpn_show_route_header(vty, bgp,
649 tbl_ver, json);
d62a17ae 650 header = 0;
651 }
652
653 prefix_cnt++;
654 }
655
9c92b5f7
MK
656 if (json)
657 json_paths = json_object_new_array();
658
d62a17ae 659 /* For EVPN, the prefix is displayed for each path (to fit in
660 * with code that already exists).
661 */
662 for (ri = rn->info; ri; ri = ri->next) {
9c92b5f7
MK
663 json_object *json_path = NULL;
664
d62a17ae 665 if (vtep_ip.s_addr
666 && !IPV4_ADDR_SAME(&(vtep_ip),
667 &(ri->attr->nexthop)))
668 continue;
669
9c92b5f7
MK
670 if (json)
671 json_path = json_object_new_array();
672
673 route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, json_path);
674
675 if (json)
676 json_object_array_add(json_paths, json_path);
677
d62a17ae 678 path_cnt++;
9c92b5f7
MK
679 add_prefix_to_json = 1;
680 }
681
682 if (json && add_prefix_to_json) {
683 json_object_string_add(json_prefix, "prefix",
684 prefix_str);
685 json_object_int_add(json_prefix, "prefixLen",
686 rn->p.prefixlen);
687 json_object_object_add(json_prefix, "paths",
688 json_paths);
689 json_object_object_add(json, prefix_str, json_prefix);
d62a17ae 690 }
691 }
692
9c92b5f7
MK
693 if (json) {
694 json_object_int_add(json, "numPrefix", prefix_cnt);
695 json_object_int_add(json, "numPaths", path_cnt);
696 } else {
697 if (prefix_cnt == 0)
698 vty_out(vty, "No EVPN prefixes %sexist for this VNI",
699 type ? "(of requested type) " : "");
700 else
50f74cf1 701 vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
9c92b5f7
MK
702 prefix_cnt, path_cnt,
703 type ? " (of requested type)" : "");
704 }
520d5d76 705}
706
d62a17ae 707static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
520d5d76 708{
d62a17ae 709 struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
710 struct vni_walk_ctx *wctx = arg;
711 struct vty *vty = wctx->vty;
9c92b5f7
MK
712 json_object *json = wctx->json;
713 json_object *json_vni = NULL;
714 char vni_str[VNI_STR_LEN];
715
716 snprintf(vni_str, VNI_STR_LEN, "%d", vpn->vni);
717 if (json) {
718 json_vni = json_object_new_object();
719 json_object_int_add(json_vni, "vni", vpn->vni);
720 } else {
721 vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
722 }
723
724 show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni);
520d5d76 725
9c92b5f7
MK
726 if (json)
727 json_object_object_add(json, vni_str, json_vni);
520d5d76 728}
729
4cce389e 730static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
996c9314 731 json_object *json)
4cce389e 732{
dcfe4716
DS
733 json_object *json_vni = NULL;
734 json_object *json_import_rtl = NULL;
735 json_object *json_export_rtl = NULL;
4cce389e
MK
736 char buf1[10];
737 char buf2[INET6_ADDRSTRLEN];
738 char rt_buf[25];
739 char *ecom_str;
740 struct listnode *node, *nnode;
741 struct ecommunity *ecom;
742
743 if (!bgp->l3vni)
744 return;
745
746 if (json) {
747 json_vni = json_object_new_object();
748 json_import_rtl = json_object_new_array();
749 json_export_rtl = json_object_new_array();
750 }
751
752 /* if an l3vni is present in bgp it is live */
753 buf1[0] = '\0';
754 sprintf(buf1, "*");
755
756 if (json) {
757 json_object_int_add(json_vni, "vni", bgp->l3vni);
758 json_object_string_add(json_vni, "type", "L3");
759 json_object_string_add(json_vni, "inKernel", "True");
d4454626 760 json_object_string_add(json_vni, "originatorIp",
761 inet_ntoa(bgp->originator_ip));
4cce389e
MK
762 json_object_string_add(
763 json_vni, "rd",
764 prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
765 } else {
996c9314 766 vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, bgp->l3vni, "L3",
4cce389e
MK
767 prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
768 }
769
770 for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) {
771 ecom_str = ecommunity_ecom2str(ecom,
772 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
773
774 if (json) {
775 json_object_array_add(json_import_rtl,
776 json_object_new_string(ecom_str));
777 } else {
778 if (listcount(bgp->vrf_import_rtl) > 1)
779 sprintf(rt_buf, "%s, ...", ecom_str);
780 else
781 sprintf(rt_buf, "%s", ecom_str);
782 vty_out(vty, " %-25s", rt_buf);
783 }
784
785 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
786
787 /* If there are multiple import RTs we break here and show only
788 * one */
789 if (!json)
790 break;
791 }
792
793 if (json)
794 json_object_object_add(json_vni, "importRTs", json_import_rtl);
795
796 for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) {
797 ecom_str = ecommunity_ecom2str(ecom,
798 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
799
800 if (json) {
801 json_object_array_add(json_export_rtl,
802 json_object_new_string(ecom_str));
803 } else {
804 if (listcount(bgp->vrf_export_rtl) > 1)
805 sprintf(rt_buf, "%s, ...", ecom_str);
806 else
807 sprintf(rt_buf, "%s", ecom_str);
808 vty_out(vty, " %-25s", rt_buf);
809 }
810
811 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
812
813 /* If there are multiple export RTs we break here and show only
814 * one */
815 if (!json)
816 break;
817 }
818
819 if (!json)
820 vty_out(vty, "%-37s", vrf_id_to_name(bgp->vrf_id));
821
822 if (json) {
823 char vni_str[VNI_STR_LEN];
824
825 json_object_object_add(json_vni, "exportRTs", json_export_rtl);
826 snprintf(vni_str, VNI_STR_LEN, "%u", bgp->l3vni);
827 json_object_object_add(json, vni_str, json_vni);
828 } else {
829 vty_out(vty, "\n");
830 }
831}
832
50f74cf1 833static void show_es_entry(struct hash_backet *backet, void *args[])
834{
835 char buf[ESI_STR_LEN];
836 char buf1[RD_ADDRSTRLEN];
837 char buf2[INET6_ADDRSTRLEN];
838 struct in_addr *vtep = NULL;
839 struct vty *vty = args[0];
840 json_object *json = args[1];
841 json_object *json_vteps = NULL;
842 struct listnode *node = NULL;
843 struct evpnes *es = (struct evpnes *)backet->data;
844
845 if (json) {
846 json_vteps = json_object_new_array();
847 json_object_string_add(json, "esi",
848 esi_to_str(&es->esi, buf, sizeof(buf)));
849 json_object_string_add(json, "type",
850 is_es_local(es) ? "Local" : "Remote");
851 json_object_string_add(json, "rd",
852 prefix_rd2str(&es->prd, buf1,
853 sizeof(buf1)));
2bb9eff4
DS
854 json_object_string_add(
855 json, "originatorIp",
50f74cf1 856 ipaddr2str(&es->originator_ip, buf2, sizeof(buf2)));
857 if (es->vtep_list) {
858 for (ALL_LIST_ELEMENTS_RO(es->vtep_list, node, vtep))
859 json_object_array_add(json_vteps,
860 json_object_new_string(
861 inet_ntoa(*vtep)));
862 }
863 json_object_object_add(json, "vteps", json_vteps);
864 } else {
865 vty_out(vty, "%-30s %-6s %-21s %-15s %-6d\n",
866 esi_to_str(&es->esi, buf, sizeof(buf)),
867 is_es_local(es) ? "Local" : "Remote",
868 prefix_rd2str(&es->prd, buf1, sizeof(buf1)),
869 ipaddr2str(&es->originator_ip, buf2,
870 sizeof(buf2)),
871 es->vtep_list ? listcount(es->vtep_list) : 0);
872 }
873}
874
9c92b5f7 875static void show_vni_entry(struct hash_backet *backet, void *args[])
520d5d76 876{
9c92b5f7
MK
877 struct vty *vty;
878 json_object *json;
fb8f41e4
RB
879 json_object *json_vni = NULL;
880 json_object *json_import_rtl = NULL;
881 json_object *json_export_rtl = NULL;
d62a17ae 882 struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
883 char buf1[10];
06b9f471 884 char buf2[RD_ADDRSTRLEN];
d62a17ae 885 char rt_buf[25];
886 char *ecom_str;
887 struct listnode *node, *nnode;
888 struct ecommunity *ecom;
520d5d76 889
9c92b5f7
MK
890 vty = args[0];
891 json = args[1];
892
893 if (json) {
894 json_vni = json_object_new_object();
895 json_import_rtl = json_object_new_array();
896 json_export_rtl = json_object_new_array();
897 }
898
d62a17ae 899 buf1[0] = '\0';
900 if (is_vni_live(vpn))
901 sprintf(buf1, "*");
520d5d76 902
9c92b5f7
MK
903 if (json) {
904 json_object_int_add(json_vni, "vni", vpn->vni);
4cce389e 905 json_object_string_add(json_vni, "type", "L2");
9c92b5f7
MK
906 json_object_string_add(json_vni, "inKernel",
907 is_vni_live(vpn) ? "True" : "False");
908 json_object_string_add(json_vni, "originatorIp",
909 inet_ntoa(vpn->originator_ip));
d4454626 910 json_object_string_add(json_vni, "originatorIp",
911 inet_ntoa(vpn->originator_ip));
9c92b5f7
MK
912 json_object_string_add(
913 json_vni, "rd",
06b9f471 914 prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
9c92b5f7 915 } else {
996c9314 916 vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, vpn->vni, "L2",
29c53922 917 prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
9c92b5f7 918 }
520d5d76 919
d62a17ae 920 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
921 ecom_str = ecommunity_ecom2str(ecom,
922 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
520d5d76 923
9c92b5f7
MK
924 if (json) {
925 json_object_array_add(json_import_rtl,
926 json_object_new_string(ecom_str));
927 } else {
928 if (listcount(vpn->import_rtl) > 1)
929 sprintf(rt_buf, "%s, ...", ecom_str);
930 else
931 sprintf(rt_buf, "%s", ecom_str);
932 vty_out(vty, " %-25s", rt_buf);
933 }
520d5d76 934
d62a17ae 935 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
9c92b5f7
MK
936
937 /* If there are multiple import RTs we break here and show only
938 * one */
939 if (!json)
940 break;
d62a17ae 941 }
942
9c92b5f7
MK
943 if (json)
944 json_object_object_add(json_vni, "importRTs", json_import_rtl);
945
d62a17ae 946 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
947 ecom_str = ecommunity_ecom2str(ecom,
948 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
949
9c92b5f7
MK
950 if (json) {
951 json_object_array_add(json_export_rtl,
952 json_object_new_string(ecom_str));
953 } else {
954 if (listcount(vpn->export_rtl) > 1)
955 sprintf(rt_buf, "%s, ...", ecom_str);
956 else
957 sprintf(rt_buf, "%s", ecom_str);
958 vty_out(vty, " %-25s", rt_buf);
959 }
d62a17ae 960
961 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
9c92b5f7
MK
962
963 /* If there are multiple export RTs we break here and show only
964 * one */
965 if (!json)
966 break;
967 }
968
6be9a208
MK
969 if (!json)
970 vty_out(vty, "%-37s", vrf_id_to_name(vpn->tenant_vrf_id));
971
9c92b5f7
MK
972 if (json) {
973 char vni_str[VNI_STR_LEN];
b682f6de 974
9c92b5f7
MK
975 json_object_object_add(json_vni, "exportRTs", json_export_rtl);
976 snprintf(vni_str, VNI_STR_LEN, "%u", vpn->vni);
977 json_object_object_add(json, vni_str, json_vni);
978 } else {
979 vty_out(vty, "\n");
d62a17ae 980 }
520d5d76 981}
982
d62a17ae 983static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
984 enum bgp_show_type type, void *output_arg,
d7c0a89a 985 int option, uint8_t use_json)
784d3a42 986{
4d0e6ece
PG
987 afi_t afi = AFI_L2VPN;
988 struct bgp *bgp;
989 struct bgp_table *table;
990 struct bgp_node *rn;
991 struct bgp_node *rm;
992 struct bgp_info *ri;
993 int rd_header;
994 int header = 1;
4d0e6ece
PG
995
996 unsigned long output_count = 0;
997 unsigned long total_count = 0;
998 json_object *json = NULL;
999 json_object *json_nroute = NULL;
1000 json_object *json_array = NULL;
1001 json_object *json_scode = NULL;
1002 json_object *json_ocode = NULL;
1003
1004 bgp = bgp_get_default();
1005 if (bgp == NULL) {
1006 if (!use_json)
d62a17ae 1007 vty_out(vty, "No BGP process is configured\n");
16307668
RW
1008 else
1009 vty_out(vty, "{}\n");
4d0e6ece
PG
1010 return CMD_WARNING;
1011 }
1012
1013 if (use_json) {
1014 json_scode = json_object_new_object();
1015 json_ocode = json_object_new_object();
1016 json = json_object_new_object();
1017 json_nroute = json_object_new_object();
1018
1019 json_object_string_add(json_scode, "suppressed", "s");
1020 json_object_string_add(json_scode, "damped", "d");
1021 json_object_string_add(json_scode, "history", "h");
1022 json_object_string_add(json_scode, "valid", "*");
1023 json_object_string_add(json_scode, "best", ">");
1024 json_object_string_add(json_scode, "internal", "i");
1025
1026 json_object_string_add(json_ocode, "igp", "i");
1027 json_object_string_add(json_ocode, "egp", "e");
1028 json_object_string_add(json_ocode, "incomplete", "?");
1029 }
1030
1031 for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
1032 rn = bgp_route_next(rn)) {
2dd32217 1033 uint64_t tbl_ver;
1034
4d0e6ece 1035 if (use_json)
d62a17ae 1036 continue; /* XXX json TODO */
4d0e6ece
PG
1037
1038 if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
1039 continue;
1040
ea47320b
DL
1041 if ((table = rn->info) == NULL)
1042 continue;
4d0e6ece 1043
ea47320b 1044 rd_header = 1;
2dd32217 1045 tbl_ver = table->version;
4d0e6ece 1046
60466a63 1047 for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm))
ea47320b
DL
1048 for (ri = rm->info; ri; ri = ri->next) {
1049 total_count++;
1050 if (type == bgp_show_type_neighbor) {
60466a63 1051 union sockunion *su = output_arg;
ea47320b
DL
1052
1053 if (ri->peer->su_remote == NULL
1054 || !sockunion_same(
60466a63 1055 ri->peer->su_remote, su))
ea47320b
DL
1056 continue;
1057 }
1058 if (header == 0) {
1059 if (use_json) {
1060 if (option
1061 == SHOW_DISPLAY_TAGS) {
1062 json_object_int_add(
1063 json,
1064 "bgpTableVersion",
2dd32217 1065 tbl_ver);
d62a17ae 1066 json_object_string_add(
ea47320b
DL
1067 json,
1068 "bgpLocalRouterId",
1069 inet_ntoa(
1070 bgp->router_id));
1071 json_object_object_add(
1072 json,
1073 "bgpStatusCodes",
1074 json_scode);
1075 json_object_object_add(
1076 json,
1077 "bgpOriginCodes",
1078 json_ocode);
1079 }
1080 } else {
60466a63 1081 if (option == SHOW_DISPLAY_TAGS)
ea47320b
DL
1082 vty_out(vty,
1083 V4_HEADER_TAG);
1084 else if (
1085 option
1086 == SHOW_DISPLAY_OVERLAY)
1087 vty_out(vty,
1088 V4_HEADER_OVERLAY);
1089 else {
1090 vty_out(vty,
2dd32217 1091 "BGP table version is %" PRIu64 ", local router ID is %s\n",
1092 tbl_ver,
ea47320b
DL
1093 inet_ntoa(
1094 bgp->router_id));
4d0e6ece 1095 vty_out(vty,
ea47320b
DL
1096 "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
1097 vty_out(vty,
1098 "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n");
60466a63 1099 vty_out(vty, V4_HEADER);
4d0e6ece 1100 }
4d0e6ece 1101 }
ea47320b 1102 header = 0;
4d0e6ece 1103 }
ea47320b 1104 if (rd_header) {
d7c0a89a 1105 uint16_t type;
ea47320b
DL
1106 struct rd_as rd_as;
1107 struct rd_ip rd_ip;
d7c0a89a 1108 uint8_t *pnt;
ea47320b
DL
1109
1110 pnt = rn->p.u.val;
1111
1112 /* Decode RD type. */
1113 type = decode_rd_type(pnt);
1114 /* Decode RD value. */
1115 if (type == RD_TYPE_AS)
1116 decode_rd_as(pnt + 2, &rd_as);
1117 else if (type == RD_TYPE_AS4)
1118 decode_rd_as4(pnt + 2, &rd_as);
1119 else if (type == RD_TYPE_IP)
1120 decode_rd_ip(pnt + 2, &rd_ip);
1121 if (use_json) {
1122 char buffer[BUFSIZ];
1123 if (type == RD_TYPE_AS
1124 || type == RD_TYPE_AS4)
60466a63 1125 sprintf(buffer, "%u:%d",
ea47320b
DL
1126 rd_as.as,
1127 rd_as.val);
60466a63
QY
1128 else if (type == RD_TYPE_IP)
1129 sprintf(buffer, "%s:%d",
ea47320b
DL
1130 inet_ntoa(
1131 rd_ip.ip),
1132 rd_ip.val);
1133 json_object_string_add(
1134 json_nroute,
1135 "routeDistinguisher",
1136 buffer);
1137 } else {
1138 vty_out(vty,
1139 "Route Distinguisher: ");
1140 if (type == RD_TYPE_AS)
1141 vty_out(vty,
1142 "as2 %u:%d",
1143 rd_as.as,
1144 rd_as.val);
60466a63 1145 else if (type == RD_TYPE_AS4)
ea47320b
DL
1146 vty_out(vty,
1147 "as4 %u:%d",
1148 rd_as.as,
1149 rd_as.val);
60466a63
QY
1150 else if (type == RD_TYPE_IP)
1151 vty_out(vty, "ip %s:%d",
ea47320b
DL
1152 inet_ntoa(
1153 rd_ip.ip),
1154 rd_ip.val);
1155 vty_out(vty, "\n\n");
1156 }
1157 rd_header = 0;
1158 }
1159 if (use_json)
1160 json_array = json_object_new_array();
1161 else
1162 json_array = NULL;
1163 if (option == SHOW_DISPLAY_TAGS)
1164 route_vty_out_tag(vty, &rm->p, ri, 0,
1165 SAFI_EVPN,
1166 json_array);
1167 else if (option == SHOW_DISPLAY_OVERLAY)
1168 route_vty_out_overlay(vty, &rm->p, ri,
1169 0, json_array);
1170 else
1171 route_vty_out(vty, &rm->p, ri, 0,
1172 SAFI_EVPN, json_array);
1173 output_count++;
1174 }
1175 /* XXX json */
4d0e6ece
PG
1176 }
1177 if (output_count == 0)
d62a17ae 1178 vty_out(vty, "No prefixes displayed, %ld exist\n", total_count);
4d0e6ece 1179 else
d62a17ae 1180 vty_out(vty, "\nDisplayed %ld out of %ld total prefixes\n",
1181 output_count, total_count);
4d0e6ece 1182 return CMD_SUCCESS;
784d3a42
PG
1183}
1184
4d0e6ece
PG
1185DEFUN(show_ip_bgp_l2vpn_evpn,
1186 show_ip_bgp_l2vpn_evpn_cmd,
1187 "show [ip] bgp l2vpn evpn [json]",
1188 SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR)
784d3a42 1189{
4d0e6ece
PG
1190 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0,
1191 use_json(argc, argv));
784d3a42
PG
1192}
1193
4d0e6ece
PG
1194DEFUN(show_ip_bgp_l2vpn_evpn_rd,
1195 show_ip_bgp_l2vpn_evpn_rd_cmd,
d114b977 1196 "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN [json]",
4d0e6ece
PG
1197 SHOW_STR
1198 IP_STR
1199 BGP_STR
1200 L2VPN_HELP_STR
1201 EVPN_HELP_STR
1202 "Display information for a route distinguisher\n"
1203 "VPN Route Distinguisher\n" JSON_STR)
784d3a42 1204{
313605cb 1205 int idx_ext_community = 0;
4d0e6ece
PG
1206 int ret;
1207 struct prefix_rd prd;
1208
d114b977 1209 argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
313605cb 1210
4d0e6ece
PG
1211 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1212 if (!ret) {
d62a17ae 1213 vty_out(vty, "%% Malformed Route Distinguisher\n");
4d0e6ece
PG
1214 return CMD_WARNING;
1215 }
1216 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0,
1217 use_json(argc, argv));
784d3a42
PG
1218}
1219
4d0e6ece
PG
1220DEFUN(show_ip_bgp_l2vpn_evpn_all_tags,
1221 show_ip_bgp_l2vpn_evpn_all_tags_cmd,
1222 "show [ip] bgp l2vpn evpn all tags",
1223 SHOW_STR
1224 IP_STR
1225 BGP_STR
1226 L2VPN_HELP_STR
1227 EVPN_HELP_STR
1228 "Display information about all EVPN NLRIs\n"
1229 "Display BGP tags for prefixes\n")
784d3a42 1230{
4d0e6ece
PG
1231 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1,
1232 0);
784d3a42
PG
1233}
1234
4d0e6ece
PG
1235DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags,
1236 show_ip_bgp_l2vpn_evpn_rd_tags_cmd,
d114b977 1237 "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN tags",
4d0e6ece
PG
1238 SHOW_STR
1239 IP_STR
1240 BGP_STR
1241 L2VPN_HELP_STR
1242 EVPN_HELP_STR
1243 "Display information for a route distinguisher\n"
1244 "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n")
784d3a42 1245{
313605cb 1246 int idx_ext_community = 0;
4d0e6ece
PG
1247 int ret;
1248 struct prefix_rd prd;
1249
d114b977 1250 argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
313605cb 1251
4d0e6ece
PG
1252 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1253 if (!ret) {
d62a17ae 1254 vty_out(vty, "%% Malformed Route Distinguisher\n");
4d0e6ece
PG
1255 return CMD_WARNING;
1256 }
1257 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1,
1258 0);
784d3a42
PG
1259}
1260
4d0e6ece
PG
1261DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
1262 show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
1263 "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
1264 SHOW_STR
1265 IP_STR
1266 BGP_STR
1267 L2VPN_HELP_STR
1268 EVPN_HELP_STR
1269 "Display information about all EVPN NLRIs\n"
1270 "Detailed information on TCP and BGP neighbor connections\n"
1271 "Neighbor to display information about\n"
1272 "Display routes learned from neighbor\n" JSON_STR)
784d3a42 1273{
313605cb 1274 int idx_ipv4 = 0;
4d0e6ece
PG
1275 union sockunion su;
1276 struct peer *peer;
1277 int ret;
d7c0a89a 1278 uint8_t uj = use_json(argc, argv);
4d0e6ece 1279
d62a17ae 1280 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
313605cb 1281
4d0e6ece
PG
1282 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
1283 if (ret < 0) {
1284 if (uj) {
1285 json_object *json_no = NULL;
1286 json_no = json_object_new_object();
1287 json_object_string_add(json_no, "warning",
1288 "Malformed address");
d62a17ae 1289 vty_out(vty, "%s\n",
96ade3ed 1290 json_object_to_json_string(json_no));
4d0e6ece
PG
1291 json_object_free(json_no);
1292 } else
d62a17ae 1293 vty_out(vty, "Malformed address: %s\n",
96ade3ed 1294 argv[idx_ipv4]->arg);
4d0e6ece
PG
1295 return CMD_WARNING;
1296 }
1297
1298 peer = peer_lookup(NULL, &su);
1299 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
1300 if (uj) {
1301 json_object *json_no = NULL;
1302 json_no = json_object_new_object();
d62a17ae 1303 json_object_string_add(
1304 json_no, "warning",
1305 "No such neighbor or address family");
1306 vty_out(vty, "%s\n",
96ade3ed 1307 json_object_to_json_string(json_no));
4d0e6ece
PG
1308 json_object_free(json_no);
1309 } else
d62a17ae 1310 vty_out(vty, "%% No such neighbor or address family\n");
4d0e6ece
PG
1311 return CMD_WARNING;
1312 }
1313
1314 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0,
1315 uj);
784d3a42
PG
1316}
1317
4d0e6ece
PG
1318DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
1319 show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
d114b977 1320 "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D routes [json]",
4d0e6ece
PG
1321 SHOW_STR
1322 IP_STR
1323 BGP_STR
1324 L2VPN_HELP_STR
1325 EVPN_HELP_STR
1326 "Display information for a route distinguisher\n"
1327 "VPN Route Distinguisher\n"
1328 "Detailed information on TCP and BGP neighbor connections\n"
1329 "Neighbor to display information about\n"
1330 "Display routes learned from neighbor\n" JSON_STR)
784d3a42 1331{
313605cb
RW
1332 int idx_ext_community = 0;
1333 int idx_ipv4 = 0;
4d0e6ece
PG
1334 int ret;
1335 union sockunion su;
1336 struct peer *peer;
1337 struct prefix_rd prd;
d7c0a89a 1338 uint8_t uj = use_json(argc, argv);
4d0e6ece 1339
d114b977 1340 argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
d62a17ae 1341 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
313605cb 1342
4d0e6ece
PG
1343 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1344 if (!ret) {
1345 if (uj) {
1346 json_object *json_no = NULL;
1347 json_no = json_object_new_object();
1348 json_object_string_add(json_no, "warning",
1349 "Malformed Route Distinguisher");
d62a17ae 1350 vty_out(vty, "%s\n",
96ade3ed 1351 json_object_to_json_string(json_no));
4d0e6ece
PG
1352 json_object_free(json_no);
1353 } else
d62a17ae 1354 vty_out(vty, "%% Malformed Route Distinguisher\n");
4d0e6ece
PG
1355 return CMD_WARNING;
1356 }
1357
1358 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
1359 if (ret < 0) {
1360 if (uj) {
1361 json_object *json_no = NULL;
1362 json_no = json_object_new_object();
1363 json_object_string_add(json_no, "warning",
1364 "Malformed address");
d62a17ae 1365 vty_out(vty, "%s\n",
96ade3ed 1366 json_object_to_json_string(json_no));
4d0e6ece
PG
1367 json_object_free(json_no);
1368 } else
d62a17ae 1369 vty_out(vty, "Malformed address: %s\n",
96ade3ed 1370 argv[idx_ext_community]->arg);
4d0e6ece
PG
1371 return CMD_WARNING;
1372 }
1373
1374 peer = peer_lookup(NULL, &su);
1375 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
1376 if (uj) {
1377 json_object *json_no = NULL;
1378 json_no = json_object_new_object();
d62a17ae 1379 json_object_string_add(
1380 json_no, "warning",
1381 "No such neighbor or address family");
1382 vty_out(vty, "%s\n",
96ade3ed 1383 json_object_to_json_string(json_no));
4d0e6ece
PG
1384 json_object_free(json_no);
1385 } else
d62a17ae 1386 vty_out(vty, "%% No such neighbor or address family\n");
4d0e6ece
PG
1387 return CMD_WARNING;
1388 }
1389
1390 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0,
1391 uj);
784d3a42
PG
1392}
1393
4d0e6ece
PG
1394DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
1395 show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
1396 "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
1397 SHOW_STR
1398 IP_STR
1399 BGP_STR
1400 L2VPN_HELP_STR
1401 EVPN_HELP_STR
1402 "Display information about all EVPN NLRIs\n"
1403 "Detailed information on TCP and BGP neighbor connections\n"
1404 "Neighbor to display information about\n"
1405 "Display the routes advertised to a BGP neighbor\n" JSON_STR)
784d3a42 1406{
313605cb 1407 int idx_ipv4 = 0;
4d0e6ece
PG
1408 int ret;
1409 struct peer *peer;
1410 union sockunion su;
d7c0a89a 1411 uint8_t uj = use_json(argc, argv);
4d0e6ece 1412
d62a17ae 1413 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
313605cb 1414
4d0e6ece
PG
1415 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
1416 if (ret < 0) {
1417 if (uj) {
1418 json_object *json_no = NULL;
1419 json_no = json_object_new_object();
1420 json_object_string_add(json_no, "warning",
1421 "Malformed address");
d62a17ae 1422 vty_out(vty, "%s\n",
96ade3ed 1423 json_object_to_json_string(json_no));
4d0e6ece
PG
1424 json_object_free(json_no);
1425 } else
d62a17ae 1426 vty_out(vty, "Malformed address: %s\n",
96ade3ed 1427 argv[idx_ipv4]->arg);
4d0e6ece
PG
1428 return CMD_WARNING;
1429 }
1430 peer = peer_lookup(NULL, &su);
1431 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
1432 if (uj) {
1433 json_object *json_no = NULL;
1434 json_no = json_object_new_object();
d62a17ae 1435 json_object_string_add(
1436 json_no, "warning",
1437 "No such neighbor or address family");
1438 vty_out(vty, "%s\n",
96ade3ed 1439 json_object_to_json_string(json_no));
4d0e6ece
PG
1440 json_object_free(json_no);
1441 } else
d62a17ae 1442 vty_out(vty, "%% No such neighbor or address family\n");
4d0e6ece
PG
1443 return CMD_WARNING;
1444 }
1445
1446 return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj);
784d3a42
PG
1447}
1448
4d0e6ece
PG
1449DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
1450 show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
d114b977 1451 "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D advertised-routes [json]",
4d0e6ece
PG
1452 SHOW_STR
1453 IP_STR
1454 BGP_STR
1455 L2VPN_HELP_STR
1456 EVPN_HELP_STR
1457 "Display information for a route distinguisher\n"
1458 "VPN Route Distinguisher\n"
1459 "Detailed information on TCP and BGP neighbor connections\n"
1460 "Neighbor to display information about\n"
1461 "Display the routes advertised to a BGP neighbor\n" JSON_STR)
784d3a42 1462{
313605cb
RW
1463 int idx_ext_community = 0;
1464 int idx_ipv4 = 0;
4d0e6ece
PG
1465 int ret;
1466 struct peer *peer;
1467 struct prefix_rd prd;
1468 union sockunion su;
d7c0a89a 1469 uint8_t uj = use_json(argc, argv);
4d0e6ece 1470
d114b977 1471 argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
d62a17ae 1472 argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
313605cb 1473
4d0e6ece
PG
1474 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
1475 if (ret < 0) {
1476 if (uj) {
1477 json_object *json_no = NULL;
1478 json_no = json_object_new_object();
1479 json_object_string_add(json_no, "warning",
1480 "Malformed address");
d62a17ae 1481 vty_out(vty, "%s\n",
96ade3ed 1482 json_object_to_json_string(json_no));
4d0e6ece
PG
1483 json_object_free(json_no);
1484 } else
d62a17ae 1485 vty_out(vty, "Malformed address: %s\n",
96ade3ed 1486 argv[idx_ext_community]->arg);
4d0e6ece
PG
1487 return CMD_WARNING;
1488 }
1489 peer = peer_lookup(NULL, &su);
1490 if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
1491 if (uj) {
1492 json_object *json_no = NULL;
1493 json_no = json_object_new_object();
d62a17ae 1494 json_object_string_add(
1495 json_no, "warning",
1496 "No such neighbor or address family");
1497 vty_out(vty, "%s\n",
96ade3ed 1498 json_object_to_json_string(json_no));
4d0e6ece
PG
1499 json_object_free(json_no);
1500 } else
d62a17ae 1501 vty_out(vty, "%% No such neighbor or address family\n");
4d0e6ece
PG
1502 return CMD_WARNING;
1503 }
1504
1505 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1506 if (!ret) {
1507 if (uj) {
1508 json_object *json_no = NULL;
1509 json_no = json_object_new_object();
1510 json_object_string_add(json_no, "warning",
1511 "Malformed Route Distinguisher");
d62a17ae 1512 vty_out(vty, "%s\n",
96ade3ed 1513 json_object_to_json_string(json_no));
4d0e6ece
PG
1514 json_object_free(json_no);
1515 } else
d62a17ae 1516 vty_out(vty, "%% Malformed Route Distinguisher\n");
4d0e6ece
PG
1517 return CMD_WARNING;
1518 }
1519
1520 return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj);
784d3a42
PG
1521}
1522
4d0e6ece
PG
1523DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay,
1524 show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
1525 "show [ip] bgp l2vpn evpn all overlay",
1526 SHOW_STR
1527 IP_STR
1528 BGP_STR
1529 L2VPN_HELP_STR
1530 EVPN_HELP_STR
1531 "Display information about all EVPN NLRIs\n"
1532 "Display BGP Overlay Information for prefixes\n")
784d3a42 1533{
4d0e6ece 1534 return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL,
d62a17ae 1535 SHOW_DISPLAY_OVERLAY,
1536 use_json(argc, argv));
784d3a42
PG
1537}
1538
4d0e6ece
PG
1539DEFUN(show_ip_bgp_evpn_rd_overlay,
1540 show_ip_bgp_evpn_rd_overlay_cmd,
d114b977 1541 "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN overlay",
4d0e6ece
PG
1542 SHOW_STR
1543 IP_STR
1544 BGP_STR
1545 L2VPN_HELP_STR
1546 EVPN_HELP_STR
1547 "Display information for a route distinguisher\n"
1548 "VPN Route Distinguisher\n"
1549 "Display BGP Overlay Information for prefixes\n")
784d3a42 1550{
313605cb 1551 int idx_ext_community = 0;
4d0e6ece
PG
1552 int ret;
1553 struct prefix_rd prd;
1554
d114b977 1555 argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
313605cb 1556
4d0e6ece
PG
1557 ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
1558 if (!ret) {
d62a17ae 1559 vty_out(vty, "%% Malformed Route Distinguisher\n");
4d0e6ece
PG
1560 return CMD_WARNING;
1561 }
1562 return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL,
d62a17ae 1563 SHOW_DISPLAY_OVERLAY,
1564 use_json(argc, argv));
784d3a42
PG
1565}
1566
3da6fcd5 1567/* For testing purpose, static route of MPLS-VPN. */
4d0e6ece
PG
1568DEFUN(evpnrt5_network,
1569 evpnrt5_network_cmd,
d114b977 1570 "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]",
4d0e6ece
PG
1571 "Specify a network to announce via BGP\n"
1572 "IP prefix\n"
1573 "IPv6 prefix\n"
1574 "Specify Route Distinguisher\n"
1575 "VPN Route Distinguisher\n"
1576 "Ethernet Tag\n"
1577 "Ethernet Tag Value\n"
1578 "BGP label\n"
1579 "label value\n"
1580 "Ethernet Segment Identifier\n"
1581 "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
1582 "Gateway IP\n"
1583 "Gateway IP ( A.B.C.D )\n"
1584 "Gateway IPv6 ( X:X::X:X )\n"
1585 "Router Mac Ext Comm\n"
55daa605
DS
1586 "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n"
1587 "Route-map to modify the attributes\n"
1588 "Name of the route map\n")
3da6fcd5 1589{
4d0e6ece 1590 int idx_ipv4_prefixlen = 1;
197cb530
PG
1591 int idx_route_distinguisher = 3;
1592 int idx_label = 7;
4d0e6ece
PG
1593 int idx_esi = 9;
1594 int idx_gwip = 11;
1595 int idx_ethtag = 5;
1596 int idx_routermac = 13;
197cb530 1597
d62a17ae 1598 return bgp_static_set_safi(
1599 AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
996c9314 1600 argv[idx_route_distinguisher]->arg, argv[idx_label]->arg, NULL,
d62a17ae 1601 BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
1602 argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
1603 argv[idx_routermac]->arg);
3da6fcd5
PG
1604}
1605
1606/* For testing purpose, static route of MPLS-VPN. */
4d0e6ece
PG
1607DEFUN(no_evpnrt5_network,
1608 no_evpnrt5_network_cmd,
d114b977 1609 "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>",
4d0e6ece
PG
1610 NO_STR
1611 "Specify a network to announce via BGP\n"
1612 "IP prefix\n"
1613 "IPv6 prefix\n"
1614 "Specify Route Distinguisher\n"
1615 "VPN Route Distinguisher\n"
1616 "Ethernet Tag\n"
1617 "Ethernet Tag Value\n"
1618 "BGP label\n"
1619 "label value\n"
1620 "Ethernet Segment Identifier\n"
1621 "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
1622 "Gateway IP\n" "Gateway IP ( A.B.C.D )\n" "Gateway IPv6 ( X:X::X:X )\n")
3da6fcd5 1623{
4d0e6ece
PG
1624 int idx_ipv4_prefixlen = 2;
1625 int idx_ext_community = 4;
1626 int idx_label = 8;
1627 int idx_ethtag = 6;
1628 int idx_esi = 10;
1629 int idx_gwip = 12;
d62a17ae 1630 return bgp_static_unset_safi(
1631 AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
1632 argv[idx_ext_community]->arg, argv[idx_label]->arg,
1633 BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
1634 argv[idx_gwip]->arg, argv[idx_ethtag]->arg);
3da6fcd5
PG
1635}
1636
d62a17ae 1637static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
90e60aa7 1638{
c581d8b0 1639 evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl);
90e60aa7 1640}
1641
d62a17ae 1642static void evpn_export_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
90e60aa7 1643{
c581d8b0 1644 evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl);
90e60aa7 1645}
1646
1647/*
1648 * Configure the Import RTs for a VNI (vty handler). Caller expected to
1649 * check that this is a change.
1650 */
d62a17ae 1651static void evpn_configure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
1652 struct ecommunity *ecomadd)
90e60aa7 1653{
d62a17ae 1654 /* If the VNI is "live", we need to uninstall routes using the current
1655 * import RT(s) first before we update the import RT, and subsequently
1656 * install routes.
1657 */
1658 if (is_vni_live(vpn))
1659 bgp_evpn_uninstall_routes(bgp, vpn);
90e60aa7 1660
d62a17ae 1661 /* Cleanup the RT to VNI mapping and get rid of existing import RT. */
1662 bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
90e60aa7 1663
d62a17ae 1664 /* If the auto route-target is in use we must remove it */
1665 evpn_import_rt_delete_auto(bgp, vpn);
90e60aa7 1666
d62a17ae 1667 /* Add new RT and rebuild the RT to VNI mapping */
1668 listnode_add_sort(vpn->import_rtl, ecomadd);
90e60aa7 1669
d62a17ae 1670 SET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
1671 bgp_evpn_map_vni_to_its_rts(bgp, vpn);
90e60aa7 1672
d62a17ae 1673 /* Install routes that match new import RT */
1674 if (is_vni_live(vpn))
1675 bgp_evpn_install_routes(bgp, vpn);
90e60aa7 1676}
1677
1678/*
1679 * Unconfigure Import RT(s) for a VNI (vty handler).
1680 */
d62a17ae 1681static void evpn_unconfigure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
1682 struct ecommunity *ecomdel)
1683{
1684 struct listnode *node, *nnode, *node_to_del;
1685 struct ecommunity *ecom;
1686
1687 /* Along the lines of "configure" except we have to reset to the
1688 * automatic value.
1689 */
1690 if (is_vni_live(vpn))
1691 bgp_evpn_uninstall_routes(bgp, vpn);
1692
1693 /* Cleanup the RT to VNI mapping and get rid of existing import RT. */
1694 bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
1695
1696 /* Delete all import RTs */
1697 if (ecomdel == NULL) {
1698 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom))
1699 ecommunity_free(&ecom);
1700
1701 list_delete_all_node(vpn->import_rtl);
1702 }
1703
1704 /* Delete a specific import RT */
1705 else {
1706 node_to_del = NULL;
1707
1708 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
1709 if (ecommunity_match(ecom, ecomdel)) {
1710 ecommunity_free(&ecom);
1711 node_to_del = node;
1712 break;
1713 }
1714 }
1715
1716 if (node_to_del)
1717 list_delete_node(vpn->import_rtl, node_to_del);
1718 }
1719
1720 /* Reset to auto RT - this also rebuilds the RT to VNI mapping */
1721 if (list_isempty(vpn->import_rtl)) {
1722 UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
1723 bgp_evpn_derive_auto_rt_import(bgp, vpn);
1724 }
1725 /* Rebuild the RT to VNI mapping */
1726 else
1727 bgp_evpn_map_vni_to_its_rts(bgp, vpn);
1728
1729 /* Install routes that match new import RT */
1730 if (is_vni_live(vpn))
1731 bgp_evpn_install_routes(bgp, vpn);
90e60aa7 1732}
1733
1734/*
1735 * Configure the Export RT for a VNI (vty handler). Caller expected to
1736 * check that this is a change. Note that only a single export RT is
1737 * allowed for a VNI and any change to configuration is implemented as
1738 * a "replace" (similar to other configuration).
1739 */
d62a17ae 1740static void evpn_configure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
1741 struct ecommunity *ecomadd)
90e60aa7 1742{
d62a17ae 1743 /* If the auto route-target is in use we must remove it */
1744 evpn_export_rt_delete_auto(bgp, vpn);
90e60aa7 1745
d62a17ae 1746 listnode_add_sort(vpn->export_rtl, ecomadd);
1747 SET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
90e60aa7 1748
d62a17ae 1749 if (is_vni_live(vpn))
1750 bgp_evpn_handle_export_rt_change(bgp, vpn);
90e60aa7 1751}
1752
1753/*
1754 * Unconfigure the Export RT for a VNI (vty handler)
1755 */
d62a17ae 1756static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
1757 struct ecommunity *ecomdel)
1758{
1759 struct listnode *node, *nnode, *node_to_del;
1760 struct ecommunity *ecom;
1761
1762 /* Delete all export RTs */
1763 if (ecomdel == NULL) {
1764 /* Reset to default and process all routes. */
1765 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
1766 ecommunity_free(&ecom);
1767
1768 list_delete_all_node(vpn->export_rtl);
1769 }
1770
1771 /* Delete a specific export RT */
1772 else {
1773 node_to_del = NULL;
1774
1775 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
1776 if (ecommunity_match(ecom, ecomdel)) {
1777 ecommunity_free(&ecom);
1778 node_to_del = node;
1779 break;
1780 }
1781 }
1782
1783 if (node_to_del)
1784 list_delete_node(vpn->export_rtl, node_to_del);
1785 }
1786
1787 if (list_isempty(vpn->export_rtl)) {
1788 UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
1789 bgp_evpn_derive_auto_rt_export(bgp, vpn);
1790 }
1791
1792 if (is_vni_live(vpn))
1793 bgp_evpn_handle_export_rt_change(bgp, vpn);
90e60aa7 1794}
1795
676f83b9 1796/*
1797 * Configure RD for VRF
1798 */
996c9314 1799static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd)
676f83b9 1800{
1801 /* If we have already advertise type-5 routes with a diffrent RD, we
523cafc4 1802 * have to delete and withdraw them firs
1803 */
06d2e8f3 1804 bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
676f83b9 1805
1806 /* update RD */
1807 memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd));
1808 SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
1809
1810 /* We have a new RD for VRF.
523cafc4 1811 * Advertise all type-5 routes again with the new RD
1812 */
06d2e8f3 1813 bgp_evpn_handle_vrf_rd_change(bgp_vrf, 0);
676f83b9 1814}
1815
1816/*
1817 * Unconfigure RD for VRF
1818 */
1819static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
1820{
1821 /* If we have already advertise type-5 routes with a diffrent RD, we
523cafc4 1822 * have to delete and withdraw them firs
1823 */
06d2e8f3 1824 bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
676f83b9 1825
1826 /* fall back to default RD */
1827 bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
99b4e972 1828 UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
676f83b9 1829
1830 /* We have a new RD for VRF.
523cafc4 1831 * Advertise all type-5 routes again with the new RD
1832 */
06d2e8f3 1833 bgp_evpn_handle_vrf_rd_change(bgp_vrf, 0);
676f83b9 1834}
1835
90e60aa7 1836/*
1837 * Configure RD for a VNI (vty handler)
1838 */
d62a17ae 1839static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
1840 struct prefix_rd *rd)
90e60aa7 1841{
d62a17ae 1842 /* If the VNI is "live", we need to delete and withdraw this VNI's
1843 * local routes with the prior RD first. Then, after updating RD,
1844 * need to re-advertise.
1845 */
1846 if (is_vni_live(vpn))
1847 bgp_evpn_handle_rd_change(bgp, vpn, 1);
90e60aa7 1848
d62a17ae 1849 /* update RD */
1850 memcpy(&vpn->prd, rd, sizeof(struct prefix_rd));
1851 SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
90e60aa7 1852
d62a17ae 1853 if (is_vni_live(vpn))
1854 bgp_evpn_handle_rd_change(bgp, vpn, 0);
90e60aa7 1855}
1856
1857/*
1858 * Unconfigure RD for a VNI (vty handler)
1859 */
d62a17ae 1860static void evpn_unconfigure_rd(struct bgp *bgp, struct bgpevpn *vpn)
90e60aa7 1861{
d62a17ae 1862 /* If the VNI is "live", we need to delete and withdraw this VNI's
1863 * local routes with the prior RD first. Then, after resetting RD
1864 * to automatic value, need to re-advertise.
1865 */
1866 if (is_vni_live(vpn))
1867 bgp_evpn_handle_rd_change(bgp, vpn, 1);
90e60aa7 1868
d62a17ae 1869 /* reset RD to default */
1870 bgp_evpn_derive_auto_rd(bgp, vpn);
90e60aa7 1871
d62a17ae 1872 if (is_vni_live(vpn))
1873 bgp_evpn_handle_rd_change(bgp, vpn, 0);
90e60aa7 1874}
1875
1876/*
1877 * Create VNI, if not already present (VTY handler). Mark as configured.
1878 */
d62a17ae 1879static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
90e60aa7 1880{
d62a17ae 1881 struct bgpevpn *vpn;
90e60aa7 1882
d62a17ae 1883 if (!bgp->vnihash)
1884 return NULL;
90e60aa7 1885
d62a17ae 1886 vpn = bgp_evpn_lookup_vni(bgp, vni);
1887 if (!vpn) {
29c53922 1888 /* tenant vrf will be updated when we get local_vni_add from
523cafc4 1889 * zebra
1890 */
29c53922 1891 vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0);
d62a17ae 1892 if (!vpn) {
1893 zlog_err(
1894 "%u: Failed to allocate VNI entry for VNI %u - at Config",
1895 bgp->vrf_id, vni);
1896 return NULL;
1897 }
1898 }
90e60aa7 1899
d62a17ae 1900 /* Mark as configured. */
1901 SET_FLAG(vpn->flags, VNI_FLAG_CFGD);
1902 return vpn;
90e60aa7 1903}
1904
1905/*
1906 * Delete VNI. If VNI does not exist in the system (i.e., just
1907 * configuration), all that is needed is to free it. Otherwise,
1908 * any parameters configured for the VNI need to be reset (with
1909 * appropriate action) and the VNI marked as unconfigured; the
1910 * VNI will continue to exist, purely as a "learnt" entity.
1911 */
d62a17ae 1912static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn)
90e60aa7 1913{
d62a17ae 1914 assert(bgp->vnihash);
90e60aa7 1915
d62a17ae 1916 if (!is_vni_live(vpn)) {
1917 bgp_evpn_free(bgp, vpn);
1918 return 0;
1919 }
90e60aa7 1920
d62a17ae 1921 /* We need to take the unconfigure action for each parameter of this VNI
1922 * that is configured. Some optimization is possible, but not worth the
1923 * additional code for an operation that should be pretty rare.
1924 */
1925 UNSET_FLAG(vpn->flags, VNI_FLAG_CFGD);
90e60aa7 1926
d62a17ae 1927 /* First, deal with the export side - RD and export RT changes. */
1928 if (is_rd_configured(vpn))
1929 evpn_unconfigure_rd(bgp, vpn);
1930 if (is_export_rt_configured(vpn))
1931 evpn_unconfigure_export_rt(bgp, vpn, NULL);
90e60aa7 1932
d62a17ae 1933 /* Next, deal with the import side. */
1934 if (is_import_rt_configured(vpn))
1935 evpn_unconfigure_import_rt(bgp, vpn, NULL);
90e60aa7 1936
d62a17ae 1937 return 0;
90e60aa7 1938}
1939
10ebe1ab
MK
1940/*
1941 * Display import RT mapping to VRFs (vty handler)
1942 * bgp_def: default bgp instance
1943 */
996c9314 1944static void evpn_show_vrf_import_rts(struct vty *vty, struct bgp *bgp_def,
10ebe1ab
MK
1945 json_object *json)
1946{
1947 void *args[2];
1948
1949 args[0] = vty;
1950 args[1] = json;
1951
1952 hash_iterate(bgp_def->vrf_import_rt_hash,
996c9314
LB
1953 (void (*)(struct hash_backet *,
1954 void *))show_vrf_import_rt_entry,
10ebe1ab
MK
1955 args);
1956}
1957
520d5d76 1958/*
1959 * Display import RT mapping to VNIs (vty handler)
1960 */
9c92b5f7
MK
1961static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
1962 json_object *json)
520d5d76 1963{
9c92b5f7
MK
1964 void *args[2];
1965
1966 args[0] = vty;
1967 args[1] = json;
1968
d62a17ae 1969 hash_iterate(
1970 bgp->import_rt_hash,
1971 (void (*)(struct hash_backet *, void *))show_import_rt_entry,
9c92b5f7 1972 args);
520d5d76 1973}
1974
1975/*
1976 * Display EVPN routes for all VNIs - vty handler.
1977 */
d62a17ae 1978static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
60466a63 1979 struct in_addr vtep_ip, json_object *json)
520d5d76 1980{
d7c0a89a 1981 uint32_t num_vnis;
d62a17ae 1982 struct vni_walk_ctx wctx;
520d5d76 1983
d62a17ae 1984 num_vnis = hashcount(bgp->vnihash);
1985 if (!num_vnis)
1986 return;
1987 memset(&wctx, 0, sizeof(struct vni_walk_ctx));
1988 wctx.bgp = bgp;
1989 wctx.vty = vty;
1990 wctx.vtep_ip = vtep_ip;
9c92b5f7 1991 wctx.json = json;
9d303b37
DL
1992 hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *,
1993 void *))show_vni_routes_hash,
1994 &wctx);
520d5d76 1995}
1996
1997/*
1998 * Display EVPN routes for a VNI -- for specific type-3 route (vty handler).
1999 */
d62a17ae 2000static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
9c92b5f7
MK
2001 vni_t vni, struct in_addr orig_ip,
2002 json_object *json)
d62a17ae 2003{
2004 struct bgpevpn *vpn;
2005 struct prefix_evpn p;
2006 struct bgp_node *rn;
2007 struct bgp_info *ri;
d7c0a89a 2008 uint32_t path_cnt = 0;
d62a17ae 2009 afi_t afi;
2010 safi_t safi;
9c92b5f7 2011 json_object *json_paths = NULL;
d62a17ae 2012
2013 afi = AFI_L2VPN;
2014 safi = SAFI_EVPN;
2015
2016 /* Locate VNI. */
2017 vpn = bgp_evpn_lookup_vni(bgp, vni);
2018 if (!vpn) {
2019 vty_out(vty, "VNI not found\n");
2020 return;
2021 }
2022
2023 /* See if route exists. */
2024 build_evpn_type3_prefix(&p, orig_ip);
2025 rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
2026 if (!rn || !rn->info) {
9c92b5f7
MK
2027 if (!json)
2028 vty_out(vty, "%% Network not in table\n");
d62a17ae 2029 return;
2030 }
2031
9c92b5f7
MK
2032 if (json)
2033 json_paths = json_object_new_array();
2034
d62a17ae 2035 /* Prefix and num paths displayed once per prefix. */
9c92b5f7 2036 route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json);
d62a17ae 2037
2038 /* Display each path for this prefix. */
2039 for (ri = rn->info; ri; ri = ri->next) {
9c92b5f7
MK
2040 json_object *json_path = NULL;
2041
2042 if (json)
2043 json_path = json_object_new_array();
2044
2045 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
2046 json_path);
2047
2048 if (json)
2049 json_object_array_add(json_paths, json_path);
2050
d62a17ae 2051 path_cnt++;
2052 }
2053
9c92b5f7
MK
2054 if (json) {
2055 if (path_cnt)
2056 json_object_object_add(json, "paths", json_paths);
2057
2058 json_object_int_add(json, "numPaths", path_cnt);
2059 } else {
2060 vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
2061 path_cnt);
2062 }
520d5d76 2063}
2064
2065/*
2066 * Display EVPN routes for a VNI -- for specific MAC and/or IP (vty handler).
2067 * By definition, only matching type-2 route will be displayed.
2068 */
d62a17ae 2069static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
2070 vni_t vni, struct ethaddr *mac,
9c92b5f7 2071 struct ipaddr *ip, json_object *json)
d62a17ae 2072{
2073 struct bgpevpn *vpn;
2074 struct prefix_evpn p;
2075 struct bgp_node *rn;
2076 struct bgp_info *ri;
d7c0a89a 2077 uint32_t path_cnt = 0;
d62a17ae 2078 afi_t afi;
2079 safi_t safi;
9c92b5f7 2080 json_object *json_paths = NULL;
d62a17ae 2081
2082 afi = AFI_L2VPN;
2083 safi = SAFI_EVPN;
2084
2085 /* Locate VNI. */
2086 vpn = bgp_evpn_lookup_vni(bgp, vni);
2087 if (!vpn) {
9c92b5f7
MK
2088 if (!json)
2089 vty_out(vty, "VNI not found\n");
d62a17ae 2090 return;
2091 }
2092
2093 /* See if route exists. Look for both non-sticky and sticky. */
2094 build_evpn_type2_prefix(&p, mac, ip);
2095 rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
2096 if (!rn || !rn->info) {
9c92b5f7
MK
2097 if (!json)
2098 vty_out(vty, "%% Network not in table\n");
d62a17ae 2099 return;
2100 }
2101
9c92b5f7
MK
2102 if (json)
2103 json_paths = json_object_new_array();
2104
d62a17ae 2105 /* Prefix and num paths displayed once per prefix. */
9c92b5f7 2106 route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json);
d62a17ae 2107
2108 /* Display each path for this prefix. */
2109 for (ri = rn->info; ri; ri = ri->next) {
9c92b5f7
MK
2110 json_object *json_path = NULL;
2111
2112 if (json)
2113 json_path = json_object_new_array();
2114
2115 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
2116 json_path);
2117
2118 if (json)
2119 json_object_array_add(json_paths, json_path);
2120
d62a17ae 2121 path_cnt++;
2122 }
2123
9c92b5f7
MK
2124 if (json) {
2125 if (path_cnt)
2126 json_object_object_add(json, "paths", json_paths);
2127
2128 json_object_int_add(json, "numPaths", path_cnt);
2129 } else {
2130 vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
2131 path_cnt);
2132 }
520d5d76 2133}
2134
50f74cf1 2135/* Disaplay EVPN routes for a ESI - VTY handler */
2136static void evpn_show_routes_esi(struct vty *vty, struct bgp *bgp,
2137 esi_t *esi, json_object *json)
2138{
2139 struct evpnes *es = NULL;
2140
2141 /* locate the ES */
2142 es = bgp_evpn_lookup_es(bgp, esi);
2143 if (!es) {
2144 if (!json)
2145 vty_out(vty, "ESI not found\n");
2146 return;
2147 }
2148
2149 show_esi_routes(bgp, es, vty, json);
2150}
2151
520d5d76 2152/*
2153 * Display EVPN routes for a VNI - vty handler.
2154 * If 'type' is non-zero, only routes matching that type are shown.
2155 * If the vtep_ip is non zero, only routes behind that vtep are shown
2156 */
d62a17ae 2157static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
9c92b5f7
MK
2158 int type, struct in_addr vtep_ip,
2159 json_object *json)
520d5d76 2160{
d62a17ae 2161 struct bgpevpn *vpn;
520d5d76 2162
d62a17ae 2163 /* Locate VNI. */
2164 vpn = bgp_evpn_lookup_vni(bgp, vni);
2165 if (!vpn) {
9c92b5f7
MK
2166 if (!json)
2167 vty_out(vty, "VNI not found\n");
d62a17ae 2168 return;
2169 }
520d5d76 2170
d62a17ae 2171 /* Walk this VNI's route table and display appropriate routes. */
9c92b5f7 2172 show_vni_routes(bgp, vpn, type, vty, vtep_ip, json);
520d5d76 2173}
2174
2175/*
2176 * Display BGP EVPN routing table -- for specific RD and MAC and/or
2177 * IP (vty handler). By definition, only matching type-2 route will be
2178 * displayed.
2179 */
d62a17ae 2180static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
2181 struct prefix_rd *prd, struct ethaddr *mac,
9c92b5f7 2182 struct ipaddr *ip, json_object *json)
d62a17ae 2183{
2184 struct prefix_evpn p;
2185 struct bgp_node *rn;
2186 struct bgp_info *ri;
2187 afi_t afi;
2188 safi_t safi;
d7c0a89a 2189 uint32_t path_cnt = 0;
9c92b5f7
MK
2190 json_object *json_paths = NULL;
2191 char prefix_str[BUFSIZ];
d62a17ae 2192
2193 afi = AFI_L2VPN;
2194 safi = SAFI_EVPN;
2195
2196 /* See if route exists. Look for both non-sticky and sticky. */
2197 build_evpn_type2_prefix(&p, mac, ip);
2198 rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
2199 (struct prefix *)&p, prd);
2200 if (!rn || !rn->info) {
9c92b5f7
MK
2201 if (!json)
2202 vty_out(vty, "%% Network not in table\n");
d62a17ae 2203 return;
2204 }
2205
9c92b5f7
MK
2206 bgp_evpn_route2str((struct prefix_evpn *)&p, prefix_str,
2207 sizeof(prefix_str));
2208
d62a17ae 2209 /* Prefix and num paths displayed once per prefix. */
9c92b5f7
MK
2210 route_vty_out_detail_header(vty, bgp, rn, prd, afi, safi, json);
2211
2212 if (json)
2213 json_paths = json_object_new_array();
d62a17ae 2214
2215 /* Display each path for this prefix. */
2216 for (ri = rn->info; ri; ri = ri->next) {
9c92b5f7
MK
2217 json_object *json_path = NULL;
2218
2219 if (json)
2220 json_path = json_object_new_array();
2221
2222 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
2223 json_path);
2224
2225 if (json)
2226 json_object_array_add(json_paths, json_path);
2227
d62a17ae 2228 path_cnt++;
2229 }
2230
9c92b5f7
MK
2231 if (json && path_cnt) {
2232 if (path_cnt)
2233 json_object_object_add(json, prefix_str, json_paths);
2234 json_object_int_add(json, "numPaths", path_cnt);
2235 } else {
2236 vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
2237 path_cnt);
2238 }
520d5d76 2239}
2240
2241/*
2242 * Display BGP EVPN routing table -- for specific RD (vty handler)
2243 * If 'type' is non-zero, only routes matching that type are shown.
2244 */
d62a17ae 2245static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
9c92b5f7
MK
2246 struct prefix_rd *prd, int type,
2247 json_object *json)
d62a17ae 2248{
2249 struct bgp_node *rd_rn;
2250 struct bgp_table *table;
2251 struct bgp_node *rn;
2252 struct bgp_info *ri;
2253 int rd_header = 1;
2254 afi_t afi;
2255 safi_t safi;
d7c0a89a 2256 uint32_t prefix_cnt, path_cnt;
9c92b5f7
MK
2257 char rd_str[RD_ADDRSTRLEN];
2258 json_object *json_rd = NULL;
2259 int add_rd_to_json = 0;
d62a17ae 2260
2261 afi = AFI_L2VPN;
2262 safi = SAFI_EVPN;
2263 prefix_cnt = path_cnt = 0;
2264
9c92b5f7
MK
2265 prefix_rd2str((struct prefix_rd *)prd, rd_str, sizeof(rd_str));
2266
d62a17ae 2267 rd_rn = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)prd);
2268 if (!rd_rn)
2269 return;
9c92b5f7 2270
d62a17ae 2271 table = (struct bgp_table *)rd_rn->info;
2272 if (table == NULL)
2273 return;
2274
9c92b5f7
MK
2275 if (json) {
2276 json_rd = json_object_new_object();
2277 json_object_string_add(json_rd, "rd", rd_str);
2278 }
2279
d62a17ae 2280 /* Display all prefixes with this RD. */
2281 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
2282 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
9c92b5f7
MK
2283 json_object *json_prefix = NULL;
2284 json_object *json_paths = NULL;
2285 char prefix_str[BUFSIZ];
2286 int add_prefix_to_json = 0;
2287
2288 bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
2289 sizeof(prefix_str));
d62a17ae 2290
2291 if (type && evp->prefix.route_type != type)
2292 continue;
2293
9c92b5f7
MK
2294 if (json)
2295 json_prefix = json_object_new_object();
2296
d62a17ae 2297 if (rn->info) {
2298 /* RD header and legend - once overall. */
9c92b5f7 2299 if (rd_header && !json) {
d62a17ae 2300 vty_out(vty,
554cd77a 2301 "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]\n");
d62a17ae 2302 vty_out(vty,
342dd0c6 2303 "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
2304 vty_out(vty,
554cd77a 2305 "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
d62a17ae 2306 rd_header = 0;
2307 }
2308
2309 /* Prefix and num paths displayed once per prefix. */
2310 route_vty_out_detail_header(vty, bgp, rn, prd, afi,
9c92b5f7 2311 safi, json_prefix);
d62a17ae 2312
2313 prefix_cnt++;
2314 }
2315
9c92b5f7
MK
2316 if (json)
2317 json_paths = json_object_new_array();
2318
d62a17ae 2319 /* Display each path for this prefix. */
2320 for (ri = rn->info; ri; ri = ri->next) {
9c92b5f7
MK
2321 json_object *json_path = NULL;
2322
2323 if (json)
2324 json_path = json_object_new_array();
2325
d62a17ae 2326 route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
9c92b5f7
MK
2327 json_path);
2328
2329 if (json)
2330 json_object_array_add(json_paths, json_path);
2331
d62a17ae 2332 path_cnt++;
9c92b5f7
MK
2333 add_prefix_to_json = 1;
2334 add_rd_to_json = 1;
2335 }
2336
2337 if (json && add_prefix_to_json) {
2338 json_object_object_add(json_prefix, "paths",
2339 json_paths);
2340 json_object_object_add(json_rd, prefix_str,
2341 json_prefix);
d62a17ae 2342 }
2343 }
2344
9c92b5f7
MK
2345 if (json && add_rd_to_json)
2346 json_object_object_add(json, rd_str, json_rd);
2347
2348 if (json) {
2349 json_object_int_add(json, "numPrefix", prefix_cnt);
2350 json_object_int_add(json, "numPaths", path_cnt);
2351 } else {
2352 if (prefix_cnt == 0)
2353 vty_out(vty, "No prefixes exist with this RD%s\n",
2354 type ? " (of requested type)" : "");
2355 else
2356 vty_out(vty,
2357 "\nDisplayed %u prefixes (%u paths) with this RD%s\n",
2358 prefix_cnt, path_cnt,
2359 type ? " (of requested type)" : "");
2360 }
520d5d76 2361}
2362
2363/*
2364 * Display BGP EVPN routing table - all routes (vty handler).
2365 * If 'type' is non-zero, only routes matching that type are shown.
2366 */
9c92b5f7
MK
2367static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
2368 json_object *json)
d62a17ae 2369{
2370 struct bgp_node *rd_rn;
2371 struct bgp_table *table;
2372 struct bgp_node *rn;
2373 struct bgp_info *ri;
2374 int header = 1;
2375 int rd_header;
2376 afi_t afi;
2377 safi_t safi;
d7c0a89a 2378 uint32_t prefix_cnt, path_cnt;
d62a17ae 2379
2380 afi = AFI_L2VPN;
2381 safi = SAFI_EVPN;
2382 prefix_cnt = path_cnt = 0;
2383
2384 /* EVPN routing table is a 2-level table with the first level being
2385 * the RD.
2386 */
2387 for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn;
2388 rd_rn = bgp_route_next(rd_rn)) {
9c92b5f7
MK
2389 char rd_str[RD_ADDRSTRLEN];
2390 json_object *json_rd = NULL; /* contains routes for an RD */
2391 int add_rd_to_json = 0;
2dd32217 2392 uint64_t tbl_ver;
9c92b5f7 2393
d62a17ae 2394 table = (struct bgp_table *)rd_rn->info;
2395 if (table == NULL)
2396 continue;
2397
2dd32217 2398 tbl_ver = table->version;
9c92b5f7
MK
2399 prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str,
2400 sizeof(rd_str));
2401
2402 if (json) {
2403 json_rd = json_object_new_object();
2404 json_object_string_add(json_rd, "rd", rd_str);
2405 }
2406
d62a17ae 2407 rd_header = 1;
2408
2409 /* Display all prefixes for an RD */
2410 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
9c92b5f7
MK
2411 json_object *json_prefix =
2412 NULL; /* contains prefix under a RD */
2413 json_object *json_paths =
2414 NULL; /* array of paths under a prefix*/
d62a17ae 2415 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
9c92b5f7
MK
2416 char prefix_str[BUFSIZ];
2417 int add_prefix_to_json = 0;
2418
2419 bgp_evpn_route2str((struct prefix_evpn *)&rn->p,
2420 prefix_str, sizeof(prefix_str));
d62a17ae 2421
2422 if (type && evp->prefix.route_type != type)
2423 continue;
2424
2425 if (rn->info) {
2426 /* Overall header/legend displayed once. */
2427 if (header) {
9c92b5f7 2428 bgp_evpn_show_route_header(vty, bgp,
2dd32217 2429 tbl_ver,
9c92b5f7 2430 json);
d62a17ae 2431 header = 0;
2432 }
2433
2434 /* RD header - per RD. */
2435 if (rd_header) {
9c92b5f7
MK
2436 bgp_evpn_show_route_rd_header(
2437 vty, rd_rn, json);
d62a17ae 2438 rd_header = 0;
2439 }
2440
2441 prefix_cnt++;
2442 }
2443
9c92b5f7
MK
2444 if (json) {
2445 json_prefix = json_object_new_object();
2446 json_paths = json_object_new_array();
2447 json_object_string_add(json_prefix, "prefix",
2448 prefix_str);
2449 json_object_int_add(json_prefix, "prefixLen",
2450 rn->p.prefixlen);
2451 }
2452
d62a17ae 2453 /* For EVPN, the prefix is displayed for each path (to
2454 * fit in
2455 * with code that already exists).
2456 */
2457 for (ri = rn->info; ri; ri = ri->next) {
9c92b5f7 2458 json_object *json_path = NULL;
d62a17ae 2459 path_cnt++;
9c92b5f7
MK
2460 add_prefix_to_json = 1;
2461 add_rd_to_json = 1;
2462
2463 if (json)
2464 json_path = json_object_new_array();
2465
d62a17ae 2466 route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN,
9c92b5f7
MK
2467 json_path);
2468
2469 if (json)
2470 json_object_array_add(json_paths,
2471 json_path);
2472 }
2473
2474 if (json && add_prefix_to_json) {
2475 json_object_object_add(json_prefix, "paths",
2476 json_paths);
2477 json_object_object_add(json_rd, prefix_str,
2478 json_prefix);
d62a17ae 2479 }
2480 }
9c92b5f7
MK
2481
2482 if (json && add_rd_to_json)
2483 json_object_object_add(json, rd_str, json_rd);
d62a17ae 2484 }
2485
9c92b5f7
MK
2486 if (json) {
2487 json_object_int_add(json, "numPrefix", prefix_cnt);
2488 json_object_int_add(json, "numPaths", path_cnt);
2489 } else {
2490 if (prefix_cnt == 0) {
2491 vty_out(vty, "No EVPN prefixes %sexist\n",
2492 type ? "(of requested type) " : "");
2493 } else {
2494 vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
2495 prefix_cnt, path_cnt,
2496 type ? " (of requested type)" : "");
2497 }
2498 }
520d5d76 2499}
2500
50f74cf1 2501/* Display specific ES */
2502static void evpn_show_es(struct vty *vty, struct bgp *bgp, esi_t *esi,
2503 json_object *json)
2504{
2505 struct evpnes *es = NULL;
2506
2507 es = bgp_evpn_lookup_es(bgp, esi);
2508 if (es) {
2509 display_es(vty, es, json);
2510 } else {
2511 if (json) {
2512 vty_out(vty, "{}\n");
2513 } else {
2514 vty_out(vty, "ESI not found\n");
2515 return;
2516 }
2517 }
2518}
2519
2520/* Display all ESs */
2bb9eff4
DS
2521static void evpn_show_all_es(struct vty *vty, struct bgp *bgp,
2522 json_object *json)
50f74cf1 2523{
2524 void *args[2];
2525
2526 if (!json)
2527 vty_out(vty, "%-30s %-6s %-21s %-15s %-6s\n",
2528 "ESI", "Type", "RD", "Originator-IP", "#VTEPs");
2529
2530 /* print all ESs */
2531 args[0] = vty;
2532 args[1] = json;
2533 hash_iterate(bgp->esihash,
2534 (void (*)(struct hash_backet *, void *))show_es_entry,
2535 args);
2536}
2537
520d5d76 2538/*
2539 * Display specified VNI (vty handler)
2540 */
9c92b5f7
MK
2541static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
2542 json_object *json)
520d5d76 2543{
d7c0a89a 2544 uint8_t found = 0;
d62a17ae 2545 struct bgpevpn *vpn;
520d5d76 2546
d62a17ae 2547 vpn = bgp_evpn_lookup_vni(bgp, vni);
4cce389e
MK
2548 if (vpn) {
2549 found = 1;
2550 display_vni(vty, vpn, json);
2551 } else {
2552 struct bgp *bgp_temp;
2553 struct listnode *node = NULL;
2554
2555 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
2556 if (bgp_temp->l3vni == vni) {
2557 found = 1;
2558 display_l3vni(vty, bgp_temp, json);
2559 }
2560 }
2561 }
2562
2563 if (!found) {
9c92b5f7
MK
2564 if (json) {
2565 vty_out(vty, "{}\n");
2566 } else {
2567 vty_out(vty, "VNI not found\n");
2568 return;
2569 }
d62a17ae 2570 }
520d5d76 2571}
2572
2573/*
2574 * Display a VNI (upon user query).
2575 */
9c92b5f7
MK
2576static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
2577 json_object *json)
520d5d76 2578{
9c92b5f7 2579 void *args[2];
4cce389e
MK
2580 struct bgp *bgp_temp = NULL;
2581 struct listnode *node;
520d5d76 2582
9c92b5f7 2583
4cce389e 2584 if (!json) {
9c92b5f7 2585 vty_out(vty, "Flags: * - Kernel\n");
4cce389e 2586 vty_out(vty, " %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI",
996c9314 2587 "Type", "RD", "Import RT", "Export RT", "Tenant VRF");
9c92b5f7
MK
2588 }
2589
4cce389e 2590 /* print all L2 VNIS */
9c92b5f7
MK
2591 args[0] = vty;
2592 args[1] = json;
d62a17ae 2593 hash_iterate(bgp->vnihash,
2594 (void (*)(struct hash_backet *, void *))show_vni_entry,
9c92b5f7 2595 args);
4cce389e
MK
2596
2597 /* print all L3 VNIs */
2598 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp))
2599 show_l3vni_entry(vty, bgp_temp, json);
520d5d76 2600}
2601
1a98c087
MK
2602/*
2603 * evpn - enable advertisement of default g/w
2604 */
2605static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn)
2606{
2607 if (!vpn) {
2608 if (bgp->advertise_gw_macip)
2609 return;
2610
2611 bgp->advertise_gw_macip = 1;
2612 bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
2613 } else {
2614 if (vpn->advertise_gw_macip)
2615 return;
2616
2617 vpn->advertise_gw_macip = 1;
2618 bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
2619 vpn->vni);
2620 }
2621 return;
2622}
2623
2624/*
2625 * evpn - disable advertisement of default g/w
2626 */
2627static void evpn_unset_advertise_default_gw(struct bgp *bgp,
2628 struct bgpevpn *vpn)
2629{
2630 if (!vpn) {
2631 if (!bgp->advertise_gw_macip)
2632 return;
2633
2634 bgp->advertise_gw_macip = 0;
2635 bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
2636 } else {
2637 if (!vpn->advertise_gw_macip)
2638 return;
2639
2640 vpn->advertise_gw_macip = 0;
2641 bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
2642 vpn->vni);
2643 }
2644 return;
2645}
2646
486456ca
MK
2647/*
2648 * evpn - enable advertisement of default g/w
2649 */
2650static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf,
2651 afi_t afi, int add)
2652{
2653 struct prefix ip_prefix;
2654 safi_t safi = SAFI_UNICAST; /* ipv4/ipv6 unicast */
2655
2656 /* form the default prefix 0.0.0.0/0 */
2657 memset(&ip_prefix, 0, sizeof(struct prefix));
2658 ip_prefix.family = afi2family(afi);
2659 ip_prefix.prefixlen = 0;
2660
2661 if (add) {
2662 /* bail if we are already advertising default route */
2663 if (evpn_default_originate_set(bgp_vrf, afi, safi))
2664 return;
2665
2666 if (afi == AFI_IP)
2667 SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
2668 BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
2669 else if (afi == AFI_IP6)
2670 SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
2671 BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
2672 bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
2673 NULL, afi, safi);
2674 } else {
2675 /* bail out if we havent advertised the default route */
2676 if (!evpn_default_originate_set(bgp_vrf, afi, safi))
2677 return;
2678 if (afi == AFI_IP)
2679 UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
2680 BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
2681 else if (afi == AFI_IP6)
2682 UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
2683 BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
2684 bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
2685 afi, safi);
2686 }
2687}
2688
31310b25
MK
2689/*
2690 * evpn - enable advertisement of default g/w
2691 */
2692static void evpn_set_advertise_subnet(struct bgp *bgp,
2693 struct bgpevpn *vpn)
2694{
2695 if (vpn->advertise_subnet)
2696 return;
2697
2698 vpn->advertise_subnet = 1;
2699 bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
2700}
2701
2702/*
2703 * evpn - disable advertisement of default g/w
2704 */
996c9314 2705static void evpn_unset_advertise_subnet(struct bgp *bgp, struct bgpevpn *vpn)
31310b25
MK
2706{
2707 if (!vpn->advertise_subnet)
2708 return;
2709
2710 vpn->advertise_subnet = 0;
2711 bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
2712}
2713
7724c0a1 2714/*
2715 * EVPN (VNI advertisement) enabled. Register with zebra.
2716 */
d62a17ae 2717static void evpn_set_advertise_all_vni(struct bgp *bgp)
7724c0a1 2718{
d62a17ae 2719 bgp->advertise_all_vni = 1;
2720 bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
7724c0a1 2721}
2722
2723/*
2724 * EVPN (VNI advertisement) disabled. De-register with zebra. Cleanup VNI
2725 * cache, EVPN routes (delete and withdraw from peers).
2726 */
d62a17ae 2727static void evpn_unset_advertise_all_vni(struct bgp *bgp)
7724c0a1 2728{
d62a17ae 2729 bgp->advertise_all_vni = 0;
2730 bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
2731 bgp_evpn_cleanup_on_disable(bgp);
7724c0a1 2732}
bf1061d8
VB
2733
2734/*
2735 * EVPN - use RFC8365 to auto-derive RT
2736 */
2737static void evpn_set_advertise_autort_rfc8365(struct bgp *bgp)
2738{
2739 bgp->advertise_autort_rfc8365 = 1;
2740 bgp_evpn_handle_autort_change(bgp);
2741}
2742
2743/*
2744 * EVPN - don't use RFC8365 to auto-derive RT
2745 */
2746static void evpn_unset_advertise_autort_rfc8365(struct bgp *bgp)
2747{
2748 bgp->advertise_autort_rfc8365 = 0;
2749 bgp_evpn_handle_autort_change(bgp);
2750}
7724c0a1 2751
2b791107 2752static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
d62a17ae 2753{
06b9f471 2754 char buf1[RD_ADDRSTRLEN];
d62a17ae 2755 char *ecom_str;
2756 struct listnode *node, *nnode;
2757 struct ecommunity *ecom;
2758
2759 if (is_vni_configured(vpn)) {
d62a17ae 2760 vty_out(vty, " vni %d\n", vpn->vni);
2761 if (is_rd_configured(vpn))
2762 vty_out(vty, " rd %s\n",
06b9f471 2763 prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
d62a17ae 2764
2765 if (is_import_rt_configured(vpn)) {
2766 for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode,
2767 ecom)) {
2768 ecom_str = ecommunity_ecom2str(
2769 ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
2770 vty_out(vty, " route-target import %s\n",
2771 ecom_str);
2772 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
2773 }
2774 }
2775
2776 if (is_export_rt_configured(vpn)) {
2777 for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode,
2778 ecom)) {
2779 ecom_str = ecommunity_ecom2str(
2780 ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
640751c7 2781 vty_out(vty, " route-target export %s\n",
d62a17ae 2782 ecom_str);
2783 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
2784 }
2785 }
2786
1a98c087
MK
2787 if (vpn->advertise_gw_macip)
2788 vty_out(vty, " advertise-default-gw\n");
2789
31310b25
MK
2790 if (vpn->advertise_subnet)
2791 vty_out(vty, " advertise-subnet\n");
2792
d62a17ae 2793 vty_out(vty, " exit-vni\n");
2794 }
2795}
2796
1a98c087
MK
2797DEFUN (bgp_evpn_advertise_default_gw_vni,
2798 bgp_evpn_advertise_default_gw_vni_cmd,
2799 "advertise-default-gw",
078af92e 2800 "Advertise default g/w mac-ip routes in EVPN for a VNI\n")
1a98c087
MK
2801{
2802 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2803 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
2804
2805 if (!bgp)
2806 return CMD_WARNING;
2807
2808 if (!vpn)
2809 return CMD_WARNING;
2810
2811 evpn_set_advertise_default_gw(bgp, vpn);
2812
2813 return CMD_SUCCESS;
2814}
2815
2816DEFUN (no_bgp_evpn_advertise_default_vni_gw,
2817 no_bgp_evpn_advertise_default_gw_vni_cmd,
2818 "no advertise-default-gw",
2819 NO_STR
2820 "Withdraw default g/w mac-ip routes from EVPN for a VNI\n")
2821{
2822 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2823 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
2824
2825 if (!bgp)
2826 return CMD_WARNING;
2827
2828 if (!vpn)
2829 return CMD_WARNING;
2830
2831 evpn_unset_advertise_default_gw(bgp, vpn);
2832
2833 return CMD_SUCCESS;
2834}
2835
2836
2837DEFUN (bgp_evpn_advertise_default_gw,
2838 bgp_evpn_advertise_default_gw_cmd,
2839 "advertise-default-gw",
078af92e 2840 "Advertise All default g/w mac-ip routes in EVPN\n")
1a98c087
MK
2841{
2842 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2843
2844 if (!bgp)
2845 return CMD_WARNING;
2846
2847 evpn_set_advertise_default_gw(bgp, NULL);
2848
2849 return CMD_SUCCESS;
2850}
2851
2852DEFUN (no_bgp_evpn_advertise_default_gw,
2853 no_bgp_evpn_advertise_default_gw_cmd,
2854 "no advertise-default-gw",
2855 NO_STR
2856 "Withdraw All default g/w mac-ip routes from EVPN\n")
2857{
2858 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2859
2860 if (!bgp)
2861 return CMD_WARNING;
2862
2863 evpn_unset_advertise_default_gw(bgp, NULL);
2864
2865 return CMD_SUCCESS;
2866}
2867
7724c0a1 2868DEFUN (bgp_evpn_advertise_all_vni,
2869 bgp_evpn_advertise_all_vni_cmd,
2870 "advertise-all-vni",
2871 "Advertise All local VNIs\n")
2872{
d62a17ae 2873 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
7724c0a1 2874
d62a17ae 2875 if (!bgp)
2876 return CMD_WARNING;
2877 evpn_set_advertise_all_vni(bgp);
2878 return CMD_SUCCESS;
7724c0a1 2879}
2880
2881DEFUN (no_bgp_evpn_advertise_all_vni,
2882 no_bgp_evpn_advertise_all_vni_cmd,
2883 "no advertise-all-vni",
2884 NO_STR
2885 "Advertise All local VNIs\n")
2886{
d62a17ae 2887 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
7724c0a1 2888
d62a17ae 2889 if (!bgp)
2890 return CMD_WARNING;
2891 evpn_unset_advertise_all_vni(bgp);
2892 return CMD_SUCCESS;
7724c0a1 2893}
2894
bf1061d8
VB
2895DEFUN (bgp_evpn_advertise_autort_rfc8365,
2896 bgp_evpn_advertise_autort_rfc8365_cmd,
2897 "autort rfc8365-compatible",
2898 "Auto-derivation of RT\n"
2899 "Auto-derivation of RT using RFC8365\n")
2900{
2901 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2902
2903 if (!bgp)
2904 return CMD_WARNING;
2905 evpn_set_advertise_autort_rfc8365(bgp);
2906 return CMD_SUCCESS;
2907}
2908
2909DEFUN (no_bgp_evpn_advertise_autort_rfc8365,
2910 no_bgp_evpn_advertise_autort_rfc8365_cmd,
2911 "no autort rfc8365-compatible",
2912 NO_STR
2913 "Auto-derivation of RT\n"
2914 "Auto-derivation of RT using RFC8365\n")
2915{
2916 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2917
2918 if (!bgp)
2919 return CMD_WARNING;
2920 evpn_unset_advertise_autort_rfc8365(bgp);
2921 return CMD_SUCCESS;
2922}
2923
486456ca
MK
2924DEFUN (bgp_evpn_default_originate,
2925 bgp_evpn_default_originate_cmd,
2926 "default-originate <ipv4 | ipv6>",
2927 "originate a default route\n"
2928 "ipv4 address family\n"
2929 "ipv6 address family\n")
2930{
2931 afi_t afi = 0;
2932 int idx_afi = 0;
2933 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
2934
2935 if (!bgp_vrf)
2936 return CMD_WARNING;
2937 argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
2938 evpn_process_default_originate_cmd(bgp_vrf, afi, 1);
2939 return CMD_SUCCESS;
2940}
2941
2942DEFUN (no_bgp_evpn_default_originate,
2943 no_bgp_evpn_default_originate_cmd,
2944 "no default-originate <ipv4 | ipv6>",
2945 NO_STR
2946 "withdraw a default route\n"
2947 "ipv4 address family\n"
2948 "ipv6 address family\n")
2949{
2950 afi_t afi = 0;
2951 int idx_afi = 0;
2952 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
2953
2954 if (!bgp_vrf)
2955 return CMD_WARNING;
2956 argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
2957 evpn_process_default_originate_cmd(bgp_vrf, afi, 0);
2958 return CMD_SUCCESS;
2959}
2960
689b5101
MK
2961DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet,
2962 bgp_evpn_advertise_vni_subnet_cmd,
2963 "advertise-subnet",
2964 "Advertise the subnet corresponding to VNI\n")
31310b25
MK
2965{
2966 struct bgp *bgp_vrf = NULL;
2967 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2968 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
2969
2970 if (!bgp)
2971 return CMD_WARNING;
2972
2973 if (!vpn)
2974 return CMD_WARNING;
2975
2976 bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
2977 if (!bgp_vrf)
2978 return CMD_WARNING;
2979
31310b25
MK
2980 evpn_set_advertise_subnet(bgp, vpn);
2981 return CMD_SUCCESS;
2982}
2983
689b5101
MK
2984DEFUN_HIDDEN (no_bgp_evpn_advertise_vni_subnet,
2985 no_bgp_evpn_advertise_vni_subnet_cmd,
2986 "no advertise-subnet",
2987 NO_STR
2988 "Advertise All local VNIs\n")
31310b25
MK
2989{
2990 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
2991 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
2992
2993 if (!bgp)
2994 return CMD_WARNING;
2995
2996 if (!vpn)
2997 return CMD_WARNING;
2998
2999 evpn_unset_advertise_subnet(bgp, vpn);
3000 return CMD_SUCCESS;
3001}
3002
342dd0c6 3003DEFUN (bgp_evpn_advertise_type5,
3004 bgp_evpn_advertise_type5_cmd,
53c84f78 3005 "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [route-map WORD]",
342dd0c6 3006 "Advertise prefix routes\n"
053905d2 3007 BGP_AFI_HELP_STR
53c84f78
MK
3008 BGP_SAFI_HELP_STR
3009 "route-map for filtering specific routes\n"
3010 "Name of the route map\n")
342dd0c6 3011{
3012 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
053905d2
MK
3013 int idx_afi = 0;
3014 int idx_safi = 0;
53c84f78 3015 int idx_rmap = 0;
053905d2
MK
3016 afi_t afi = 0;
3017 safi_t safi = 0;
53c84f78
MK
3018 int ret = 0;
3019 int rmap_changed = 0;
053905d2
MK
3020
3021 argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
3022 argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
53c84f78
MK
3023 ret = argv_find(argv, argc, "route-map", &idx_rmap);
3024 if (ret) {
3025 if (!bgp_vrf->adv_cmd_rmap[afi][safi].name)
3026 rmap_changed = 1;
3027 else if (strcmp(argv[idx_rmap + 1]->arg,
996c9314
LB
3028 bgp_vrf->adv_cmd_rmap[afi][safi].name)
3029 != 0)
53c84f78
MK
3030 rmap_changed = 1;
3031 } else if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
3032 rmap_changed = 1;
3033 }
053905d2 3034
e779dc76 3035 if (!(afi == AFI_IP || afi == AFI_IP6)) {
053905d2
MK
3036 vty_out(vty,
3037 "%%only ipv4 or ipv6 address families are supported");
342dd0c6 3038 return CMD_WARNING;
3039 }
3040
053905d2
MK
3041 if (safi != SAFI_UNICAST) {
3042 vty_out(vty,
3043 "%%only ipv4 unicast or ipv6 unicast are supported");
3044 return CMD_WARNING;
3045 }
3046
3047 if (afi == AFI_IP) {
342dd0c6 3048
3049 /* if we are already advertising ipv4 prefix as type-5
523cafc4 3050 * nothing to do
3051 */
154faa50
MK
3052 if (!rmap_changed &&
3053 CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3054 BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
53c84f78 3055 return CMD_WARNING;
154faa50
MK
3056 SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3057 BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
342dd0c6 3058 } else {
3059
3060 /* if we are already advertising ipv6 prefix as type-5
523cafc4 3061 * nothing to do
3062 */
154faa50
MK
3063 if (!rmap_changed &&
3064 CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3065 BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
53c84f78 3066 return CMD_WARNING;
154faa50
MK
3067 SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3068 BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
53c84f78
MK
3069 }
3070
3071 if (rmap_changed) {
3072 bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
3073 if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
3074 XFREE(MTYPE_ROUTE_MAP_NAME,
3075 bgp_vrf->adv_cmd_rmap[afi][safi].name);
3076 bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
3077 bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
342dd0c6 3078 }
3079 }
53c84f78
MK
3080
3081 /* set the route-map for advertise command */
3082 if (ret && argv[idx_rmap + 1]->arg) {
3083 bgp_vrf->adv_cmd_rmap[afi][safi].name =
996c9314 3084 XSTRDUP(MTYPE_ROUTE_MAP_NAME, argv[idx_rmap + 1]->arg);
53c84f78
MK
3085 bgp_vrf->adv_cmd_rmap[afi][safi].map =
3086 route_map_lookup_by_name(argv[idx_rmap + 1]->arg);
3087 }
3088
3089 /* advertise type-5 routes */
3090 bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
342dd0c6 3091 return CMD_SUCCESS;
3092}
3093
3094DEFUN (no_bgp_evpn_advertise_type5,
3095 no_bgp_evpn_advertise_type5_cmd,
053905d2 3096 "no advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR,
342dd0c6 3097 NO_STR
3098 "Advertise prefix routes\n"
053905d2
MK
3099 BGP_AFI_HELP_STR
3100 BGP_SAFI_HELP_STR)
342dd0c6 3101{
3102 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
053905d2
MK
3103 int idx_afi = 0;
3104 int idx_safi = 0;
3105 afi_t afi = 0;
3106 safi_t safi = 0;
3107
3108 argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
3109 argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
3110
1ec31309 3111 if (!(afi == AFI_IP || afi == AFI_IP6)) {
053905d2
MK
3112 vty_out(vty,
3113 "%%only ipv4 or ipv6 address families are supported");
3114 return CMD_WARNING;
3115 }
3116
3117 if (safi != SAFI_UNICAST) {
3118 vty_out(vty,
3119 "%%only ipv4 unicast or ipv6 unicast are supported");
342dd0c6 3120 return CMD_WARNING;
3121 }
3122
053905d2 3123 if (afi == AFI_IP) {
342dd0c6 3124
fdf19f06 3125 /* if we are not advertising ipv4 prefix as type-5
523cafc4 3126 * nothing to do
3127 */
154faa50
MK
3128 if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3129 BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
053905d2 3130 bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
154faa50
MK
3131 UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3132 BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
342dd0c6 3133 }
3134 } else {
3135
fdf19f06 3136 /* if we are not advertising ipv6 prefix as type-5
523cafc4 3137 * nothing to do
3138 */
154faa50
MK
3139 if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
3140 BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
053905d2 3141 bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
d4f7497e 3142 UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
154faa50 3143 BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
342dd0c6 3144 }
3145 }
53c84f78
MK
3146
3147 /* clear the route-map information for advertise ipv4/ipv6 unicast */
3148 if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
3149 XFREE(MTYPE_ROUTE_MAP_NAME,
3150 bgp_vrf->adv_cmd_rmap[afi][safi].name);
3151 bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
3152 bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
3153 }
3154
342dd0c6 3155 return CMD_SUCCESS;
3156}
3157
f2d62262 3158/*
3159 * Display VNI information - for all or a specific VNI
3160 */
9c92b5f7
MK
3161DEFUN(show_bgp_l2vpn_evpn_vni,
3162 show_bgp_l2vpn_evpn_vni_cmd,
3163 "show bgp l2vpn evpn vni [(1-16777215)] [json]",
3164 SHOW_STR
3165 BGP_STR
3166 L2VPN_HELP_STR
3167 EVPN_HELP_STR
3168 "Show VNI\n"
3169 "VNI number\n"
3170 JSON_STR)
520d5d76 3171{
4cce389e 3172 struct bgp *bgp_def;
f2d62262 3173 vni_t vni;
3174 int idx = 0;
d7c0a89a 3175 uint8_t uj = 0;
9c92b5f7 3176 json_object *json = NULL;
d7c0a89a
QY
3177 uint32_t num_l2vnis = 0;
3178 uint32_t num_l3vnis = 0;
d4454626 3179 uint32_t num_vnis = 0;
4cce389e
MK
3180 struct listnode *node = NULL;
3181 struct bgp *bgp_temp = NULL;
9c92b5f7
MK
3182
3183 uj = use_json(argc, argv);
520d5d76 3184
4cce389e
MK
3185 bgp_def = bgp_get_default();
3186 if (!bgp_def)
d62a17ae 3187 return CMD_WARNING;
520d5d76 3188
f2d62262 3189 if (!argv_find(argv, argc, "evpn", &idx))
3190 return CMD_WARNING;
3191
9c92b5f7
MK
3192 if (uj)
3193 json = json_object_new_object();
1a98c087 3194
9c92b5f7 3195 if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
4cce389e
MK
3196
3197 num_l2vnis = hashcount(bgp_def->vnihash);
4cce389e
MK
3198
3199 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
3200 if (bgp_temp->l3vni)
3201 num_l3vnis++;
3202 }
d4454626 3203 num_vnis = num_l2vnis + num_l3vnis;
9c92b5f7
MK
3204 if (uj) {
3205 json_object_string_add(json, "advertiseGatewayMacip",
4cce389e 3206 bgp_def->advertise_gw_macip
9c92b5f7
MK
3207 ? "Enabled"
3208 : "Disabled");
3209 json_object_string_add(json, "advertiseAllVnis",
996c9314
LB
3210 is_evpn_enabled() ? "Enabled"
3211 : "Disabled");
d4454626 3212 json_object_int_add(json, "numVnis", num_vnis);
4cce389e
MK
3213 json_object_int_add(json, "numL2Vnis", num_l2vnis);
3214 json_object_int_add(json, "numL3Vnis", num_l3vnis);
9c92b5f7
MK
3215 } else {
3216 vty_out(vty, "Advertise Gateway Macip: %s\n",
4cce389e 3217 bgp_def->advertise_gw_macip ? "Enabled"
996c9314 3218 : "Disabled");
9c92b5f7 3219 vty_out(vty, "Advertise All VNI flag: %s\n",
94c2f693 3220 is_evpn_enabled() ? "Enabled" : "Disabled");
4cce389e
MK
3221 vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
3222 vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis);
9c92b5f7 3223 }
4cce389e 3224 evpn_show_all_vnis(vty, bgp_def, json);
f2d62262 3225 } else {
9c92b5f7
MK
3226 int vni_idx = 0;
3227
3228 if (!argv_find(argv, argc, "vni", &vni_idx))
3229 return CMD_WARNING;
3230
f2d62262 3231 /* Display specific VNI */
9c92b5f7 3232 vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
4cce389e 3233 evpn_show_vni(vty, bgp_def, vni, json);
9c92b5f7
MK
3234 }
3235
3236 if (uj) {
3237 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3238 json, JSON_C_TO_STRING_PRETTY));
3239 json_object_free(json);
f2d62262 3240 }
520d5d76 3241
d62a17ae 3242 return CMD_SUCCESS;
520d5d76 3243}
3244
50f74cf1 3245/* Disaply ES */
3246DEFUN(show_bgp_l2vpn_evpn_es,
3247 show_bgp_l2vpn_evpn_es_cmd,
3248 "show bgp l2vpn evpn es [ESI] [json]",
3249 SHOW_STR
3250 BGP_STR
3251 L2VPN_HELP_STR
3252 EVPN_HELP_STR
3253 "ethernet-Segment\n"
b482a7fd
QY
3254 "Ethernet-Segment Identifier\n"
3255 JSON_STR)
50f74cf1 3256{
3257 int idx = 0;
3258 uint8_t uj = 0;
3259 esi_t esi = {0};
3260 json_object *json = NULL;
3261 struct bgp *bgp = NULL;
3262
3263 uj = use_json(argc, argv);
3264
3265 bgp = bgp_get_default();
3266 if (!bgp)
3267 return CMD_WARNING;
3268
3269 if (!argv_find(argv, argc, "evpn", &idx))
3270 return CMD_WARNING;
3271
3272 if ((uj && argc == ((idx + 1) + 2)) ||
3273 (!uj && argc == (idx + 1) + 1)) {
3274
3275 /* show all ESs */
3276 evpn_show_all_es(vty, bgp, json);
3277 } else {
3278
3279 /* show a specific ES */
3280
3281 /* get the ESI - ESI-ID is at argv[5] */
3282 if (!str_to_esi(argv[idx + 2]->arg, &esi)) {
3283 vty_out(vty, "%% Malformed ESI\n");
3284 return CMD_WARNING;
3285 }
3286 evpn_show_es(vty, bgp, &esi, json);
3287 }
3288
3289 if (uj) {
3290 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3291 json, JSON_C_TO_STRING_PRETTY));
3292 json_object_free(json);
3293 }
3294
3295 return CMD_SUCCESS;
3296}
3297
f2d62262 3298/*
3299 * Display EVPN neighbor summary.
3300 */
9c92b5f7
MK
3301DEFUN(show_bgp_l2vpn_evpn_summary,
3302 show_bgp_l2vpn_evpn_summary_cmd,
ee851c8c 3303 "show bgp [vrf VRFNAME] l2vpn evpn summary [json]",
9c92b5f7
MK
3304 SHOW_STR
3305 BGP_STR
ee851c8c
MK
3306 "bgp vrf\n"
3307 "vrf name\n"
9c92b5f7
MK
3308 L2VPN_HELP_STR
3309 EVPN_HELP_STR
3310 "Summary of BGP neighbor status\n"
3311 JSON_STR)
520d5d76 3312{
ee851c8c 3313 int idx_vrf = 0;
d7c0a89a 3314 uint8_t uj = use_json(argc, argv);
ee851c8c
MK
3315 char *vrf = NULL;
3316
3317 if (argv_find(argv, argc, "vrf", &idx_vrf))
3318 vrf = argv[++idx_vrf]->arg;
3319 return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, uj);
520d5d76 3320}
3321
f2d62262 3322/*
3323 * Display global EVPN routing table.
3324 */
60466a63
QY
3325DEFUN(show_bgp_l2vpn_evpn_route,
3326 show_bgp_l2vpn_evpn_route_cmd,
50f74cf1 3327 "show bgp l2vpn evpn route [type <macip|multicast|es|prefix>] [json]",
9c92b5f7
MK
3328 SHOW_STR
3329 BGP_STR
3330 L2VPN_HELP_STR
3331 EVPN_HELP_STR
3332 "EVPN route information\n"
3333 "Specify Route type\n"
3334 "MAC-IP (Type-2) route\n"
3335 "Multicast (Type-3) route\n"
50f74cf1 3336 "Ethernet Segment (type-4) route \n"
3337 "Prefix (type-5 )route\n"
9c92b5f7 3338 JSON_STR)
520d5d76 3339{
d62a17ae 3340 struct bgp *bgp;
8367c327 3341 int type_idx = 0;
d62a17ae 3342 int type = 0;
d7c0a89a 3343 uint8_t uj = 0;
9c92b5f7
MK
3344 json_object *json = NULL;
3345
3346 uj = use_json(argc, argv);
520d5d76 3347
d62a17ae 3348 bgp = bgp_get_default();
3349 if (!bgp)
3350 return CMD_WARNING;
520d5d76 3351
9c92b5f7
MK
3352 if (uj)
3353 json = json_object_new_object();
f2d62262 3354
9c92b5f7
MK
3355 /* get the type */
3356 if (argv_find(argv, argc, "type", &type_idx)) {
f2d62262 3357 /* Specific type is requested */
9c92b5f7 3358 if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
d62a17ae 3359 type = BGP_EVPN_MAC_IP_ROUTE;
9c92b5f7 3360 else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
d62a17ae 3361 type = BGP_EVPN_IMET_ROUTE;
50f74cf1 3362 else if (strncmp(argv[type_idx + 1]->arg, "es", 2) == 0)
3363 type = BGP_EVPN_ES_ROUTE;
47b71369
MK
3364 else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
3365 type = BGP_EVPN_IP_PREFIX_ROUTE;
d62a17ae 3366 else
3367 return CMD_WARNING;
3368 }
520d5d76 3369
9c92b5f7
MK
3370 evpn_show_all_routes(vty, bgp, type, json);
3371
3372 if (uj) {
3373 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3374 json, JSON_C_TO_STRING_PRETTY));
3375 json_object_free(json);
3376 }
d62a17ae 3377 return CMD_SUCCESS;
520d5d76 3378}
3379
f2d62262 3380/*
3381 * Display global EVPN routing table for specific RD.
3382 */
60466a63
QY
3383DEFUN(show_bgp_l2vpn_evpn_route_rd,
3384 show_bgp_l2vpn_evpn_route_rd_cmd,
50f74cf1 3385 "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast|es|prefix>] [json]",
9c92b5f7
MK
3386 SHOW_STR
3387 BGP_STR
3388 L2VPN_HELP_STR
3389 EVPN_HELP_STR
3390 "EVPN route information\n"
3391 "Route Distinguisher\n"
3392 "ASN:XX or A.B.C.D:XX\n"
3393 "Specify Route type\n"
3394 "MAC-IP (Type-2) route\n"
3395 "Multicast (Type-3) route\n"
50f74cf1 3396 "Ethernet Segment route\n"
aa9db9e6 3397 "Prefix route\n"
9c92b5f7 3398 JSON_STR)
520d5d76 3399{
d62a17ae 3400 struct bgp *bgp;
3401 int ret;
3402 struct prefix_rd prd;
3403 int type = 0;
9c92b5f7
MK
3404 int rd_idx = 0;
3405 int type_idx = 0;
3406 int uj = 0;
3407 json_object *json = NULL;
520d5d76 3408
d62a17ae 3409 bgp = bgp_get_default();
3410 if (!bgp)
3411 return CMD_WARNING;
520d5d76 3412
9c92b5f7
MK
3413 /* check if we need json output */
3414 uj = use_json(argc, argv);
3415 if (uj)
3416 json = json_object_new_object();
f2d62262 3417
9c92b5f7
MK
3418 /* get the RD */
3419 if (argv_find(argv, argc, "rd", &rd_idx)) {
3420 ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd);
3421
3422 if (!ret) {
3423 vty_out(vty, "%% Malformed Route Distinguisher\n");
3424 return CMD_WARNING;
3425 }
d62a17ae 3426 }
520d5d76 3427
9c92b5f7
MK
3428 /* get the type */
3429 if (argv_find(argv, argc, "type", &type_idx)) {
f2d62262 3430 /* Specific type is requested */
9c92b5f7 3431 if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
d62a17ae 3432 type = BGP_EVPN_MAC_IP_ROUTE;
9c92b5f7 3433 else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
d62a17ae 3434 type = BGP_EVPN_IMET_ROUTE;
aa9db9e6
MK
3435 else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
3436 type = BGP_EVPN_IP_PREFIX_ROUTE;
d62a17ae 3437 else
3438 return CMD_WARNING;
3439 }
520d5d76 3440
9c92b5f7
MK
3441 evpn_show_route_rd(vty, bgp, &prd, type, json);
3442
3443 if (uj) {
3444 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3445 json, JSON_C_TO_STRING_PRETTY));
3446 json_object_free(json);
3447 }
3448
d62a17ae 3449 return CMD_SUCCESS;
520d5d76 3450}
3451
f2d62262 3452/*
3453 * Display global EVPN routing table for specific RD and MACIP.
3454 */
9c92b5f7
MK
3455DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
3456 show_bgp_l2vpn_evpn_route_rd_macip_cmd,
d114b977 3457 "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN mac WORD [ip WORD] [json]",
9c92b5f7
MK
3458 SHOW_STR
3459 BGP_STR
3460 L2VPN_HELP_STR
3461 EVPN_HELP_STR
3462 "EVPN route information\n"
3463 "Route Distinguisher\n"
3464 "ASN:XX or A.B.C.D:XX\n"
3465 "MAC\n"
3466 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
3467 "IP\n"
3468 "IP address (IPv4 or IPv6)\n"
3469 JSON_STR)
3470{
0291c246
MK
3471 struct bgp *bgp;
3472 int ret;
3473 struct prefix_rd prd;
3474 struct ethaddr mac;
3475 struct ipaddr ip;
3476 int rd_idx = 0;
3477 int mac_idx = 0;
3478 int ip_idx = 0;
3479 int uj = 0;
3480 json_object *json = NULL;
9c92b5f7
MK
3481
3482 memset(&mac, 0, sizeof(struct ethaddr));
3483 memset(&ip, 0, sizeof(struct ipaddr));
d62a17ae 3484
3485 bgp = bgp_get_default();
3486 if (!bgp)
3487 return CMD_WARNING;
3488
9c92b5f7
MK
3489 /* check if we need json output */
3490 uj = use_json(argc, argv);
3491 if (uj)
3492 json = json_object_new_object();
f2d62262 3493
9c92b5f7
MK
3494 /* get the prd */
3495 if (argv_find(argv, argc, "rd", &rd_idx)) {
3496 ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd);
3497 if (!ret) {
3498 vty_out(vty, "%% Malformed Route Distinguisher\n");
3499 return CMD_WARNING;
3500 }
d62a17ae 3501 }
9c92b5f7
MK
3502
3503 /* get the mac */
3504 if (argv_find(argv, argc, "mac", &mac_idx)) {
3505 if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) {
3506 vty_out(vty, "%% Malformed MAC address\n");
3507 return CMD_WARNING;
3508 }
d62a17ae 3509 }
9c92b5f7
MK
3510
3511 /* get the ip if specified */
3512 if (argv_find(argv, argc, "ip", &ip_idx)) {
3513 if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) {
d62a17ae 3514 vty_out(vty, "%% Malformed IP address\n");
3515 return CMD_WARNING;
3516 }
3517 }
3518
9c92b5f7
MK
3519 evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json);
3520
3521 if (uj) {
3522 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3523 json, JSON_C_TO_STRING_PRETTY));
3524 json_object_free(json);
3525 }
3526
d62a17ae 3527 return CMD_SUCCESS;
520d5d76 3528}
3529
50f74cf1 3530/* Display per ESI routing table */
3531DEFUN(show_bgp_l2vpn_evpn_route_esi,
3532 show_bgp_l2vpn_evpn_route_esi_cmd,
3533 "show bgp l2vpn evpn route esi ESI [json]",
3534 SHOW_STR
3535 BGP_STR
3536 L2VPN_HELP_STR
3537 EVPN_HELP_STR
3538 "EVPN route information\n"
3539 "Ethernet Segment Identifier\n"
3540 "ESI ID\n"
3541 JSON_STR)
3542{
3543 int uj = 0;
3544 esi_t esi = {0};
3545 struct bgp *bgp = NULL;
3546 json_object *json = NULL;
3547
3548 bgp = bgp_get_default();
3549 if (!bgp)
3550 return CMD_WARNING;
3551
3552 uj = use_json(argc, argv);
3553 if (uj)
3554 json = json_object_new_object();
3555
3556 /* get the ESI - ESI-ID is at argv[6] */
3557 if (!str_to_esi(argv[6]->arg, &esi)) {
3558 vty_out(vty, "%% Malformed ESI\n");
3559 return CMD_WARNING;
3560 }
3561
3562 evpn_show_routes_esi(vty, bgp, &esi, json);
3563
3564 if (uj) {
3565 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3566 json, JSON_C_TO_STRING_PRETTY));
3567 json_object_free(json);
3568 }
3569
3570 return CMD_SUCCESS;
3571}
3572
3573
f2d62262 3574/*
3575 * Display per-VNI EVPN routing table.
3576 */
9c92b5f7
MK
3577DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd,
3578 "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>] [json]",
3579 SHOW_STR
3580 BGP_STR
3581 L2VPN_HELP_STR
3582 EVPN_HELP_STR
3583 "EVPN route information\n"
3584 "VXLAN Network Identifier\n"
3585 "VNI number\n"
3586 "Specify Route type\n"
3587 "MAC-IP (Type-2) route\n"
3588 "Multicast (Type-3) route\n"
3589 "Remote VTEP\n"
3590 "Remote VTEP IP address\n"
3591 JSON_STR)
520d5d76 3592{
d62a17ae 3593 vni_t vni;
3594 struct bgp *bgp;
3595 struct in_addr vtep_ip;
3596 int type = 0;
f2d62262 3597 int idx = 0;
9c92b5f7
MK
3598 int uj = 0;
3599 json_object *json = NULL;
d62a17ae 3600
3601 bgp = bgp_get_default();
3602 if (!bgp)
3603 return CMD_WARNING;
3604
9c92b5f7
MK
3605 /* check if we need json output */
3606 uj = use_json(argc, argv);
3607 if (uj)
3608 json = json_object_new_object();
3609
f2d62262 3610 if (!argv_find(argv, argc, "evpn", &idx))
3611 return CMD_WARNING;
3612
d62a17ae 3613 vtep_ip.s_addr = 0;
3614
f2d62262 3615 vni = strtoul(argv[idx + 3]->arg, NULL, 10);
d62a17ae 3616
9c92b5f7
MK
3617 if ((!uj && ((argc == (idx + 1 + 5)) && argv[idx + 4]->arg))
3618 || (uj && ((argc == (idx + 1 + 6)) && argv[idx + 4]->arg))) {
f2d62262 3619 if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) {
3620 if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0)
d62a17ae 3621 type = BGP_EVPN_MAC_IP_ROUTE;
f2d62262 3622 else if (strncmp(argv[idx + 5]->arg, "mu", 2) == 0)
d62a17ae 3623 type = BGP_EVPN_IMET_ROUTE;
3624 else
3625 return CMD_WARNING;
f2d62262 3626 } else if (strncmp(argv[idx + 4]->arg, "vtep", 4) == 0) {
3627 if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
d62a17ae 3628 vty_out(vty, "%% Malformed VTEP IP address\n");
3629 return CMD_WARNING;
3630 }
3631 } else
3632 return CMD_WARNING;
3633 }
3634
9c92b5f7
MK
3635 evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json);
3636
3637 if (uj) {
3638 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3639 json, JSON_C_TO_STRING_PRETTY));
3640 json_object_free(json);
3641 }
3642
d62a17ae 3643 return CMD_SUCCESS;
520d5d76 3644}
3645
f2d62262 3646/*
3647 * Display per-VNI EVPN routing table for specific MACIP.
3648 */
9c92b5f7
MK
3649DEFUN(show_bgp_l2vpn_evpn_route_vni_macip,
3650 show_bgp_l2vpn_evpn_route_vni_macip_cmd,
3651 "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD] [json]",
3652 SHOW_STR
3653 BGP_STR
3654 L2VPN_HELP_STR
3655 EVPN_HELP_STR
3656 "EVPN route information\n"
3657 "VXLAN Network Identifier\n"
3658 "VNI number\n"
3659 "MAC\n"
3660 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
3661 "IP\n"
3662 "IP address (IPv4 or IPv6)\n"
3663 JSON_STR)
520d5d76 3664{
d62a17ae 3665 vni_t vni;
3666 struct bgp *bgp;
3667 struct ethaddr mac;
3668 struct ipaddr ip;
f2d62262 3669 int idx = 0;
9c92b5f7
MK
3670 int uj = 0;
3671 json_object *json = NULL;
d62a17ae 3672
3673 bgp = bgp_get_default();
3674 if (!bgp)
3675 return CMD_WARNING;
3676
9c92b5f7
MK
3677 /* check if we need json output */
3678 uj = use_json(argc, argv);
3679 if (uj)
3680 json = json_object_new_object();
3681
f2d62262 3682 if (!argv_find(argv, argc, "evpn", &idx))
3683 return CMD_WARNING;
3684
9c92b5f7 3685 /* get the VNI */
f2d62262 3686 vni = strtoul(argv[idx + 3]->arg, NULL, 10);
9c92b5f7
MK
3687
3688 /* get the mac */
f2d62262 3689 if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
d62a17ae 3690 vty_out(vty, "%% Malformed MAC address\n");
3691 return CMD_WARNING;
3692 }
9c92b5f7
MK
3693
3694 /* get the ip */
d62a17ae 3695 memset(&ip, 0, sizeof(ip));
9c92b5f7
MK
3696 if ((!uj && ((argc == (idx + 1 + 7)) && argv[idx + 7]->arg != NULL))
3697 || (uj
3698 && ((argc == (idx + 1 + 8)) && argv[idx + 7]->arg != NULL))) {
f2d62262 3699 if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) {
d62a17ae 3700 vty_out(vty, "%% Malformed IP address\n");
3701 return CMD_WARNING;
3702 }
3703 }
3704
9c92b5f7
MK
3705 evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip, json);
3706
3707 if (uj) {
3708 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3709 json, JSON_C_TO_STRING_PRETTY));
3710 json_object_free(json);
3711 }
3712
d62a17ae 3713 return CMD_SUCCESS;
520d5d76 3714}
3715
f2d62262 3716/*
3717 * Display per-VNI EVPN routing table for specific multicast IP (remote VTEP).
3718 */
9c92b5f7
MK
3719DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast,
3720 show_bgp_l2vpn_evpn_route_vni_multicast_cmd,
3721 "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D [json]",
3722 SHOW_STR
3723 BGP_STR
3724 L2VPN_HELP_STR
3725 EVPN_HELP_STR
3726 "EVPN route information\n"
3727 "VXLAN Network Identifier\n"
3728 "VNI number\n"
3729 "Multicast (Type-3) route\n"
3730 "Originating Router IP address\n"
3731 JSON_STR)
520d5d76 3732{
d62a17ae 3733 vni_t vni;
3734 struct bgp *bgp;
3735 int ret;
3736 struct in_addr orig_ip;
f2d62262 3737 int idx = 0;
9c92b5f7
MK
3738 int uj = 0;
3739 json_object *json = NULL;
520d5d76 3740
d62a17ae 3741 bgp = bgp_get_default();
3742 if (!bgp)
3743 return CMD_WARNING;
520d5d76 3744
9c92b5f7
MK
3745 /* check if we need json output */
3746 uj = use_json(argc, argv);
3747 if (uj)
3748 json = json_object_new_object();
3749
f2d62262 3750 if (!argv_find(argv, argc, "evpn", &idx))
3751 return CMD_WARNING;
3752
9c92b5f7 3753 /* get the VNI */
f2d62262 3754 vni = strtoul(argv[idx + 3]->arg, NULL, 10);
9c92b5f7
MK
3755
3756 /* get the ip */
f2d62262 3757 ret = inet_aton(argv[idx + 5]->arg, &orig_ip);
d62a17ae 3758 if (!ret) {
3759 vty_out(vty, "%% Malformed Originating Router IP address\n");
3760 return CMD_WARNING;
3761 }
520d5d76 3762
9c92b5f7
MK
3763 evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip, json);
3764
3765 if (uj) {
3766 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3767 json, JSON_C_TO_STRING_PRETTY));
3768 json_object_free(json);
3769 }
3770
d62a17ae 3771 return CMD_SUCCESS;
520d5d76 3772}
3773
f2d62262 3774/*
3775 * Display per-VNI EVPN routing table - for all VNIs.
3776 */
60466a63
QY
3777DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
3778 show_bgp_l2vpn_evpn_route_vni_all_cmd,
9c92b5f7
MK
3779 "show bgp l2vpn evpn route vni all [vtep A.B.C.D] [json]",
3780 SHOW_STR
3781 BGP_STR
3782 L2VPN_HELP_STR
3783 EVPN_HELP_STR
3784 "EVPN route information\n"
3785 "VXLAN Network Identifier\n"
3786 "All VNIs\n"
3787 "Remote VTEP\n"
3788 "Remote VTEP IP address\n"
3789 JSON_STR)
520d5d76 3790{
d62a17ae 3791 struct bgp *bgp;
3792 struct in_addr vtep_ip;
f2d62262 3793 int idx = 0;
9c92b5f7
MK
3794 int uj = 0;
3795 json_object *json = NULL;
520d5d76 3796
d62a17ae 3797 bgp = bgp_get_default();
3798 if (!bgp)
3799 return CMD_WARNING;
520d5d76 3800
9c92b5f7
MK
3801 /* check if we need json output */
3802 uj = use_json(argc, argv);
3803 if (uj)
3804 json = json_object_new_object();
3805
f2d62262 3806 if (!argv_find(argv, argc, "evpn", &idx))
3807 return CMD_WARNING;
3808
d62a17ae 3809 vtep_ip.s_addr = 0;
9c92b5f7
MK
3810 if ((!uj && (argc == (idx + 1 + 5) && argv[idx + 5]->arg))
3811 || (uj && (argc == (idx + 1 + 6) && argv[idx + 5]->arg))) {
f2d62262 3812 if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
d62a17ae 3813 vty_out(vty, "%% Malformed VTEP IP address\n");
3814 return CMD_WARNING;
3815 }
3816 }
520d5d76 3817
9c92b5f7
MK
3818 evpn_show_routes_vni_all(vty, bgp, vtep_ip, json);
3819
3820 if (uj) {
3821 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3822 json, JSON_C_TO_STRING_PRETTY));
3823 json_object_free(json);
3824 }
3825
d62a17ae 3826 return CMD_SUCCESS;
520d5d76 3827}
3828
10ebe1ab
MK
3829/*
3830 * Display EVPN import route-target hash table
3831 */
3832DEFUN(show_bgp_l2vpn_evpn_vrf_import_rt,
3833 show_bgp_l2vpn_evpn_vrf_import_rt_cmd,
3834 "show bgp l2vpn evpn vrf-import-rt [json]",
3835 SHOW_STR
3836 BGP_STR
3837 L2VPN_HELP_STR
3838 EVPN_HELP_STR
3839 "Show vrf import route target\n"
3840 JSON_STR)
3841{
d7c0a89a 3842 uint8_t uj = 0;
181c08c6 3843 struct bgp *bgp_def = NULL;
10ebe1ab
MK
3844 json_object *json = NULL;
3845
3846 bgp_def = bgp_get_default();
3847 if (!bgp_def)
3848 return CMD_WARNING;
3849
3850 uj = use_json(argc, argv);
3851 if (uj)
3852 json = json_object_new_object();
3853
3854 evpn_show_vrf_import_rts(vty, bgp_def, json);
3855
3856 if (uj) {
3857 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3858 json, JSON_C_TO_STRING_PRETTY));
3859 json_object_free(json);
3860 }
3861
3862 return CMD_SUCCESS;
3863}
3864
f2d62262 3865/*
3866 * Display EVPN import route-target hash table
3867 */
60466a63
QY
3868DEFUN(show_bgp_l2vpn_evpn_import_rt,
3869 show_bgp_l2vpn_evpn_import_rt_cmd,
9c92b5f7
MK
3870 "show bgp l2vpn evpn import-rt [json]",
3871 SHOW_STR
3872 BGP_STR
3873 L2VPN_HELP_STR
3874 EVPN_HELP_STR
3875 "Show import route target\n"
3876 JSON_STR)
520d5d76 3877{
d62a17ae 3878 struct bgp *bgp;
d7c0a89a 3879 uint8_t uj = 0;
9c92b5f7 3880 json_object *json = NULL;
520d5d76 3881
d62a17ae 3882 bgp = bgp_get_default();
3883 if (!bgp)
3884 return CMD_WARNING;
520d5d76 3885
9c92b5f7
MK
3886 uj = use_json(argc, argv);
3887 if (uj)
3888 json = json_object_new_object();
3889
3890 evpn_show_import_rts(vty, bgp, json);
3891
3892 if (uj) {
3893 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3894 json, JSON_C_TO_STRING_PRETTY));
3895 json_object_free(json);
3896 }
3897
d62a17ae 3898 return CMD_SUCCESS;
520d5d76 3899}
3900
50f74cf1 3901DEFUN(test_adv_evpn_type4_route,
3902 test_adv_evpn_type4_route_cmd,
3903 "advertise es ESI",
3904 "Advertise EVPN ES route\n"
3905 "Ethernet-segment\n"
3906 "Ethernet-Segment Identifier\n")
3907{
3908 int ret = 0;
3909 esi_t esi;
3910 struct bgp *bgp;
3911 struct ipaddr vtep_ip;
3912
3913 bgp = bgp_get_default();
3914 if (!bgp) {
3915 vty_out(vty, "%%Default BGP instance not yet created\n");
3916 return CMD_WARNING;
3917 }
3918
2bb9eff4 3919 if (!str_to_esi(argv[2]->arg, &esi)) {
50f74cf1 3920 vty_out(vty, "%%Malformed ESI\n");
3921 return CMD_WARNING;
3922 }
3923
3924 vtep_ip.ipa_type = IPADDR_V4;
3925 vtep_ip.ipaddr_v4 = bgp->router_id;
3926
3927 ret = bgp_evpn_local_es_add(bgp, &esi, &vtep_ip);
3928 if (ret == -1) {
3929 vty_out(vty, "%%Failed to EVPN advertise type-4 route\n");
3930 return CMD_WARNING;
3931 }
3932 return CMD_SUCCESS;
3933}
3934
3935DEFUN(test_withdraw_evpn_type4_route,
3936 test_withdraw_evpn_type4_route_cmd,
3937 "withdraw es ESI",
3938 "Advertise EVPN ES route\n"
3939 "Ethernet-segment\n"
3940 "Ethernet-Segment Identifier\n")
3941{
3942 int ret = 0;
3943 esi_t esi;
3944 struct bgp *bgp;
3945 struct ipaddr vtep_ip;
3946
3947 bgp = bgp_get_default();
3948 if (!bgp) {
3949 vty_out(vty, "%%Default BGP instance not yet created\n");
3950 return CMD_WARNING;
3951 }
3952
3953 if (!bgp->peer_self) {
3954 vty_out(vty, "%%BGP instance doesnt have self peer\n");
3955 return CMD_WARNING;
3956 }
3957
2bb9eff4 3958 if (!str_to_esi(argv[2]->arg, &esi)) {
50f74cf1 3959 vty_out(vty, "%%Malformed ESI\n");
3960 return CMD_WARNING;
3961 }
3962
3963 vtep_ip.ipa_type = IPADDR_V4;
3964 vtep_ip.ipaddr_v4 = bgp->router_id;
3965 ret = bgp_evpn_local_es_del(bgp, &esi, &vtep_ip);
3966 if (ret == -1) {
3967 vty_out(vty, "%%Failed to withdraw EVPN type-4 route\n");
3968 return CMD_WARNING;
3969 }
3970 return CMD_SUCCESS;
3971}
3972
5014d96f
DW
3973ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd,
3974 "show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR
3975 "Show VNI\n"
3976 "VNI number\n")
3977
3978ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd,
3979 "show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR
996c9314 3980 "Summary of BGP neighbor status\n" JSON_STR)
5014d96f
DW
3981
3982ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd,
3983 "show bgp evpn route [type <macip|multicast>]",
3984 SHOW_STR BGP_STR EVPN_HELP_STR
3985 "EVPN route information\n"
3986 "Specify Route type\n"
3987 "MAC-IP (Type-2) route\n"
3988 "Multicast (Type-3) route\n")
3989
3990ALIAS_HIDDEN(
3991 show_bgp_l2vpn_evpn_route_rd, show_bgp_evpn_route_rd_cmd,
d114b977 3992 "show bgp evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast>]",
5014d96f
DW
3993 SHOW_STR BGP_STR EVPN_HELP_STR
3994 "EVPN route information\n"
3995 "Route Distinguisher\n"
3996 "ASN:XX or A.B.C.D:XX\n"
3997 "Specify Route type\n"
3998 "MAC-IP (Type-2) route\n"
3999 "Multicast (Type-3) route\n")
4000
4001ALIAS_HIDDEN(
4002 show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_evpn_route_rd_macip_cmd,
d114b977 4003 "show bgp evpn route rd ASN:NN_OR_IP-ADDRESS:NN mac WORD [ip WORD]",
5014d96f
DW
4004 SHOW_STR BGP_STR EVPN_HELP_STR
4005 "EVPN route information\n"
4006 "Route Distinguisher\n"
4007 "ASN:XX or A.B.C.D:XX\n"
4008 "MAC\n"
4009 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
4010 "IP\n"
4011 "IP address (IPv4 or IPv6)\n")
4012
4013ALIAS_HIDDEN(
4014 show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd,
4015 "show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
4016 SHOW_STR BGP_STR EVPN_HELP_STR
4017 "EVPN route information\n"
4018 "VXLAN Network Identifier\n"
4019 "VNI number\n"
4020 "Specify Route type\n"
4021 "MAC-IP (Type-2) route\n"
4022 "Multicast (Type-3) route\n"
4023 "Remote VTEP\n"
4024 "Remote VTEP IP address\n")
4025
4026ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip,
4027 show_bgp_evpn_route_vni_macip_cmd,
4028 "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]",
4029 SHOW_STR BGP_STR EVPN_HELP_STR
4030 "EVPN route information\n"
4031 "VXLAN Network Identifier\n"
4032 "VNI number\n"
4033 "MAC\n"
4034 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
4035 "IP\n"
4036 "IP address (IPv4 or IPv6)\n")
4037
4038ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast,
4039 show_bgp_evpn_route_vni_multicast_cmd,
4040 "show bgp evpn route vni (1-16777215) multicast A.B.C.D",
4041 SHOW_STR BGP_STR EVPN_HELP_STR
4042 "EVPN route information\n"
4043 "VXLAN Network Identifier\n"
4044 "VNI number\n"
4045 "Multicast (Type-3) route\n"
4046 "Originating Router IP address\n")
4047
4048ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
4049 "show bgp evpn route vni all [vtep A.B.C.D]",
4050 SHOW_STR BGP_STR EVPN_HELP_STR
4051 "EVPN route information\n"
4052 "VXLAN Network Identifier\n"
4053 "All VNIs\n"
4054 "Remote VTEP\n"
4055 "Remote VTEP IP address\n")
4056
4057ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd,
4058 "show bgp evpn import-rt",
4059 SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n")
5014d96f 4060
90e60aa7 4061DEFUN_NOSH (bgp_evpn_vni,
4062 bgp_evpn_vni_cmd,
4063 "vni (1-16777215)",
4064 "VXLAN Network Identifier\n"
4065 "VNI number\n")
4066{
d62a17ae 4067 vni_t vni;
4068 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4069 struct bgpevpn *vpn;
90e60aa7 4070
d62a17ae 4071 if (!bgp)
4072 return CMD_WARNING;
90e60aa7 4073
d62a17ae 4074 vni = strtoul(argv[1]->arg, NULL, 10);
90e60aa7 4075
d62a17ae 4076 /* Create VNI, or mark as configured. */
4077 vpn = evpn_create_update_vni(bgp, vni);
4078 if (!vpn) {
4079 vty_out(vty, "%% Failed to create VNI \n");
4080 return CMD_WARNING;
4081 }
90e60aa7 4082
d62a17ae 4083 VTY_PUSH_CONTEXT_SUB(BGP_EVPN_VNI_NODE, vpn);
4084 return CMD_SUCCESS;
90e60aa7 4085}
4086
4087DEFUN (no_bgp_evpn_vni,
4088 no_bgp_evpn_vni_cmd,
4089 "no vni (1-16777215)",
4090 NO_STR
4091 "VXLAN Network Identifier\n"
4092 "VNI number\n")
4093{
d62a17ae 4094 vni_t vni;
4095 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4096 struct bgpevpn *vpn;
90e60aa7 4097
d62a17ae 4098 if (!bgp)
4099 return CMD_WARNING;
90e60aa7 4100
d62a17ae 4101 vni = strtoul(argv[2]->arg, NULL, 10);
90e60aa7 4102
d62a17ae 4103 /* Check if we should disallow. */
4104 vpn = bgp_evpn_lookup_vni(bgp, vni);
4105 if (!vpn) {
4106 vty_out(vty, "%% Specified VNI does not exist\n");
4107 return CMD_WARNING;
4108 }
4109 if (!is_vni_configured(vpn)) {
4110 vty_out(vty, "%% Specified VNI is not configured\n");
4111 return CMD_WARNING;
4112 }
90e60aa7 4113
d62a17ae 4114 evpn_delete_vni(bgp, vpn);
4115 return CMD_SUCCESS;
90e60aa7 4116}
4117
4118DEFUN_NOSH (exit_vni,
4119 exit_vni_cmd,
4120 "exit-vni",
4121 "Exit from VNI mode\n")
4122{
d62a17ae 4123 if (vty->node == BGP_EVPN_VNI_NODE)
4124 vty->node = BGP_EVPN_NODE;
4125 return CMD_SUCCESS;
90e60aa7 4126}
4127
676f83b9 4128DEFUN (bgp_evpn_vrf_rd,
4129 bgp_evpn_vrf_rd_cmd,
4130 "rd ASN:NN_OR_IP-ADDRESS:NN",
4131 "Route Distinguisher\n"
4132 "ASN:XX or A.B.C.D:XX\n")
4133{
4134 int ret;
4135 struct prefix_rd prd;
4136 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
4137
4138 if (!bgp_vrf)
4139 return CMD_WARNING;
4140
4141 ret = str2prefix_rd(argv[1]->arg, &prd);
4142 if (!ret) {
4143 vty_out(vty, "%% Malformed Route Distinguisher\n");
4144 return CMD_WARNING;
4145 }
4146
4147 /* If same as existing value, there is nothing more to do. */
4148 if (bgp_evpn_vrf_rd_matches_existing(bgp_vrf, &prd))
4149 return CMD_SUCCESS;
4150
4151 /* Configure or update the RD. */
4152 evpn_configure_vrf_rd(bgp_vrf, &prd);
4153 return CMD_SUCCESS;
4154}
4155
4156DEFUN (no_bgp_evpn_vrf_rd,
4157 no_bgp_evpn_vrf_rd_cmd,
4158 "no rd ASN:NN_OR_IP-ADDRESS:NN",
4159 NO_STR
4160 "Route Distinguisher\n"
4161 "ASN:XX or A.B.C.D:XX\n")
4162{
4163 int ret;
4164 struct prefix_rd prd;
4165 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
4166
4167 if (!bgp_vrf)
4168 return CMD_WARNING;
4169
4170 ret = str2prefix_rd(argv[2]->arg, &prd);
4171 if (!ret) {
4172 vty_out(vty, "%% Malformed Route Distinguisher\n");
4173 return CMD_WARNING;
4174 }
4175
4176 /* Check if we should disallow. */
4177 if (!is_vrf_rd_configured(bgp_vrf)) {
4178 vty_out(vty, "%% RD is not configured for this VRF\n");
4179 return CMD_WARNING;
4180 }
4181
4182 if (!bgp_evpn_vrf_rd_matches_existing(bgp_vrf, &prd)) {
4183 vty_out(vty,
4184 "%% RD specified does not match configuration for this VRF\n");
4185 return CMD_WARNING;
4186 }
4187
4188 evpn_unconfigure_vrf_rd(bgp_vrf);
4189 return CMD_SUCCESS;
4190}
4191
4192DEFUN (no_bgp_evpn_vrf_rd_without_val,
4193 no_bgp_evpn_vrf_rd_without_val_cmd,
4194 "no rd",
4195 NO_STR
4196 "Route Distinguisher\n")
4197{
4198 struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
4199
4200 if (!bgp_vrf)
4201 return CMD_WARNING;
4202
4203 /* Check if we should disallow. */
4204 if (!is_vrf_rd_configured(bgp_vrf)) {
4205 vty_out(vty, "%% RD is not configured for this VRF\n");
4206 return CMD_WARNING;
4207 }
4208
4209 evpn_unconfigure_vrf_rd(bgp_vrf);
4210 return CMD_SUCCESS;
4211}
4212
90e60aa7 4213DEFUN (bgp_evpn_vni_rd,
4214 bgp_evpn_vni_rd_cmd,
d114b977 4215 "rd ASN:NN_OR_IP-ADDRESS:NN",
90e60aa7 4216 "Route Distinguisher\n"
4217 "ASN:XX or A.B.C.D:XX\n")
4218{
d62a17ae 4219 struct prefix_rd prd;
4220 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4221 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
4222 int ret;
90e60aa7 4223
d62a17ae 4224 if (!bgp || !vpn)
4225 return CMD_WARNING;
90e60aa7 4226
a2a8153f
CS
4227 if (bgp->vrf_id != VRF_DEFAULT) {
4228 vty_out(vty,
4229 "This command is only supported under Default VRF\n");
4230 return CMD_WARNING;
4231 }
4232
d62a17ae 4233 ret = str2prefix_rd(argv[1]->arg, &prd);
4234 if (!ret) {
4235 vty_out(vty, "%% Malformed Route Distinguisher\n");
4236 return CMD_WARNING;
4237 }
90e60aa7 4238
d62a17ae 4239 /* If same as existing value, there is nothing more to do. */
4240 if (bgp_evpn_rd_matches_existing(vpn, &prd))
4241 return CMD_SUCCESS;
90e60aa7 4242
d62a17ae 4243 /* Configure or update the RD. */
4244 evpn_configure_rd(bgp, vpn, &prd);
4245 return CMD_SUCCESS;
90e60aa7 4246}
4247
4248DEFUN (no_bgp_evpn_vni_rd,
4249 no_bgp_evpn_vni_rd_cmd,
d114b977 4250 "no rd ASN:NN_OR_IP-ADDRESS:NN",
90e60aa7 4251 NO_STR
4252 "Route Distinguisher\n"
4253 "ASN:XX or A.B.C.D:XX\n")
4254{
d62a17ae 4255 struct prefix_rd prd;
4256 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4257 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
4258 int ret;
90e60aa7 4259
d62a17ae 4260 if (!bgp || !vpn)
4261 return CMD_WARNING;
90e60aa7 4262
a2a8153f
CS
4263 if (bgp->vrf_id != VRF_DEFAULT) {
4264 vty_out(vty,
4265 "This command is only supported under Default VRF\n");
4266 return CMD_WARNING;
4267 }
4268
d62a17ae 4269 ret = str2prefix_rd(argv[2]->arg, &prd);
4270 if (!ret) {
4271 vty_out(vty, "%% Malformed Route Distinguisher\n");
4272 return CMD_WARNING;
4273 }
90e60aa7 4274
d62a17ae 4275 /* Check if we should disallow. */
4276 if (!is_rd_configured(vpn)) {
4277 vty_out(vty, "%% RD is not configured for this VNI\n");
4278 return CMD_WARNING;
4279 }
90e60aa7 4280
d62a17ae 4281 if (!bgp_evpn_rd_matches_existing(vpn, &prd)) {
4282 vty_out(vty,
4283 "%% RD specified does not match configuration for this VNI\n");
4284 return CMD_WARNING;
4285 }
90e60aa7 4286
d62a17ae 4287 evpn_unconfigure_rd(bgp, vpn);
4288 return CMD_SUCCESS;
90e60aa7 4289}
4290
4291DEFUN (no_bgp_evpn_vni_rd_without_val,
4292 no_bgp_evpn_vni_rd_without_val_cmd,
4293 "no rd",
4294 NO_STR
4295 "Route Distinguisher\n")
4296{
d62a17ae 4297 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4298 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
90e60aa7 4299
d62a17ae 4300 if (!bgp || !vpn)
4301 return CMD_WARNING;
90e60aa7 4302
a2a8153f
CS
4303 if (bgp->vrf_id != VRF_DEFAULT) {
4304 vty_out(vty,
4305 "This command is only supported under Default VRF\n");
4306 return CMD_WARNING;
4307 }
4308
d62a17ae 4309 /* Check if we should disallow. */
4310 if (!is_rd_configured(vpn)) {
4311 vty_out(vty, "%% RD is not configured for this VNI\n");
4312 return CMD_WARNING;
4313 }
90e60aa7 4314
d62a17ae 4315 evpn_unconfigure_rd(bgp, vpn);
4316 return CMD_SUCCESS;
90e60aa7 4317}
4318
4319/*
4320 * Loop over all extended-communities in the route-target list rtl and
4321 * return 1 if we find ecomtarget
4322 */
d62a17ae 4323static int bgp_evpn_rt_matches_existing(struct list *rtl,
4324 struct ecommunity *ecomtarget)
90e60aa7 4325{
d62a17ae 4326 struct listnode *node, *nnode;
4327 struct ecommunity *ecom;
90e60aa7 4328
d62a17ae 4329 for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
4330 if (ecommunity_match(ecom, ecomtarget))
4331 return 1;
4332 }
90e60aa7 4333
d62a17ae 4334 return 0;
90e60aa7 4335}
4336
c581d8b0
MK
4337/* display L3VNI related info for a VRF instance */
4338DEFUN (show_bgp_vrf_l3vni_info,
4339 show_bgp_vrf_l3vni_info_cmd,
4cce389e 4340 "show bgp vrf VRFNAME vni [json]",
c581d8b0
MK
4341 SHOW_STR
4342 BGP_STR
4343 "show bgp vrf\n"
4344 "VRF Name\n"
4345 "L3-VNI\n"
ceb9a921 4346 JSON_STR)
c581d8b0
MK
4347{
4348 char buf[ETHER_ADDR_STRLEN];
676f83b9 4349 char buf1[INET6_ADDRSTRLEN];
c581d8b0
MK
4350 int idx_vrf = 3;
4351 const char *name = NULL;
4352 struct bgp *bgp = NULL;
4353 struct listnode *node = NULL;
6a8657d0 4354 struct bgpevpn *vpn = NULL;
c581d8b0 4355 struct ecommunity *ecom = NULL;
ceb9a921
MK
4356 json_object *json = NULL;
4357 json_object *json_vnis = NULL;
4358 json_object *json_export_rts = NULL;
4359 json_object *json_import_rts = NULL;
d7c0a89a 4360 uint8_t uj = use_json(argc, argv);
ceb9a921
MK
4361
4362 if (uj) {
4363 json = json_object_new_object();
4364 json_vnis = json_object_new_array();
4365 json_export_rts = json_object_new_array();
4366 json_import_rts = json_object_new_array();
4367 }
c581d8b0
MK
4368
4369 name = argv[idx_vrf]->arg;
4370 bgp = bgp_lookup_by_name(name);
4371 if (!bgp) {
ceb9a921 4372 if (!uj)
996c9314 4373 vty_out(vty, "BGP instance for VRF %s not found", name);
ceb9a921
MK
4374 else {
4375 json_object_string_add(json, "warning",
4376 "BGP instance not found");
996c9314 4377 vty_out(vty, "%s\n", json_object_to_json_string(json));
ceb9a921
MK
4378 json_object_free(json);
4379 }
c581d8b0
MK
4380 return CMD_WARNING;
4381 }
4382
ceb9a921
MK
4383 if (!json) {
4384 vty_out(vty, "BGP VRF: %s\n", name);
996c9314 4385 vty_out(vty, " Local-Ip: %s\n", inet_ntoa(bgp->originator_ip));
ceb9a921
MK
4386 vty_out(vty, " L3-VNI: %u\n", bgp->l3vni);
4387 vty_out(vty, " Rmac: %s\n",
4388 prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
c48d9f5f
MK
4389 vty_out(vty, " VNI Filter: %s\n",
4390 CHECK_FLAG(bgp->vrf_flags,
996c9314
LB
4391 BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)
4392 ? "prefix-routes-only"
4393 : "none");
ceb9a921
MK
4394 vty_out(vty, " L2-VNI List:\n");
4395 vty_out(vty, " ");
4396 for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
4397 vty_out(vty, "%u ", vpn->vni);
4398 vty_out(vty, "\n");
4399 vty_out(vty, " Export-RTs:\n");
4400 vty_out(vty, " ");
4401 for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
4402 vty_out(vty, "%s ", ecommunity_str(ecom));
4403 vty_out(vty, "\n");
4404 vty_out(vty, " Import-RTs:\n");
4405 vty_out(vty, " ");
4406 for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
4407 vty_out(vty, "%s ", ecommunity_str(ecom));
4408 vty_out(vty, "\n");
676f83b9 4409 vty_out(vty, " RD: %s\n",
4410 prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
ceb9a921
MK
4411 } else {
4412 json_object_string_add(json, "vrf", name);
b67a60d2 4413 json_object_string_add(json, "local-ip",
4414 inet_ntoa(bgp->originator_ip));
ceb9a921 4415 json_object_int_add(json, "l3vni", bgp->l3vni);
996c9314
LB
4416 json_object_string_add(
4417 json, "rmac",
4418 prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
4419 json_object_string_add(
4420 json, "vniFilter",
4421 CHECK_FLAG(bgp->vrf_flags,
4422 BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)
4423 ? "prefix-routes-only"
4424 : "none");
ceb9a921
MK
4425 /* list of l2vnis */
4426 for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
4427 json_object_array_add(json_vnis,
4428 json_object_new_int(vpn->vni));
4429 json_object_object_add(json, "l2vnis", json_vnis);
4430
4431 /* export rts */
4432 for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
996c9314
LB
4433 json_object_array_add(
4434 json_export_rts,
4435 json_object_new_string(ecommunity_str(ecom)));
ceb9a921
MK
4436 json_object_object_add(json, "export-rts", json_export_rts);
4437
4438 /* import rts */
4439 for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
996c9314
LB
4440 json_object_array_add(
4441 json_import_rts,
4442 json_object_new_string(ecommunity_str(ecom)));
ceb9a921 4443 json_object_object_add(json, "import-rts", json_import_rts);
676f83b9 4444 json_object_string_add(
4445 json, "rd",
4446 prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
ceb9a921 4447 }
c581d8b0 4448
ceb9a921
MK
4449 if (uj) {
4450 vty_out(vty, "%s\n", json_object_to_json_string_ext(
4451 json, JSON_C_TO_STRING_PRETTY));
4452 json_object_free(json);
4453 }
c581d8b0
MK
4454 return CMD_SUCCESS;
4455}
4456
4457/* import/export rt for l3vni-vrf */
4458DEFUN (bgp_evpn_vrf_rt,
4459 bgp_evpn_vrf_rt_cmd,
4460 "route-target <both|import|export> RT",
4461 "Route Target\n"
4462 "import and export\n"
4463 "import\n"
4464 "export\n"
4465 "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
4466{
4467 int rt_type;
4468 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4469 struct ecommunity *ecomadd = NULL;
4470
4471 if (!bgp)
4472 return CMD_WARNING;
4473
4474 if (!strcmp(argv[1]->arg, "import"))
4475 rt_type = RT_TYPE_IMPORT;
4476 else if (!strcmp(argv[1]->arg, "export"))
4477 rt_type = RT_TYPE_EXPORT;
4478 else if (!strcmp(argv[1]->arg, "both"))
4479 rt_type = RT_TYPE_BOTH;
4480 else {
4481 vty_out(vty, "%% Invalid Route Target type\n");
4482 return CMD_WARNING;
4483 }
4484
4485 /* Add/update the import route-target */
4486 if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
4487 ecomadd = ecommunity_str2com(argv[2]->arg,
4488 ECOMMUNITY_ROUTE_TARGET, 0);
4489 if (!ecomadd) {
4490 vty_out(vty, "%% Malformed Route Target list\n");
4491 return CMD_WARNING;
4492 }
4493 ecommunity_str(ecomadd);
4494
4495 /* Do nothing if we already have this import route-target */
996c9314 4496 if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl, ecomadd))
c581d8b0
MK
4497 bgp_evpn_configure_import_rt_for_vrf(bgp, ecomadd);
4498 }
4499
4500 /* Add/update the export route-target */
4501 if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
4502 ecomadd = ecommunity_str2com(argv[2]->arg,
4503 ECOMMUNITY_ROUTE_TARGET, 0);
4504 if (!ecomadd) {
4505 vty_out(vty, "%% Malformed Route Target list\n");
4506 return CMD_WARNING;
4507 }
4508 ecommunity_str(ecomadd);
4509
4510 /* Do nothing if we already have this export route-target */
996c9314 4511 if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl, ecomadd))
c581d8b0
MK
4512 bgp_evpn_configure_export_rt_for_vrf(bgp, ecomadd);
4513 }
4514
4515 return CMD_SUCCESS;
4516}
4517
4518DEFUN (no_bgp_evpn_vrf_rt,
4519 no_bgp_evpn_vrf_rt_cmd,
4520 "no route-target <both|import|export> RT",
4521 NO_STR
4522 "Route Target\n"
4523 "import and export\n"
4524 "import\n"
4525 "export\n"
4526 "ASN:XX or A.B.C.D:XX\n")
4527{
4528 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4529 int rt_type, found_ecomdel;
4530 struct ecommunity *ecomdel = NULL;
4531
4532 if (!bgp)
4533 return CMD_WARNING;
4534
4535 if (!strcmp(argv[2]->arg, "import"))
4536 rt_type = RT_TYPE_IMPORT;
4537 else if (!strcmp(argv[2]->arg, "export"))
4538 rt_type = RT_TYPE_EXPORT;
4539 else if (!strcmp(argv[2]->arg, "both"))
4540 rt_type = RT_TYPE_BOTH;
4541 else {
4542 vty_out(vty, "%% Invalid Route Target type\n");
4543 return CMD_WARNING;
4544 }
4545
4546 if (rt_type == RT_TYPE_IMPORT) {
4547 if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
4548 vty_out(vty,
4549 "%% Import RT is not configured for this VRF\n");
4550 return CMD_WARNING;
4551 }
4552 } else if (rt_type == RT_TYPE_EXPORT) {
4553 if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
4554 vty_out(vty,
4555 "%% Export RT is not configured for this VRF\n");
4556 return CMD_WARNING;
4557 }
4558 } else if (rt_type == RT_TYPE_BOTH) {
4559 if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)
4560 && !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
4561 vty_out(vty,
4562 "%% Import/Export RT is not configured for this VRF\n");
4563 return CMD_WARNING;
4564 }
4565 }
4566
4567 ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
4568 if (!ecomdel) {
4569 vty_out(vty, "%% Malformed Route Target list\n");
4570 return CMD_WARNING;
4571 }
4572 ecommunity_str(ecomdel);
4573
4574 if (rt_type == RT_TYPE_IMPORT) {
4575 if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
4576 ecomdel)) {
4577 vty_out(vty,
4578 "%% RT specified does not match configuration for this VRF\n");
4579 return CMD_WARNING;
4580 }
4581 bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);
4582 } else if (rt_type == RT_TYPE_EXPORT) {
4583 if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
4584 ecomdel)) {
4585 vty_out(vty,
4586 "%% RT specified does not match configuration for this VRF\n");
4587 return CMD_WARNING;
4588 }
4589 bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);
4590 } else if (rt_type == RT_TYPE_BOTH) {
4591 found_ecomdel = 0;
4592
4593 if (bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
4594 ecomdel)) {
4595 bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);
4596 found_ecomdel = 1;
4597 }
4598
4599 if (bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
4600 ecomdel)) {
4601 bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);
4602 found_ecomdel = 1;
4603 }
4604
4605 if (!found_ecomdel) {
4606 vty_out(vty,
4607 "%% RT specified does not match configuration for this VRF\n");
4608 return CMD_WARNING;
4609 }
4610 }
4611
4612 return CMD_SUCCESS;
4613}
90e60aa7 4614
4615DEFUN (bgp_evpn_vni_rt,
4616 bgp_evpn_vni_rt_cmd,
4617 "route-target <both|import|export> RT",
4618 "Route Target\n"
4619 "import and export\n"
4620 "import\n"
4621 "export\n"
4622 "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
4623{
d62a17ae 4624 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4625 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
4626 int rt_type;
4627 struct ecommunity *ecomadd = NULL;
4628
4629 if (!bgp || !vpn)
4630 return CMD_WARNING;
4631
a2a8153f
CS
4632 if (bgp->vrf_id != VRF_DEFAULT) {
4633 vty_out(vty,
4634 "This command is only supported under Default VRF\n");
4635 return CMD_WARNING;
4636 }
4637
8034beff 4638 if (!strcmp(argv[1]->text, "import"))
d62a17ae 4639 rt_type = RT_TYPE_IMPORT;
8034beff 4640 else if (!strcmp(argv[1]->text, "export"))
d62a17ae 4641 rt_type = RT_TYPE_EXPORT;
8034beff 4642 else if (!strcmp(argv[1]->text, "both"))
d62a17ae 4643 rt_type = RT_TYPE_BOTH;
4644 else {
4645 vty_out(vty, "%% Invalid Route Target type\n");
4646 return CMD_WARNING;
4647 }
4648
4649 /* Add/update the import route-target */
4650 if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
4651 ecomadd = ecommunity_str2com(argv[2]->arg,
4652 ECOMMUNITY_ROUTE_TARGET, 0);
d62a17ae 4653 if (!ecomadd) {
4654 vty_out(vty, "%% Malformed Route Target list\n");
4655 return CMD_WARNING;
4656 }
5bc2ed52 4657 ecommunity_str(ecomadd);
d62a17ae 4658
4659 /* Do nothing if we already have this import route-target */
4660 if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd))
4661 evpn_configure_import_rt(bgp, vpn, ecomadd);
4662 }
4663
4664 /* Add/update the export route-target */
4665 if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
4666 ecomadd = ecommunity_str2com(argv[2]->arg,
4667 ECOMMUNITY_ROUTE_TARGET, 0);
d62a17ae 4668 if (!ecomadd) {
4669 vty_out(vty, "%% Malformed Route Target list\n");
4670 return CMD_WARNING;
4671 }
5bc2ed52 4672 ecommunity_str(ecomadd);
d62a17ae 4673
4674 /* Do nothing if we already have this export route-target */
4675 if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd))
4676 evpn_configure_export_rt(bgp, vpn, ecomadd);
4677 }
4678
4679 return CMD_SUCCESS;
90e60aa7 4680}
4681
4682DEFUN (no_bgp_evpn_vni_rt,
4683 no_bgp_evpn_vni_rt_cmd,
4684 "no route-target <both|import|export> RT",
4685 NO_STR
4686 "Route Target\n"
4687 "import and export\n"
4688 "import\n"
4689 "export\n"
4690 "ASN:XX or A.B.C.D:XX\n")
4691{
d62a17ae 4692 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4693 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
4694 int rt_type, found_ecomdel;
4695 struct ecommunity *ecomdel = NULL;
4696
4697 if (!bgp || !vpn)
4698 return CMD_WARNING;
4699
a2a8153f
CS
4700 if (bgp->vrf_id != VRF_DEFAULT) {
4701 vty_out(vty,
4702 "This command is only supported under Default VRF\n");
4703 return CMD_WARNING;
4704 }
4705
8034beff 4706 if (!strcmp(argv[2]->text, "import"))
d62a17ae 4707 rt_type = RT_TYPE_IMPORT;
8034beff 4708 else if (!strcmp(argv[2]->text, "export"))
d62a17ae 4709 rt_type = RT_TYPE_EXPORT;
8034beff 4710 else if (!strcmp(argv[2]->text, "both"))
d62a17ae 4711 rt_type = RT_TYPE_BOTH;
4712 else {
4713 vty_out(vty, "%% Invalid Route Target type\n");
4714 return CMD_WARNING;
4715 }
4716
4717 /* The user did "no route-target import", check to see if there are any
4718 * import route-targets configured. */
4719 if (rt_type == RT_TYPE_IMPORT) {
4720 if (!is_import_rt_configured(vpn)) {
4721 vty_out(vty,
4722 "%% Import RT is not configured for this VNI\n");
4723 return CMD_WARNING;
4724 }
4725 } else if (rt_type == RT_TYPE_EXPORT) {
4726 if (!is_export_rt_configured(vpn)) {
4727 vty_out(vty,
4728 "%% Export RT is not configured for this VNI\n");
4729 return CMD_WARNING;
4730 }
4731 } else if (rt_type == RT_TYPE_BOTH) {
4732 if (!is_import_rt_configured(vpn)
4733 && !is_export_rt_configured(vpn)) {
4734 vty_out(vty,
4735 "%% Import/Export RT is not configured for this VNI\n");
4736 return CMD_WARNING;
4737 }
4738 }
4739
4740 ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
d62a17ae 4741 if (!ecomdel) {
4742 vty_out(vty, "%% Malformed Route Target list\n");
4743 return CMD_WARNING;
4744 }
5bc2ed52 4745 ecommunity_str(ecomdel);
d62a17ae 4746
4747 if (rt_type == RT_TYPE_IMPORT) {
4748 if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
4749 vty_out(vty,
4750 "%% RT specified does not match configuration for this VNI\n");
4751 return CMD_WARNING;
4752 }
4753 evpn_unconfigure_import_rt(bgp, vpn, ecomdel);
4754 } else if (rt_type == RT_TYPE_EXPORT) {
4755 if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomdel)) {
4756 vty_out(vty,
4757 "%% RT specified does not match configuration for this VNI\n");
4758 return CMD_WARNING;
4759 }
4760 evpn_unconfigure_export_rt(bgp, vpn, ecomdel);
4761 } else if (rt_type == RT_TYPE_BOTH) {
4762 found_ecomdel = 0;
4763
4764 if (bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
4765 evpn_unconfigure_import_rt(bgp, vpn, ecomdel);
4766 found_ecomdel = 1;
4767 }
4768
4769 if (bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomdel)) {
4770 evpn_unconfigure_export_rt(bgp, vpn, ecomdel);
4771 found_ecomdel = 1;
4772 }
4773
4774 if (!found_ecomdel) {
4775 vty_out(vty,
4776 "%% RT specified does not match configuration for this VNI\n");
4777 return CMD_WARNING;
4778 }
4779 }
4780
4781 return CMD_SUCCESS;
90e60aa7 4782}
4783
4784DEFUN (no_bgp_evpn_vni_rt_without_val,
4785 no_bgp_evpn_vni_rt_without_val_cmd,
4786 "no route-target <import|export>",
4787 NO_STR
4788 "Route Target\n"
4789 "import\n"
4790 "export\n")
4791{
d62a17ae 4792 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
4793 VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
4794 int rt_type;
4795
4796 if (!bgp || !vpn)
4797 return CMD_WARNING;
4798
a2a8153f
CS
4799 if (bgp->vrf_id != VRF_DEFAULT) {
4800 vty_out(vty,
4801 "This command is only supported under Default VRF\n");
4802 return CMD_WARNING;
4803 }
4804
8034beff 4805 if (!strcmp(argv[2]->text, "import")) {
d62a17ae 4806 rt_type = RT_TYPE_IMPORT;
8034beff 4807 } else if (!strcmp(argv[2]->text, "export")) {
d62a17ae 4808 rt_type = RT_TYPE_EXPORT;
4809 } else {
4810 vty_out(vty, "%% Invalid Route Target type\n");
4811 return CMD_WARNING;
4812 }
4813
4814 /* Check if we should disallow. */
4815 if (rt_type == RT_TYPE_IMPORT) {
4816 if (!is_import_rt_configured(vpn)) {
4817 vty_out(vty,
4818 "%% Import RT is not configured for this VNI\n");
4819 return CMD_WARNING;
4820 }
4821 } else {
4822 if (!is_export_rt_configured(vpn)) {
4823 vty_out(vty,
4824 "%% Export RT is not configured for this VNI\n");
4825 return CMD_WARNING;
4826 }
4827 }
4828
4829 /* Unconfigure the RT. */
4830 if (rt_type == RT_TYPE_IMPORT)
4831 evpn_unconfigure_import_rt(bgp, vpn, NULL);
4832 else
4833 evpn_unconfigure_export_rt(bgp, vpn, NULL);
4834 return CMD_SUCCESS;
90e60aa7 4835}
568b6b44
QY
4836
4837static int vni_cmp(const void **a, const void **b)
4838{
4839 const struct bgpevpn *first = *a;
4840 const struct bgpevpn *secnd = *b;
4841
4842 return secnd->vni - first->vni;
4843}
4844
90e60aa7 4845/*
4846 * Output EVPN configuration information.
4847 */
d62a17ae 4848void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
2b791107 4849 safi_t safi)
d62a17ae 4850{
a75c2553
MK
4851 char buf1[RD_ADDRSTRLEN];
4852
568b6b44
QY
4853 if (bgp->vnihash) {
4854 struct list *vnilist = hash_to_list(bgp->vnihash);
4855 struct listnode *ln;
4856 struct bgpevpn *data;
4857
4858 list_sort(vnilist, vni_cmp);
4859 for (ALL_LIST_ELEMENTS_RO(vnilist, ln, data))
4860 write_vni_config(vty, data);
4861
4862 list_delete_and_null(&vnilist);
4863 }
90e60aa7 4864
2b791107 4865 if (bgp->advertise_all_vni)
d62a17ae 4866 vty_out(vty, " advertise-all-vni\n");
1a98c087 4867
bf1061d8
VB
4868 if (bgp->advertise_autort_rfc8365)
4869 vty_out(vty, " autort rfc8365-compatible\n");
4870
2b791107 4871 if (bgp->advertise_gw_macip)
1a98c087 4872 vty_out(vty, " advertise-default-gw\n");
6ee86383 4873
154faa50 4874 if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
d2a0075a
MK
4875 BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
4876 if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name)
4877 vty_out(vty, " advertise ipv4 unicast route-map %s\n",
4878 bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name);
4879 else
4880 vty_out(vty, " advertise ipv4 unicast\n");
4881 }
6ee86383 4882
154faa50 4883 if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
d2a0075a
MK
4884 BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
4885 if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name)
4886 vty_out(vty, " advertise ipv6 unicast route-map %s\n",
4887 bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name);
4888 else
4889 vty_out(vty, " advertise ipv6 unicast\n");
4890 }
486456ca
MK
4891
4892 if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
4893 BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
4894 vty_out(vty, " default-originate ipv4\n");
4895
4896 if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
4897 BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
4898 vty_out(vty, " default-originate ipv6\n");
58f9e4d3 4899
a75c2553
MK
4900 if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
4901 vty_out(vty, " rd %s\n",
4902 prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
4903
db29a4a8
MK
4904 /* import route-target */
4905 if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
4906 char *ecom_str;
4907 struct listnode *node, *nnode;
4908 struct ecommunity *ecom;
4909
4910 for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
4911 ecom)) {
4912 ecom_str = ecommunity_ecom2str(
4913 ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
996c9314 4914 vty_out(vty, " route-target import %s\n", ecom_str);
db29a4a8
MK
4915 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
4916 }
4917 }
4918
4919 /* export route-target */
4920 if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
4921 char *ecom_str;
4922 struct listnode *node, *nnode;
4923 struct ecommunity *ecom;
4924
4925 for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
4926 ecom)) {
4927 ecom_str = ecommunity_ecom2str(
4928 ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
996c9314 4929 vty_out(vty, " route-target export %s\n", ecom_str);
db29a4a8
MK
4930 XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
4931 }
4932 }
90e60aa7 4933}
4934
4d0e6ece 4935void bgp_ethernetvpn_init(void)
784d3a42 4936{
d62a17ae 4937 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd);
4938 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd);
4939 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
4940 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
4941 install_element(VIEW_NODE,
4942 &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
4943 install_element(VIEW_NODE,
4944 &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
4945 install_element(
4946 VIEW_NODE,
4947 &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
4948 install_element(
4949 VIEW_NODE,
4950 &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
4951 install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd);
4952 install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
4953 install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
4954 install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
d62a17ae 4955 install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
4956 install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
bf1061d8
VB
4957 install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_autort_rfc8365_cmd);
4958 install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_autort_rfc8365_cmd);
1a98c087
MK
4959 install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
4960 install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
342dd0c6 4961 install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
4962 install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
486456ca
MK
4963 install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
4964 install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
d62a17ae 4965
50f74cf1 4966 /* test commands */
4967 install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd);
4968 install_element(BGP_EVPN_NODE, &test_withdraw_evpn_type4_route_cmd);
4969
f2d62262 4970 /* "show bgp l2vpn evpn" commands. */
50f74cf1 4971 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_cmd);
f2d62262 4972 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
4973 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
4974 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
4975 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
4976 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
50f74cf1 4977 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_esi_cmd);
f2d62262 4978 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
4979 install_element(VIEW_NODE,
4980 &show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
4981 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
4982 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
4983 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
10ebe1ab 4984 install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
d62a17ae 4985
5014d96f
DW
4986 /* "show bgp evpn" commands. */
4987 install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
4988 install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
4989 install_element(VIEW_NODE, &show_bgp_evpn_route_cmd);
4990 install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd);
4991 install_element(VIEW_NODE, &show_bgp_evpn_route_rd_macip_cmd);
4992 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_cmd);
4993 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_multicast_cmd);
4994 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd);
4995 install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd);
4996 install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd);
c581d8b0 4997 install_element(VIEW_NODE, &show_bgp_vrf_l3vni_info_cmd);
5014d96f 4998
d62a17ae 4999 install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
5000 install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd);
5001 install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd);
5002 install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rd_cmd);
5003 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rd_cmd);
5004 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rd_without_val_cmd);
5005 install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
5006 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
5007 install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
bf48830b
MK
5008 install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rd_cmd);
5009 install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rd_cmd);
676f83b9 5010 install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd);
df399d1c
MK
5011 install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd);
5012 install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd);
1a98c087
MK
5013 install_element(BGP_EVPN_VNI_NODE,
5014 &bgp_evpn_advertise_default_gw_vni_cmd);
5015 install_element(BGP_EVPN_VNI_NODE,
5016 &no_bgp_evpn_advertise_default_gw_vni_cmd);
31310b25
MK
5017 install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
5018 install_element(BGP_EVPN_VNI_NODE,
5019 &no_bgp_evpn_advertise_vni_subnet_cmd);
784d3a42 5020}