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>
This commit is contained in:
Philippe Guibert 2017-01-09 18:26:24 +01:00
parent dfa42ea338
commit 784d3a4299
10 changed files with 955 additions and 177 deletions

View File

@ -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@

597
bgpd/bgp_evpn_vty.c Normal file
View File

@ -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);
}

27
bgpd/bgp_evpn_vty.h Normal file
View File

@ -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 */

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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,

View File

@ -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,

200
bgpd/bgp_vpn.c Normal file
View File

@ -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;
}

30
bgpd/bgp_vpn.h Normal file
View File

@ -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 */

View File

@ -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 ();