summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_evpn_vty.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_evpn_vty.c')
-rw-r--r--bgpd/bgp_evpn_vty.c402
1 files changed, 398 insertions, 4 deletions
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 12f18016b..2f4349b32 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -328,6 +328,7 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
vty_out(vty,
"EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
+ vty_out(vty, "EVPN type-4 prefix: [4]:[ESI]:[IPlen]:[OrigIP]\n");
vty_out(vty, "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
vty_out(vty, "%s", ri_header);
}
@@ -409,6 +410,45 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object_object_add(json, "exportRts", json_export_rtl);
}
+static void display_es(struct vty *vty, struct evpnes *es, json_object *json)
+{
+ struct in_addr *vtep;
+ char buf[ESI_STR_LEN];
+ char buf1[RD_ADDRSTRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ struct listnode *node = NULL;
+ json_object *json_vteps = NULL;
+
+ if (json) {
+ json_vteps = json_object_new_array();
+ json_object_string_add(json, "esi",
+ esi_to_str(&es->esi, buf, sizeof(buf)));
+ json_object_string_add(json, "rd",
+ prefix_rd2str(&es->prd, buf1,
+ sizeof(buf1)));
+ json_object_string_add(json,"originatorIp",
+ ipaddr2str(&es->originator_ip, buf2, sizeof(buf2)));
+ if (es->vtep_list) {
+ for (ALL_LIST_ELEMENTS_RO(es->vtep_list, node, vtep))
+ json_object_array_add(json_vteps,
+ json_object_new_string(inet_ntoa(*vtep)));
+ }
+ json_object_object_add(json, "vteps", json_vteps);
+ } else {
+ vty_out(vty, "ESI: %s\n",
+ esi_to_str(&es->esi, buf, sizeof(buf)));
+ vty_out(vty, " RD: %s\n", prefix_rd2str(&es->prd, buf1,
+ sizeof(buf1)));
+ vty_out(vty, " Originator-IP: %s\n",
+ ipaddr2str(&es->originator_ip, buf2, sizeof(buf2)));
+ if (es->vtep_list) {
+ vty_out(vty, " VTEP List:\n");
+ for (ALL_LIST_ELEMENTS_RO(es->vtep_list, node, vtep))
+ vty_out(vty," %s\n", inet_ntoa(*vtep));
+ }
+ }
+}
+
static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
{
char buf1[RD_ADDRSTRLEN];
@@ -487,6 +527,88 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object_object_add(json, "exportRts", json_export_rtl);
}
+static void show_esi_routes(struct bgp *bgp,
+ struct evpnes *es,
+ struct vty *vty,
+ json_object *json)
+{
+ int header = 1;
+ struct bgp_node *rn;
+ struct bgp_info *ri;
+ uint32_t prefix_cnt, path_cnt;
+ uint64_t tbl_ver;
+
+ prefix_cnt = path_cnt = 0;
+
+ tbl_ver = es->route_table->version;
+ for (rn = bgp_table_top(es->route_table); rn;
+ rn = bgp_route_next(rn)) {
+ int add_prefix_to_json = 0;
+ char prefix_str[BUFSIZ];
+ json_object *json_paths = NULL;
+ json_object *json_prefix = NULL;
+
+ bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+ sizeof(prefix_str));
+
+ if (json)
+ json_prefix = json_object_new_object();
+
+ if (rn->info) {
+ /* Overall header/legend displayed once. */
+ if (header) {
+ bgp_evpn_show_route_header(vty, bgp,
+ tbl_ver, json);
+ header = 0;
+ }
+
+ prefix_cnt++;
+ }
+
+ if (json)
+ json_paths = json_object_new_array();
+
+ /* For EVPN, the prefix is displayed for each path (to fit in
+ * with code that already exists).
+ */
+ for (ri = rn->info; ri; ri = ri->next) {
+ json_object *json_path = NULL;
+
+ if (json)
+ json_path = json_object_new_array();
+
+ route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, json_path);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+
+ path_cnt++;
+ add_prefix_to_json = 1;
+ }
+
+ if (json && add_prefix_to_json) {
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json, prefix_str, json_prefix);
+ }
+ }
+
+ if (json) {
+ json_object_int_add(json, "numPrefix", prefix_cnt);
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ if (prefix_cnt == 0)
+ vty_out(vty, "No EVPN prefixes exist for this ESI");
+ else
+ vty_out(vty, "\nDisplayed %u prefixes (%u paths)\n",
+ prefix_cnt, path_cnt);
+ }
+}
+
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
struct vty *vty, struct in_addr vtep_ip,
json_object *json)
@@ -575,7 +697,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
vty_out(vty, "No EVPN prefixes %sexist for this VNI",
type ? "(of requested type) " : "");
else
- vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s",
+ vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
prefix_cnt, path_cnt,
type ? " (of requested type)" : "");
}
@@ -707,6 +829,47 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
}
}
+static void show_es_entry(struct hash_backet *backet, void *args[])
+{
+ char buf[ESI_STR_LEN];
+ char buf1[RD_ADDRSTRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ struct in_addr *vtep = NULL;
+ struct vty *vty = args[0];
+ json_object *json = args[1];
+ json_object *json_vteps = NULL;
+ struct listnode *node = NULL;
+ struct evpnes *es = (struct evpnes *)backet->data;
+
+ if (json) {
+ json_vteps = json_object_new_array();
+ json_object_string_add(json, "esi",
+ esi_to_str(&es->esi, buf, sizeof(buf)));
+ json_object_string_add(json, "type",
+ is_es_local(es) ? "Local" : "Remote");
+ json_object_string_add(json, "rd",
+ prefix_rd2str(&es->prd, buf1,
+ sizeof(buf1)));
+ json_object_string_add(json,"originatorIp",
+ ipaddr2str(&es->originator_ip, buf2, sizeof(buf2)));
+ if (es->vtep_list) {
+ for (ALL_LIST_ELEMENTS_RO(es->vtep_list, node, vtep))
+ json_object_array_add(json_vteps,
+ json_object_new_string(
+ inet_ntoa(*vtep)));
+ }
+ json_object_object_add(json, "vteps", json_vteps);
+ } else {
+ vty_out(vty, "%-30s %-6s %-21s %-15s %-6d\n",
+ esi_to_str(&es->esi, buf, sizeof(buf)),
+ is_es_local(es) ? "Local" : "Remote",
+ prefix_rd2str(&es->prd, buf1, sizeof(buf1)),
+ ipaddr2str(&es->originator_ip, buf2,
+ sizeof(buf2)),
+ es->vtep_list ? listcount(es->vtep_list) : 0);
+ }
+}
+
static void show_vni_entry(struct hash_backet *backet, void *args[])
{
struct vty *vty;
@@ -1969,6 +2132,23 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
}
}
+/* Disaplay EVPN routes for a ESI - VTY handler */
+static void evpn_show_routes_esi(struct vty *vty, struct bgp *bgp,
+ esi_t *esi, json_object *json)
+{
+ struct evpnes *es = NULL;
+
+ /* locate the ES */
+ es = bgp_evpn_lookup_es(bgp, esi);
+ if (!es) {
+ if (!json)
+ vty_out(vty, "ESI not found\n");
+ return;
+ }
+
+ show_esi_routes(bgp, es, vty, json);
+}
+
/*
* Display EVPN routes for a VNI - vty handler.
* If 'type' is non-zero, only routes matching that type are shown.
@@ -2318,6 +2498,42 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
}
}
+/* Display specific ES */
+static void evpn_show_es(struct vty *vty, struct bgp *bgp, esi_t *esi,
+ json_object *json)
+{
+ struct evpnes *es = NULL;
+
+ es = bgp_evpn_lookup_es(bgp, esi);
+ if (es) {
+ display_es(vty, es, json);
+ } else {
+ if (json) {
+ vty_out(vty, "{}\n");
+ } else {
+ vty_out(vty, "ESI not found\n");
+ return;
+ }
+ }
+}
+
+/* Display all ESs */
+static void evpn_show_all_es(struct vty *vty, struct bgp *bgp, json_object *json)
+{
+ void *args[2];
+
+ if (!json)
+ vty_out(vty, "%-30s %-6s %-21s %-15s %-6s\n",
+ "ESI", "Type", "RD", "Originator-IP", "#VTEPs");
+
+ /* print all ESs */
+ args[0] = vty;
+ args[1] = json;
+ hash_iterate(bgp->esihash,
+ (void (*)(struct hash_backet *, void *))show_es_entry,
+ args);
+}
+
/*
* Display specified VNI (vty handler)
*/
@@ -3027,6 +3243,58 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
return CMD_SUCCESS;
}
+/* Disaply ES */
+DEFUN(show_bgp_l2vpn_evpn_es,
+ show_bgp_l2vpn_evpn_es_cmd,
+ "show bgp l2vpn evpn es [ESI] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "ethernet-Segment\n"
+ "Ethernet-Segment Identifier\n")
+{
+ int idx = 0;
+ uint8_t uj = 0;
+ esi_t esi = {0};
+ json_object *json = NULL;
+ struct bgp *bgp = NULL;
+
+ uj = use_json(argc, argv);
+
+ bgp = bgp_get_default();
+ if (!bgp)
+ return CMD_WARNING;
+
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ if ((uj && argc == ((idx + 1) + 2)) ||
+ (!uj && argc == (idx + 1) + 1)) {
+
+ /* show all ESs */
+ evpn_show_all_es(vty, bgp, json);
+ } else {
+
+ /* show a specific ES */
+
+ /* get the ESI - ESI-ID is at argv[5] */
+ if (!str_to_esi(argv[idx + 2]->arg, &esi)) {
+ vty_out(vty, "%% Malformed ESI\n");
+ return CMD_WARNING;
+ }
+ evpn_show_es(vty, bgp, &esi, json);
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
/*
* Display EVPN neighbor summary.
*/
@@ -3056,7 +3324,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
*/
DEFUN(show_bgp_l2vpn_evpn_route,
show_bgp_l2vpn_evpn_route_cmd,
- "show bgp l2vpn evpn route [type <macip|multicast|prefix>] [json]",
+ "show bgp l2vpn evpn route [type <macip|multicast|es|prefix>] [json]",
SHOW_STR
BGP_STR
L2VPN_HELP_STR
@@ -3065,7 +3333,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n"
- "Prefix route\n"
+ "Ethernet Segment (type-4) route \n"
+ "Prefix (type-5 )route\n"
JSON_STR)
{
struct bgp *bgp;
@@ -3090,6 +3359,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
type = BGP_EVPN_MAC_IP_ROUTE;
else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE;
+ else if (strncmp(argv[type_idx + 1]->arg, "es", 2) == 0)
+ type = BGP_EVPN_ES_ROUTE;
else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
type = BGP_EVPN_IP_PREFIX_ROUTE;
else
@@ -3111,7 +3382,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
*/
DEFUN(show_bgp_l2vpn_evpn_route_rd,
show_bgp_l2vpn_evpn_route_rd_cmd,
- "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast|prefix>] [json]",
+ "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast|es|prefix>] [json]",
SHOW_STR
BGP_STR
L2VPN_HELP_STR
@@ -3122,6 +3393,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n"
+ "Ethernet Segment route\n"
"Prefix route\n"
JSON_STR)
{
@@ -3255,6 +3527,50 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
return CMD_SUCCESS;
}
+/* Display per ESI routing table */
+DEFUN(show_bgp_l2vpn_evpn_route_esi,
+ show_bgp_l2vpn_evpn_route_esi_cmd,
+ "show bgp l2vpn evpn route esi ESI [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "Ethernet Segment Identifier\n"
+ "ESI ID\n"
+ JSON_STR)
+{
+ int uj = 0;
+ esi_t esi = {0};
+ struct bgp *bgp = NULL;
+ json_object *json = NULL;
+
+ bgp = bgp_get_default();
+ if (!bgp)
+ return CMD_WARNING;
+
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
+ /* get the ESI - ESI-ID is at argv[6] */
+ if (!str_to_esi(argv[6]->arg, &esi)) {
+ vty_out(vty, "%% Malformed ESI\n");
+ return CMD_WARNING;
+ }
+
+ evpn_show_routes_esi(vty, bgp, &esi, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+
/*
* Display per-VNI EVPN routing table.
*/
@@ -3583,6 +3899,78 @@ DEFUN(show_bgp_l2vpn_evpn_import_rt,
}
#if defined(HAVE_CUMULUS)
+DEFUN(test_adv_evpn_type4_route,
+ test_adv_evpn_type4_route_cmd,
+ "advertise es ESI",
+ "Advertise EVPN ES route\n"
+ "Ethernet-segment\n"
+ "Ethernet-Segment Identifier\n")
+{
+ int ret = 0;
+ esi_t esi;
+ struct bgp *bgp;
+ struct ipaddr vtep_ip;
+
+ bgp = bgp_get_default();
+ if (!bgp) {
+ vty_out(vty, "%%Default BGP instance not yet created\n");
+ return CMD_WARNING;
+ }
+
+ if(!str_to_esi(argv[2]->arg, &esi)) {
+ vty_out(vty, "%%Malformed ESI\n");
+ return CMD_WARNING;
+ }
+
+ vtep_ip.ipa_type = IPADDR_V4;
+ vtep_ip.ipaddr_v4 = bgp->router_id;
+
+ ret = bgp_evpn_local_es_add(bgp, &esi, &vtep_ip);
+ if (ret == -1) {
+ vty_out(vty, "%%Failed to EVPN advertise type-4 route\n");
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(test_withdraw_evpn_type4_route,
+ test_withdraw_evpn_type4_route_cmd,
+ "withdraw es ESI",
+ "Advertise EVPN ES route\n"
+ "Ethernet-segment\n"
+ "Ethernet-Segment Identifier\n")
+{
+ int ret = 0;
+ esi_t esi;
+ struct bgp *bgp;
+ struct ipaddr vtep_ip;
+
+ bgp = bgp_get_default();
+ if (!bgp) {
+ vty_out(vty, "%%Default BGP instance not yet created\n");
+ return CMD_WARNING;
+ }
+
+ if (!bgp->peer_self) {
+ vty_out(vty, "%%BGP instance doesnt have self peer\n");
+ return CMD_WARNING;
+ }
+
+ if(!str_to_esi(argv[2]->arg, &esi)) {
+ vty_out(vty, "%%Malformed ESI\n");
+ return CMD_WARNING;
+ }
+
+ vtep_ip.ipa_type = IPADDR_V4;
+ vtep_ip.ipaddr_v4 = bgp->router_id;
+ ret = bgp_evpn_local_es_del(bgp, &esi, &vtep_ip);
+ if (ret == -1) {
+ vty_out(vty, "%%Failed to withdraw EVPN type-4 route\n");
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd,
"show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR
"Show VNI\n"
@@ -4543,12 +4931,18 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
+ /* test commands */
+ install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd);
+ install_element(BGP_EVPN_NODE, &test_withdraw_evpn_type4_route_cmd);
+
/* "show bgp l2vpn evpn" commands. */
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_esi_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
install_element(VIEW_NODE,
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd);