]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_evpn_vty.c
bgpd: enhance EPVN vty show commands
[mirror_frr.git] / bgpd / bgp_evpn_vty.c
1 /* Ethernet-VPN Packet and vty Processing File
2 Copyright (C) 2017 6WIND
3
4 This file is part of Free Range Routing
5
6 Free Range Routing 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 Free Range Routing 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
17 along with Free Range Routing; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
20
21 #include <zebra.h>
22 #include "command.h"
23 #include "prefix.h"
24 #include "lib/json.h"
25
26 #include "bgpd/bgpd.h"
27 #include "bgpd/bgp_table.h"
28 #include "bgpd/bgp_attr.h"
29 #include "bgpd/bgp_route.h"
30 #include "bgpd/bgp_mplsvpn.h"
31 #include "bgpd/bgp_vpn.h"
32 #include "bgpd/bgp_evpn_vty.h"
33
34 #define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
35 #define EVPN_HELP_STR "Ethernet Virtual Private Network\n"
36
37 #define SHOW_DISPLAY_STANDARD 0
38 #define SHOW_DISPLAY_TAGS 1
39 #define SHOW_DISPLAY_OVERLAY 2
40
41 static int
42 bgp_show_ethernet_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type,
43 void *output_arg, int option, u_char use_json)
44 {
45 afi_t afi = AFI_L2VPN;
46 struct bgp *bgp;
47 struct bgp_table *table;
48 struct bgp_node *rn;
49 struct bgp_node *rm;
50 struct bgp_info *ri;
51 int rd_header;
52 int header = 1;
53 char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s";
54 char v4_header_tag[] = " Network Next Hop In tag/Out tag%s";
55 char v4_header_overlay[] = " Network Next Hop EthTag Overlay Index RouterMac%s";
56
57 unsigned long output_count = 0;
58 unsigned long total_count = 0;
59 json_object *json = NULL;
60 json_object *json_nroute = NULL;
61 json_object *json_array = NULL;
62 json_object *json_scode = NULL;
63 json_object *json_ocode = NULL;
64
65 bgp = bgp_get_default ();
66 if (bgp == NULL)
67 {
68 if (!use_json)
69 vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
70 return CMD_WARNING;
71 }
72
73 if (use_json)
74 {
75 json_scode = json_object_new_object();
76 json_ocode = json_object_new_object();
77 json = json_object_new_object();
78 json_nroute = json_object_new_object();
79
80 json_object_string_add(json_scode, "suppressed", "s");
81 json_object_string_add(json_scode, "damped", "d");
82 json_object_string_add(json_scode, "history", "h");
83 json_object_string_add(json_scode, "valid", "*");
84 json_object_string_add(json_scode, "best", ">");
85 json_object_string_add(json_scode, "internal", "i");
86
87 json_object_string_add(json_ocode, "igp", "i");
88 json_object_string_add(json_ocode, "egp", "e");
89 json_object_string_add(json_ocode, "incomplete", "?");
90 }
91
92 for (rn = bgp_table_top (bgp->rib[afi][SAFI_EVPN]); rn; rn = bgp_route_next (rn))
93 {
94 if (use_json)
95 continue; /* XXX json TODO */
96
97 if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
98 continue;
99
100 if ((table = rn->info) != NULL)
101 {
102 rd_header = 1;
103
104 for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
105 for (ri = rm->info; ri; ri = ri->next)
106 {
107 total_count++;
108 if (type == bgp_show_type_neighbor)
109 {
110 union sockunion *su = output_arg;
111
112 if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
113 continue;
114 }
115 if (header == 0)
116 {
117 if (use_json)
118 {
119 if (option == SHOW_DISPLAY_TAGS)
120 {
121 json_object_int_add(json, "bgpTableVersion", 0);
122 json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
123 json_object_object_add(json, "bgpStatusCodes", json_scode);
124 json_object_object_add(json, "bgpOriginCodes", json_ocode);
125 }
126 }
127 else
128 {
129 if (option == SHOW_DISPLAY_TAGS)
130 vty_out (vty, v4_header_tag, VTY_NEWLINE);
131 else if (option == SHOW_DISPLAY_OVERLAY)
132 vty_out (vty, v4_header_overlay, VTY_NEWLINE);
133 else
134 {
135 vty_out (vty, "BGP table version is 0, local router ID is %s%s",
136 inet_ntoa (bgp->router_id), VTY_NEWLINE);
137 vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
138 VTY_NEWLINE);
139 vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
140 VTY_NEWLINE, VTY_NEWLINE);
141 vty_out (vty, v4_header, VTY_NEWLINE);
142 }
143 }
144 header = 0;
145 }
146 if (rd_header)
147 {
148 u_int16_t type;
149 struct rd_as rd_as;
150 struct rd_ip rd_ip;
151 u_char *pnt;
152
153 pnt = rn->p.u.val;
154
155 /* Decode RD type. */
156 type = decode_rd_type (pnt);
157 /* Decode RD value. */
158 if (type == RD_TYPE_AS)
159 decode_rd_as (pnt + 2, &rd_as);
160 else if (type == RD_TYPE_AS4)
161 decode_rd_as4 (pnt + 2, &rd_as);
162 else if (type == RD_TYPE_IP)
163 decode_rd_ip (pnt + 2, &rd_ip);
164 if (use_json)
165 {
166 char buffer[BUFSIZ];
167 if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
168 sprintf (buffer, "%u:%d", rd_as.as, rd_as.val);
169 else if (type == RD_TYPE_IP)
170 sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
171 json_object_string_add(json_nroute, "routeDistinguisher", buffer);
172 }
173 else
174 {
175 vty_out (vty, "Route Distinguisher: ");
176 if (type == RD_TYPE_AS)
177 vty_out (vty, "as2 %u:%d", rd_as.as, rd_as.val);
178 else if (type == RD_TYPE_AS4)
179 vty_out (vty, "as4 %u:%d", rd_as.as, rd_as.val);
180 else if (type == RD_TYPE_IP)
181 vty_out (vty, "ip %s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
182 vty_out (vty, "%s", VTY_NEWLINE);
183 }
184 rd_header = 0;
185 }
186 if (use_json)
187 json_array = json_object_new_array();
188 else
189 json_array = NULL;
190 if (option == SHOW_DISPLAY_TAGS)
191 route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_EVPN, json_array);
192 else if (option == SHOW_DISPLAY_OVERLAY)
193 route_vty_out_overlay (vty, &rm->p, ri, 0, json_array);
194 else
195 route_vty_out (vty, &rm->p, ri, 0, SAFI_EVPN, json_array);
196 output_count++;
197 }
198 /* XXX json */
199 }
200 }
201 if (output_count == 0)
202 vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE);
203 else
204 vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s",
205 VTY_NEWLINE, output_count, total_count, VTY_NEWLINE);
206 return CMD_SUCCESS;
207 }
208
209 DEFUN (show_ip_bgp_l2vpn_evpn,
210 show_ip_bgp_l2vpn_evpn_cmd,
211 "show [ip] bgp l2vpn evpn [json]",
212 SHOW_STR
213 IP_STR
214 BGP_STR
215 L2VPN_HELP_STR
216 EVPN_HELP_STR
217 JSON_STR)
218 {
219 return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 0, use_json (argc, argv));
220 }
221
222 DEFUN (show_ip_bgp_l2vpn_evpn_rd,
223 show_ip_bgp_l2vpn_evpn_rd_cmd,
224 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]",
225 SHOW_STR
226 IP_STR
227 BGP_STR
228 L2VPN_HELP_STR
229 EVPN_HELP_STR
230 "Display information for a route distinguisher\n"
231 "VPN Route Distinguisher\n"
232 JSON_STR)
233 {
234 int idx_ext_community = 6;
235 int ret;
236 struct prefix_rd prd;
237
238 ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd);
239 if (! ret)
240 {
241 vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
242 return CMD_WARNING;
243 }
244 return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, 0, use_json (argc, argv));
245 }
246
247 DEFUN (show_ip_bgp_l2vpn_evpn_all_tags,
248 show_ip_bgp_l2vpn_evpn_all_tags_cmd,
249 "show [ip] bgp l2vpn evpn all tags",
250 SHOW_STR
251 IP_STR
252 BGP_STR
253 L2VPN_HELP_STR
254 EVPN_HELP_STR
255 "Display information about all EVPN NLRIs\n"
256 "Display BGP tags for prefixes\n")
257 {
258 return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 1, 0);
259 }
260
261 DEFUN (show_ip_bgp_l2vpn_evpn_rd_tags,
262 show_ip_bgp_l2vpn_evpn_rd_tags_cmd,
263 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags",
264 SHOW_STR
265 IP_STR
266 BGP_STR
267 L2VPN_HELP_STR
268 EVPN_HELP_STR
269 "Display information for a route distinguisher\n"
270 "VPN Route Distinguisher\n"
271 "Display BGP tags for prefixes\n")
272 {
273 int idx_ext_community = 6;
274 int ret;
275 struct prefix_rd prd;
276
277 ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd);
278 if (! ret)
279 {
280 vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
281 return CMD_WARNING;
282 }
283 return bgp_show_ethernet_vpn (vty,&prd, bgp_show_type_normal, NULL, 1, 0);
284 }
285
286 DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
287 show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
288 "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
289 SHOW_STR
290 IP_STR
291 BGP_STR
292 L2VPN_HELP_STR
293 EVPN_HELP_STR
294 "Display information about all EVPN NLRIs\n"
295 "Detailed information on TCP and BGP neighbor connections\n"
296 "Neighbor to display information about\n"
297 "Display routes learned from neighbor\n"
298 JSON_STR)
299 {
300 int idx_ipv4 = 6;
301 union sockunion su;
302 struct peer *peer;
303 int ret;
304 u_char uj = use_json(argc, argv);
305
306 ret = str2sockunion (argv[idx_ipv4]->arg, &su);
307 if (ret < 0)
308 {
309 if (uj)
310 {
311 json_object *json_no = NULL;
312 json_no = json_object_new_object();
313 json_object_string_add(json_no, "warning", "Malformed address");
314 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
315 json_object_free(json_no);
316 }
317 else
318 vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE);
319 return CMD_WARNING;
320 }
321
322 peer = peer_lookup (NULL, &su);
323 if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN])
324 {
325 if (uj)
326 {
327 json_object *json_no = NULL;
328 json_no = json_object_new_object();
329 json_object_string_add(json_no, "warning", "No such neighbor or address family");
330 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
331 json_object_free(json_no);
332 }
333 else
334 vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
335 return CMD_WARNING;
336 }
337
338 return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0, uj);
339 }
340
341 DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
342 show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
343 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]",
344 SHOW_STR
345 IP_STR
346 BGP_STR
347 L2VPN_HELP_STR
348 EVPN_HELP_STR
349 "Display information for a route distinguisher\n"
350 "VPN Route Distinguisher\n"
351 "Detailed information on TCP and BGP neighbor connections\n"
352 "Neighbor to display information about\n"
353 "Display routes learned from neighbor\n"
354 JSON_STR)
355 {
356 int idx_ext_community = 6;
357 int idx_ipv4 = 8;
358 int ret;
359 union sockunion su;
360 struct peer *peer;
361 struct prefix_rd prd;
362 u_char uj = use_json(argc, argv);
363
364 ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd);
365 if (! ret)
366 {
367 if (uj)
368 {
369 json_object *json_no = NULL;
370 json_no = json_object_new_object();
371 json_object_string_add(json_no, "warning", "Malformed Route Distinguisher");
372 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
373 json_object_free(json_no);
374 }
375 else
376 vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
377 return CMD_WARNING;
378 }
379
380 ret = str2sockunion (argv[idx_ipv4]->arg, &su);
381 if (ret < 0)
382 {
383 if (uj)
384 {
385 json_object *json_no = NULL;
386 json_no = json_object_new_object();
387 json_object_string_add(json_no, "warning", "Malformed address");
388 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
389 json_object_free(json_no);
390 }
391 else
392 vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE);
393 return CMD_WARNING;
394 }
395
396 peer = peer_lookup (NULL, &su);
397 if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN])
398 {
399 if (uj)
400 {
401 json_object *json_no = NULL;
402 json_no = json_object_new_object();
403 json_object_string_add(json_no, "warning", "No such neighbor or address family");
404 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
405 json_object_free(json_no);
406 }
407 else
408 vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
409 return CMD_WARNING;
410 }
411
412 return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0, uj);
413 }
414
415 DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
416 show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
417 "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
418 SHOW_STR
419 IP_STR
420 BGP_STR
421 L2VPN_HELP_STR
422 EVPN_HELP_STR
423 "Display information about all EVPN NLRIs\n"
424 "Detailed information on TCP and BGP neighbor connections\n"
425 "Neighbor to display information about\n"
426 "Display the routes advertised to a BGP neighbor\n"
427 JSON_STR)
428 {
429 int idx_ipv4 = 7;
430 int ret;
431 struct peer *peer;
432 union sockunion su;
433 u_char uj = use_json(argc, argv);
434
435 ret = str2sockunion (argv[idx_ipv4]->arg, &su);
436 if (ret < 0)
437 {
438 if (uj)
439 {
440 json_object *json_no = NULL;
441 json_no = json_object_new_object();
442 json_object_string_add(json_no, "warning", "Malformed address");
443 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
444 json_object_free(json_no);
445 }
446 else
447 vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE);
448 return CMD_WARNING;
449 }
450 peer = peer_lookup (NULL, &su);
451 if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN])
452 {
453 if (uj)
454 {
455 json_object *json_no = NULL;
456 json_no = json_object_new_object();
457 json_object_string_add(json_no, "warning", "No such neighbor or address family");
458 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
459 json_object_free(json_no);
460 }
461 else
462 vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
463 return CMD_WARNING;
464 }
465
466 return show_adj_route_vpn (vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj);
467 }
468
469 DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
470 show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
471 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]",
472 SHOW_STR
473 IP_STR
474 BGP_STR
475 L2VPN_HELP_STR
476 EVPN_HELP_STR
477 "Display information for a route distinguisher\n"
478 "VPN Route Distinguisher\n"
479 "Detailed information on TCP and BGP neighbor connections\n"
480 "Neighbor to display information about\n"
481 "Display the routes advertised to a BGP neighbor\n"
482 JSON_STR)
483 {
484 int idx_ext_community = 6;
485 int idx_ipv4 = 8;
486 int ret;
487 struct peer *peer;
488 struct prefix_rd prd;
489 union sockunion su;
490 u_char uj = use_json(argc, argv);
491
492 ret = str2sockunion (argv[idx_ipv4]->arg, &su);
493 if (ret < 0)
494 {
495 if (uj)
496 {
497 json_object *json_no = NULL;
498 json_no = json_object_new_object();
499 json_object_string_add(json_no, "warning", "Malformed address");
500 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
501 json_object_free(json_no);
502 }
503 else
504 vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE);
505 return CMD_WARNING;
506 }
507 peer = peer_lookup (NULL, &su);
508 if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN])
509 {
510 if (uj)
511 {
512 json_object *json_no = NULL;
513 json_no = json_object_new_object();
514 json_object_string_add(json_no, "warning", "No such neighbor or address family");
515 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
516 json_object_free(json_no);
517 }
518 else
519 vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
520 return CMD_WARNING;
521 }
522
523 ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd);
524 if (! ret)
525 {
526 if (uj)
527 {
528 json_object *json_no = NULL;
529 json_no = json_object_new_object();
530 json_object_string_add(json_no, "warning", "Malformed Route Distinguisher");
531 vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
532 json_object_free(json_no);
533 }
534 else
535 vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
536 return CMD_WARNING;
537 }
538
539 return show_adj_route_vpn (vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj);
540 }
541
542 DEFUN (show_ip_bgp_l2vpn_evpn_all_overlay,
543 show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
544 "show [ip] bgp l2vpn evpn all overlay",
545 SHOW_STR
546 IP_STR
547 BGP_STR
548 L2VPN_HELP_STR
549 EVPN_HELP_STR
550 "Display information about all EVPN NLRIs\n"
551 "Display BGP Overlay Information for prefixes\n")
552 {
553 return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL,
554 SHOW_DISPLAY_OVERLAY, use_json (argc, argv));
555 }
556
557 DEFUN (show_ip_bgp_evpn_rd_overlay,
558 show_ip_bgp_evpn_rd_overlay_cmd,
559 "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay",
560 SHOW_STR
561 IP_STR
562 BGP_STR
563 L2VPN_HELP_STR
564 EVPN_HELP_STR
565 "Display information for a route distinguisher\n"
566 "VPN Route Distinguisher\n"
567 "Display BGP Overlay Information for prefixes\n")
568 {
569 int idx_ext_community = 6;
570 int ret;
571 struct prefix_rd prd;
572
573 ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd);
574 if (! ret)
575 {
576 vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
577 return CMD_WARNING;
578 }
579 return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL,
580 SHOW_DISPLAY_OVERLAY, use_json (argc, argv));
581 }
582
583
584 void
585 bgp_ethernetvpn_init (void)
586 {
587 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd);
588 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd);
589 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
590 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
591 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
592 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
593 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
594 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
595 install_element (VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd);
596 install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
597 }