summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/Makefile.am4
-rw-r--r--bgpd/bgp_evpn_vty.c597
-rw-r--r--bgpd/bgp_evpn_vty.h27
-rw-r--r--bgpd/bgp_mplsvpn.c177
-rw-r--r--bgpd/bgp_mplsvpn.h3
-rw-r--r--bgpd/bgp_route.c89
-rw-r--r--bgpd/bgp_route.h3
-rw-r--r--bgpd/bgp_vpn.c200
-rw-r--r--bgpd/bgp_vpn.h30
-rw-r--r--bgpd/bgpd.c2
10 files changed, 955 insertions, 177 deletions
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 <zebra.h>
+#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 <zebra.h>
+#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 <zebra.h>
+
+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 ();