summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2017-01-09 18:26:24 +0100
committerPhilippe Guibert <philippe.guibert@6wind.com>2017-02-14 13:58:58 +0100
commit784d3a4299eef5f663bb6da4b6e52bf6a6e17d68 (patch)
tree45e6b8ea174f916a294f6ab34b6b4dce54f06900
parentbgpd: handling router mac extended community (diff)
downloadfrr-784d3a4299eef5f663bb6da4b6e52bf6a6e17d68.tar.xz
frr-784d3a4299eef5f663bb6da4b6e52bf6a6e17d68.zip
bgpd: enhance EPVN vty show commands
This patch introduces show show bgp evpn commands to dump NLRI entries configured or received on BGP, related to EVPN New command introduced is the following: show [ip] bgp l2vpn evpn [all | rd <rd name> ] [overlay] Like for MPLS, similar set of commands is added for EVPN: show [ip] bgp l2vpn evpn [all|rd <RDNAME>] show [ip] bgp l2vpn evpn all neighbor <NEIGHBOR> routes show [ip] bgp l2vpn evpn all neighbor <NEIGHBOR> advertised-routes Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-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 4ce2cd03b..a9e709e23 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 000000000..9016f530b
--- /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 000000000..367a4bd20
--- /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 3e11e522f..5fd322b65 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 148e5946f..518bf6143 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 8d513fa1d..7aee689d9 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 85a8cea86..1f9586d34 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 000000000..edc5891d2
--- /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 000000000..a16914b65
--- /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 5e4340023..627d01952 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 ();