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