diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 4ce2cd03b5..a9e709e231 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -80,7 +80,7 @@ libbgp_a_SOURCES = \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ - bgp_evpn.c + bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c noinst_HEADERS = \ bgp_memory.h \ @@ -91,7 +91,7 @@ noinst_HEADERS = \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h + $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c new file mode 100644 index 0000000000..9016f530bc --- /dev/null +++ b/bgpd/bgp_evpn_vty.c @@ -0,0 +1,597 @@ +/* Ethernet-VPN Packet and vty Processing File + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include +#include "command.h" +#include "prefix.h" +#include "lib/json.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_vpn.h" +#include "bgpd/bgp_evpn_vty.h" + +#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" +#define EVPN_HELP_STR "Ethernet Virtual Private Network\n" + +#define SHOW_DISPLAY_STANDARD 0 +#define SHOW_DISPLAY_TAGS 1 +#define SHOW_DISPLAY_OVERLAY 2 + +static int +bgp_show_ethernet_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, + void *output_arg, int option, u_char use_json) +{ + afi_t afi = AFI_L2VPN; + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; + char v4_header_overlay[] = " Network Next Hop EthTag Overlay Index RouterMac%s"; + + unsigned long output_count = 0; + unsigned long total_count = 0; + json_object *json = NULL; + json_object *json_nroute = NULL; + json_object *json_array = NULL; + json_object *json_scode = NULL; + json_object *json_ocode = NULL; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + if (!use_json) + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (use_json) + { + json_scode = json_object_new_object(); + json_ocode = json_object_new_object(); + json = json_object_new_object(); + json_nroute = json_object_new_object(); + + json_object_string_add(json_scode, "suppressed", "s"); + json_object_string_add(json_scode, "damped", "d"); + json_object_string_add(json_scode, "history", "h"); + json_object_string_add(json_scode, "valid", "*"); + json_object_string_add(json_scode, "best", ">"); + json_object_string_add(json_scode, "internal", "i"); + + json_object_string_add(json_ocode, "igp", "i"); + json_object_string_add(json_ocode, "egp", "e"); + json_object_string_add(json_ocode, "incomplete", "?"); + } + + for (rn = bgp_table_top (bgp->rib[afi][SAFI_EVPN]); rn; rn = bgp_route_next (rn)) + { + if (use_json) + continue; /* XXX json TODO */ + + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + for (ri = rm->info; ri; ri = ri->next) + { + total_count++; + if (type == bgp_show_type_neighbor) + { + union sockunion *su = output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (header == 0) + { + if (use_json) + { + if (option == SHOW_DISPLAY_TAGS) + { + json_object_int_add(json, "bgpTableVersion", 0); + json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); + json_object_object_add(json, "bgpStatusCodes", json_scode); + json_object_object_add(json, "bgpOriginCodes", json_ocode); + } + } + else + { + if (option == SHOW_DISPLAY_TAGS) + vty_out (vty, v4_header_tag, VTY_NEWLINE); + else if (option == SHOW_DISPLAY_OVERLAY) + vty_out (vty, v4_header_overlay, VTY_NEWLINE); + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + } + header = 0; + } + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4 (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); + if (use_json) + { + char buffer[BUFSIZ]; + if (type == RD_TYPE_AS || type == RD_TYPE_AS4) + sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + json_object_string_add(json_nroute, "routeDistinguisher", buffer); + } + else + { + vty_out (vty, "Route Distinguisher: "); + if (type == RD_TYPE_AS) + vty_out (vty, "as2 %u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_AS4) + vty_out (vty, "as4 %u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "ip %s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + vty_out (vty, "%s", VTY_NEWLINE); + } + rd_header = 0; + } + if (use_json) + json_array = json_object_new_array(); + else + json_array = NULL; + if (option == SHOW_DISPLAY_TAGS) + route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_EVPN, json_array); + else if (option == SHOW_DISPLAY_OVERLAY) + route_vty_out_overlay (vty, &rm->p, ri, 0, json_array); + else + route_vty_out (vty, &rm->p, ri, 0, SAFI_EVPN, json_array); + output_count++; + } + /* XXX json */ + } + } + if (output_count == 0) + vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); + else + vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", + VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_l2vpn_evpn, + show_ip_bgp_l2vpn_evpn_cmd, + "show [ip] bgp l2vpn evpn [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + JSON_STR) +{ + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd, + show_ip_bgp_l2vpn_evpn_rd_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + JSON_STR) +{ + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_tags, + show_ip_bgp_l2vpn_evpn_all_tags_cmd, + "show [ip] bgp l2vpn evpn all tags", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 1, 0); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd_tags, + show_ip_bgp_l2vpn_evpn_rd_tags_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn (vty,&prd, bgp_show_type_normal, NULL, 1, 0); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_routes, + show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n" + JSON_STR) +{ + int idx_ipv4 = 6; + union sockunion su; + struct peer *peer; + int ret; + u_char uj = use_json(argc, argv); + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, + show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n" + JSON_STR) +{ + int idx_ext_community = 6; + int idx_ipv4 = 8; + int ret; + union sockunion su; + struct peer *peer; + struct prefix_rd prd; + u_char uj = use_json(argc, argv); + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n" + JSON_STR) +{ + int idx_ipv4 = 7; + int ret; + struct peer *peer; + union sockunion su; + u_char uj = use_json(argc, argv); + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n" + JSON_STR) +{ + int idx_ext_community = 6; + int idx_ipv4 = 8; + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + u_char uj = use_json(argc, argv); + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_overlay, + show_ip_bgp_l2vpn_evpn_all_overlay_cmd, + "show [ip] bgp l2vpn evpn all overlay", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Display BGP Overlay Information for prefixes\n") +{ + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, + SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); +} + +DEFUN (show_ip_bgp_evpn_rd_overlay, + show_ip_bgp_evpn_rd_overlay_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP Overlay Information for prefixes\n") +{ + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, + SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); +} + + +void +bgp_ethernetvpn_init (void) +{ + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); +} diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h new file mode 100644 index 0000000000..367a4bd20d --- /dev/null +++ b/bgpd/bgp_evpn_vty.h @@ -0,0 +1,27 @@ +/* EVPN VTY functions to EVPN + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _FRR_BGP_EVPN_VTY_H +#define _FRR_BGP_EVPN_VTY_H + +extern void +bgp_ethernetvpn_init (void); + +#endif /* _QUAGGA_BGP_EVPN_VTY_H */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3e11e522fa..5fd322b65e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_vpn.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -146,7 +147,7 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) #if ENABLE_BGP_VNC /* type == RD_TYPE_VNC_ETH */ -static void +void decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth) { rd_vnc_eth->type = RD_TYPE_VNC_ETH; @@ -550,175 +551,6 @@ DEFUN (no_vpnv6_network, return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg); } -#if defined(KEEP_OLD_VPN_COMMANDS) -static int -show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi) -{ - struct bgp *bgp; - struct bgp_table *table; - struct bgp_node *rn; - struct bgp_node *rm; - struct attr *attr; - int rd_header; - int header = 1; - char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; - json_object *json = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; - json_object *json_routes = NULL; - json_object *json_array = NULL; - - bgp = bgp_get_default (); - if (bgp == NULL) - { - if (!use_json) - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (use_json) - { - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); - json_routes = json_object_new_object(); - json = json_object_new_object(); - - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "internal", "i"); - - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); - } - - for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn; - rn = bgp_route_next (rn)) - { - if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) - continue; - - if ((table = rn->info) != NULL) - { - if (use_json) - json_array = json_object_new_array(); - else - json_array = NULL; - - rd_header = 1; - - for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) - { - if ((attr = rm->info) != NULL) - { - if (header) - { - if (use_json) - { - json_object_int_add(json, "bgpTableVersion", 0); - json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); - json_object_object_add(json, "bgpStatusCodes", json_scode); - json_object_object_add(json, "bgpOriginCodes", json_ocode); - } - else - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", - inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", - VTY_NEWLINE); - vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", - VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, v4_header, VTY_NEWLINE); - } - header = 0; - } - - if (rd_header) - { - u_int16_t type; - struct rd_as rd_as; - struct rd_ip rd_ip = {0}; -#if ENABLE_BGP_VNC - struct rd_vnc_eth rd_vnc_eth = {0}; -#endif - u_char *pnt; - - pnt = rn->p.u.val; - - /* Decode RD type. */ - type = decode_rd_type (pnt); - /* Decode RD value. */ - if (type == RD_TYPE_AS) - decode_rd_as (pnt + 2, &rd_as); - else if (type == RD_TYPE_AS4) - decode_rd_as4 (pnt + 2, &rd_as); - else if (type == RD_TYPE_IP) - decode_rd_ip (pnt + 2, &rd_ip); -#if ENABLE_BGP_VNC - else if (type == RD_TYPE_VNC_ETH) - decode_rd_vnc_eth (pnt, &rd_vnc_eth); -#endif - - if (use_json) - { - char buffer[BUFSIZ]; - if (type == RD_TYPE_AS || type == RD_TYPE_AS4) - sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_IP) - sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); - json_object_string_add(json_routes, "routeDistinguisher", buffer); - } - else - { - vty_out (vty, "Route Distinguisher: "); - - if (type == RD_TYPE_AS || type == RD_TYPE_AS4) - vty_out (vty, "%u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_IP) - vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); -#if ENABLE_BGP_VNC - else if (type == RD_TYPE_VNC_ETH) - vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", - rd_vnc_eth.local_nve_id, - rd_vnc_eth.macaddr.octet[0], - rd_vnc_eth.macaddr.octet[1], - rd_vnc_eth.macaddr.octet[2], - rd_vnc_eth.macaddr.octet[3], - rd_vnc_eth.macaddr.octet[4], - rd_vnc_eth.macaddr.octet[5]); -#endif - - vty_out (vty, "%s", VTY_NEWLINE); - } - rd_header = 0; - } - route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array); - } - } - if (use_json) - { - struct prefix *p; - char buf_a[BUFSIZ]; - char buf_b[BUFSIZ]; - p = &rm->p; - sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen); - json_object_object_add(json_routes, buf_a, json_array); - } - } - } - if (use_json) - { - json_object_object_add(json, "routes", json_routes); - vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); - json_object_free(json); - } - return CMD_SUCCESS; -} -#endif - int bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int tags, u_char use_json) @@ -1281,8 +1113,7 @@ DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes, vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - - return show_adj_route_vpn (vty, peer, NULL, uj, afi); + return show_adj_route_vpn (vty, peer, NULL, AFI_IP, SAFI_MPLS_VPN, uj); } return CMD_SUCCESS; } @@ -1360,7 +1191,7 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, return CMD_WARNING; } - return show_adj_route_vpn (vty, peer, &prd, uj, afi); + return show_adj_route_vpn (vty, peer, &prd, AFI_IP, SAFI_MPLS_VPN, uj); } return CMD_SUCCESS; } diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 148e5946f1..518bf6143f 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -100,7 +100,8 @@ extern void decode_rd_as (u_char *, struct rd_as *); extern void decode_rd_as4 (u_char *, struct rd_as *); extern void decode_rd_ip (u_char *, struct rd_ip *); #if ENABLE_BGP_VNC -extern void decode_vnc_eth (u_char *, struct rd_vnc_eth *); +extern void +decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth); #endif extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8d513fa1dc..7aee689d9c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6374,7 +6374,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, json_object *json_out = NULL; struct attr *attr; u_int32_t label = 0; - + if (!binfo->extra) return; @@ -6464,10 +6464,97 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, else { vty_out (vty, "notag/%d", label); + vty_out (vty, "%s", VTY_NEWLINE); } } +void +route_vty_out_overlay (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, json_object *json_paths) +{ + struct attr *attr; + char buf[BUFSIZ]; + json_object *json_path = NULL; + + if (json_paths) + json_path = json_object_new_object(); + + if (!binfo->extra) + return; + + /* short status lead text */ + route_vty_short_status_out (vty, binfo, json_path); + + /* print prefix and mask */ + if (! display) + route_vty_out_route (p, vty); + else + vty_out (vty, "%*s", 17, " "); + + /* Print attribute */ + attr = binfo->attr; + if (attr) + { + if (attr->extra) + { + char buf1[BUFSIZ]; + int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len); + + switch (af) { + case AF_INET: + vty_out (vty, "%-16s", inet_ntop(af, + &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); + break; + case AF_INET6: + vty_out (vty, "%s(%s)", + inet_ntop (af, + &attr->extra->mp_nexthop_global, buf, BUFSIZ), + inet_ntop (af, + &attr->extra->mp_nexthop_local, buf1, BUFSIZ)); + break; + default: + vty_out(vty, "?"); + } + } else { + vty_out(vty, "?"); + } + } + + if(attr->extra) + { + struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id); + char *str = esi2str(id); + vty_out (vty, "%s", str); + free(str); + if (p->u.prefix_evpn.flags & IP_PREFIX_V4) + { + vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4)); + } + else if (p->u.prefix_evpn.flags & IP_PREFIX_V6) + { + vty_out (vty, "/%s", + inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6), + buf, BUFSIZ)); + } + if(attr->extra->ecommunity) + { + char *mac = NULL; + struct ecommunity_val *routermac = ecommunity_lookup (attr->extra->ecommunity, + ECOMMUNITY_ENCODE_EVPN, + ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); + if(routermac) + mac = ecom_mac2str((char *)routermac->val); + if(mac) + { + vty_out (vty, "/%s",(char *)mac); + free(mac); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + /* dampening route */ static void damp_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 85a8cea860..1f9586d343 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -358,6 +358,9 @@ extern safi_t bgp_node_safi (struct vty *); extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *); extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t, u_char, json_object *); +extern void +route_vty_out_overlay (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, json_object *json); extern int subgroup_process_announce_selected (struct update_subgroup *subgrp, diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c new file mode 100644 index 0000000000..edc5891d22 --- /dev/null +++ b/bgpd/bgp_vpn.c @@ -0,0 +1,200 @@ +/* VPN Related functions + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include +#include "command.h" +#include "prefix.h" +#include "lib/json.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_vpn.h" + +int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, + afi_t afi, safi_t safi, u_char use_json) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct attr *attr; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + json_object *json = NULL; + json_object *json_scode = NULL; + json_object *json_ocode = NULL; + json_object *json_routes = NULL; + json_object *json_array = NULL; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + if (!use_json) + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (use_json) + { + json_scode = json_object_new_object(); + json_ocode = json_object_new_object(); + json_routes = json_object_new_object(); + json = json_object_new_object(); + + json_object_string_add(json_scode, "suppressed", "s"); + json_object_string_add(json_scode, "damped", "d"); + json_object_string_add(json_scode, "history", "h"); + json_object_string_add(json_scode, "valid", "*"); + json_object_string_add(json_scode, "best", ">"); + json_object_string_add(json_scode, "internal", "i"); + + json_object_string_add(json_ocode, "igp", "i"); + json_object_string_add(json_ocode, "egp", "e"); + json_object_string_add(json_ocode, "incomplete", "?"); + } + + for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn; + rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + if (use_json) + json_array = json_object_new_array(); + else + json_array = NULL; + + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + { + if ((attr = rm->info) != NULL) + { + if (header) + { + if (use_json) + { + json_object_int_add(json, "bgpTableVersion", 0); + json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); + json_object_object_add(json, "bgpStatusCodes", json_scode); + json_object_object_add(json, "bgpOriginCodes", json_ocode); + } + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip = {0}; +#if ENABLE_BGP_VNC + struct rd_vnc_eth rd_vnc_eth = {0}; +#endif + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4 (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); +#if ENABLE_BGP_VNC + else if (type == RD_TYPE_VNC_ETH) + decode_rd_vnc_eth (pnt, &rd_vnc_eth); +#endif + + if (use_json) + { + char buffer[BUFSIZ]; + if (type == RD_TYPE_AS || type == RD_TYPE_AS4) + sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + json_object_string_add(json_routes, "routeDistinguisher", buffer); + } + else + { + vty_out (vty, "Route Distinguisher: "); + + if (type == RD_TYPE_AS || type == RD_TYPE_AS4) + vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); +#if ENABLE_BGP_VNC + else if (type == RD_TYPE_VNC_ETH) + vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", + rd_vnc_eth.local_nve_id, + rd_vnc_eth.macaddr.octet[0], + rd_vnc_eth.macaddr.octet[1], + rd_vnc_eth.macaddr.octet[2], + rd_vnc_eth.macaddr.octet[3], + rd_vnc_eth.macaddr.octet[4], + rd_vnc_eth.macaddr.octet[5]); +#endif + + vty_out (vty, "%s", VTY_NEWLINE); + } + rd_header = 0; + } + route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array); + } + } + if (use_json) + { + struct prefix *p; + char buf_a[BUFSIZ]; + char buf_b[BUFSIZ]; + p = &rm->p; + sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen); + json_object_object_add(json_routes, buf_a, json_array); + } + } + } + if (use_json) + { + json_object_object_add(json, "routes", json_routes); + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } + return CMD_SUCCESS; +} + diff --git a/bgpd/bgp_vpn.h b/bgpd/bgp_vpn.h new file mode 100644 index 0000000000..a16914b65e --- /dev/null +++ b/bgpd/bgp_vpn.h @@ -0,0 +1,30 @@ +/* VPN common functions to MP-BGP + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _FRR_BGP_VPN_H +#define _FRR_BGP_VPN_H + +#include + +extern int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, + afi_t afi, safi_t safi, u_char use_json); + +#endif /* _QUAGGA_BGP_VPN_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5e43400237..627d019523 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -78,6 +78,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_evpn_vty.h" DEFINE_QOBJ_TYPE(bgp_master) DEFINE_QOBJ_TYPE(bgp) @@ -7625,6 +7626,7 @@ bgp_init (void) #if ENABLE_BGP_VNC rfapi_init (); #endif + bgp_ethernetvpn_init (); /* Access list initialize. */ access_list_init ();