*: support for evpn type-4 route

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
mitesh 2018-04-13 15:01:12 -07:00 committed by Donald Sharp
parent 68542a6da6
commit 50f74cf131
15 changed files with 1692 additions and 105 deletions

View File

@ -801,6 +801,20 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
len = sprintf(
str_buf + str_pnt,
"FS:marking %u", *(pnt+5));
} else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT) {
struct ethaddr mac;
pnt++;
memcpy(&mac, pnt, ETH_ALEN);
len = sprintf(
str_buf + str_pnt,
"ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
(uint8_t)mac.octet[0],
(uint8_t)mac.octet[1],
(uint8_t)mac.octet[2],
(uint8_t)mac.octet[3],
(uint8_t)mac.octet[4],
(uint8_t)mac.octet[5]);
} else
unk_ecom = 1;
} else {

File diff suppressed because it is too large Load Diff

View File

@ -141,6 +141,10 @@ extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id);
extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
struct ipaddr *originator_ip);
extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi,
struct ipaddr *originator_ip);
extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
extern void bgp_evpn_cleanup(struct bgp *bgp);
extern void bgp_evpn_init(struct bgp *bgp);

View File

@ -31,9 +31,7 @@
#define RT_ADDRSTRLEN 28
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
#define EVPN_TYPE_2_ROUTE_PREFIXLEN 224
#define EVPN_TYPE_3_ROUTE_PREFIXLEN 224
#define EVPN_TYPE_5_ROUTE_PREFIXLEN 224
#define EVPN_ROUTE_PREFIXLEN 224
/* EVPN route types. */
typedef enum {
@ -98,6 +96,38 @@ struct bgpevpn {
DECLARE_QOBJ_TYPE(bgpevpn)
struct evpnes {
/* Ethernet Segment Identifier */
esi_t esi;
/* es flags */
uint16_t flags;
#define EVPNES_LOCAL 0x01
#define EVPNES_REMOTE 0x02
/* Id for deriving the RD
* automatically for this ESI */
uint16_t rd_id;
/* RD for this VNI. */
struct prefix_rd prd;
/* originator ip address */
struct ipaddr originator_ip;
/* list of VTEPs in the same site */
struct list *vtep_list;
/* Route table for EVPN routes for
* this ESI. - type4 routes */
struct bgp_table *route_table;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(evpnes)
/* Mapping of Import RT to VNIs.
* The Import RTs of all VNIs are maintained in a hash table with each
* RT linking to all VNIs that will import routes matching this RT.
@ -238,6 +268,15 @@ static inline int is_vni_param_configured(struct bgpevpn *vpn)
|| is_export_rt_configured(vpn));
}
static inline void encode_es_rt_extcomm(struct ecommunity_val *eval,
struct ethaddr *mac)
{
memset(eval, 0, sizeof(struct ecommunity_val));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT;
memcpy(&eval->val[2], mac, ETH_ALEN);
}
static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
struct ethaddr *rmac)
{
@ -326,7 +365,7 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
{
memset(p, 0, sizeof(struct prefix_evpn));
p->family = AF_EVPN;
p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p->prefixlen = EVPN_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
memcpy(&p->prefix.macip_addr.mac.octet, mac->octet, ETH_ALEN);
p->prefix.macip_addr.ip.ipa_type = IPADDR_NONE;
@ -352,7 +391,7 @@ static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp,
memset(evp, 0, sizeof(struct prefix_evpn));
evp->family = AF_EVPN;
evp->prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN;
evp->prefixlen = EVPN_ROUTE_PREFIXLEN;
evp->prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
evp->prefix.prefix_addr.ip_prefix_length = ip_prefix->prefixlen;
evp->prefix.prefix_addr.ip.ipa_type = ip.ipa_type;
@ -364,12 +403,26 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
{
memset(p, 0, sizeof(struct prefix_evpn));
p->family = AF_EVPN;
p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p->prefixlen = EVPN_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_IMET_ROUTE;
p->prefix.imet_addr.ip.ipa_type = IPADDR_V4;
p->prefix.imet_addr.ip.ipaddr_v4 = originator_ip;
}
static inline void build_evpn_type4_prefix(struct prefix_evpn *p,
esi_t *esi,
struct in_addr originator_ip)
{
memset(p, 0, sizeof(struct prefix_evpn));
p->family = AF_EVPN;
p->prefixlen = EVPN_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_ES_ROUTE;
p->prefix.es_addr.ip_prefix_length = IPV4_MAX_BITLEN;
p->prefix.es_addr.ip.ipa_type = IPADDR_V4;
p->prefix.es_addr.ip.ipaddr_v4 = originator_ip;
memcpy(&p->prefix.es_addr.esi, esi, sizeof(esi_t));
}
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
safi_t safi)
{
@ -384,6 +437,20 @@ static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
return 0;
}
static inline void es_get_system_mac(esi_t *esi,
struct ethaddr *mac)
{
/* for type-1 and type-3 ESIs,
the system mac starts at val[1]
*/
memcpy(mac, &esi->val[1], ETH_ALEN);
}
static inline int is_es_local(struct evpnes *es)
{
return CHECK_FLAG(es->flags, EVPNES_LOCAL) ? 1 : 0;
}
extern void evpn_rt_delete_auto(struct bgp *, vni_t, struct list *);
extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomadd);
@ -417,4 +484,8 @@ extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id);
extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
extern struct evpnes *bgp_evpn_lookup_es(struct bgp *bgp, esi_t *esi);
extern struct evpnes *bgp_evpn_es_new(struct bgp *bgp, esi_t *esi,
struct ipaddr *originator_ip);
extern void bgp_evpn_es_free(struct bgp *bgp, struct evpnes *es);
#endif /* _BGP_EVPN_PRIVATE_H */

View File

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

View File

@ -116,6 +116,8 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP Ip")
DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information")
DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")

View File

@ -111,6 +111,9 @@ DECLARE_MTYPE(LCOMMUNITY)
DECLARE_MTYPE(LCOMMUNITY_STR)
DECLARE_MTYPE(LCOMMUNITY_VAL)
DECLARE_MTYPE(BGP_EVPN_ES)
DECLARE_MTYPE(BGP_EVPN_ES_VTEP)
DECLARE_MTYPE(BGP_EVPN)
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)

View File

@ -2107,12 +2107,10 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
struct bgp_info *mpinfo;
/* If this is multipath, check all selected paths for any nexthop change
* or
* attribute change. Some attribute changes (e.g., community) aren't of
* or attribute change. Some attribute changes (e.g., community) aren't of
* relevance to the RIB, but we'll update zebra to ensure we handle the
* case of BGP nexthop change. This is the behavior when the best path
* has
* an attribute change anyway.
* has an attribute change anyway.
*/
if (CHECK_FLAG(selected->flags, BGP_INFO_IGP_CHANGED)
|| CHECK_FLAG(selected->flags, BGP_INFO_MULTIPATH_CHG))

View File

@ -2249,6 +2249,40 @@ static void bgp_zebra_connected(struct zclient *zclient)
*/
}
static int bgp_zebra_process_local_es(int cmd, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
esi_t esi;
struct bgp *bgp = NULL;
struct stream *s = NULL;
char buf[ESI_STR_LEN];
char buf1[INET6_ADDRSTRLEN];
struct ipaddr originator_ip;
memset(&esi, 0, sizeof(esi_t));
memset(&originator_ip, 0, sizeof(struct ipaddr));
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
s = zclient->ibuf;
stream_get(&esi, s, sizeof(esi_t));
stream_get(&originator_ip, s, sizeof(struct ipaddr));
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx %s ESI %s originator-ip %s",
(cmd == ZEBRA_LOCAL_ES_ADD) ? "add" : "del",
esi_to_str(&esi, buf, sizeof(buf)),
ipaddr2str(&originator_ip, buf1, sizeof(buf1)));
if (cmd == ZEBRA_LOCAL_ES_ADD)
bgp_evpn_local_es_add(bgp, &esi, &originator_ip);
else
bgp_evpn_local_es_del(bgp, &esi, &originator_ip);
return 0;
}
static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
@ -2484,6 +2518,8 @@ void bgp_zebra_init(struct thread_master *master)
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
zclient->fec_update = bgp_read_fec_update;
zclient->local_es_add = bgp_zebra_process_local_es;
zclient->local_es_del = bgp_zebra_process_local_es;
zclient->local_vni_add = bgp_zebra_process_local_vni;
zclient->local_vni_del = bgp_zebra_process_local_vni;
zclient->local_macip_add = bgp_zebra_process_local_macip;

View File

@ -534,6 +534,9 @@ struct bgp {
struct bgp_pbr_config *bgp_pbr_cfg;
/* local esi hash table */
struct hash *esihash;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgp)

View File

@ -945,6 +945,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
DESC_ENTRY(ZEBRA_LOCAL_ES_ADD),
DESC_ENTRY(ZEBRA_LOCAL_ES_DEL),
DESC_ENTRY(ZEBRA_VNI_ADD),
DESC_ENTRY(ZEBRA_VNI_DEL),
DESC_ENTRY(ZEBRA_L3VNI_ADD),

View File

@ -429,6 +429,14 @@ static const struct in6_addr maskbytes6[] = {
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
void prefix_hexdump(const struct prefix *p)
{
char buf[PREFIX_STRLEN];
zlog_debug("prefix: %s",
prefix2str(p, buf, sizeof(buf)));
zlog_hexdump(p, sizeof(struct prefix));
}
int is_zero_mac(struct ethaddr *mac)
{
int i = 0;
@ -1262,7 +1270,12 @@ static const char *prefixevpn_imet2str(const struct prefix_evpn *p, char *str,
static const char *prefixevpn_es2str(const struct prefix_evpn *p, char *str,
int size)
{
snprintf(str, size, "Unsupported EVPN prefix");
char buf[ESI_STR_LEN];
snprintf(str, size, "[%d]:[%s]:[%s]/%d", p->prefix.route_type,
esi_to_str(&p->prefix.es_addr.esi, buf, sizeof(buf)),
inet_ntoa(p->prefix.es_addr.ip.ipaddr_v4),
p->prefixlen);
return str;
}
@ -1540,3 +1553,56 @@ unsigned prefix_hash_key(void *pp)
offsetof(struct prefix, u.prefix) + PSIZE(copy.prefixlen),
0x55aa5a5a);
}
/* converts to internal representation of esi
* returns 1 on success, 0 otherwise
* format accepted: aa:aa:aa:aa:aa:aa:aa:aa:aa:aa
* if esi parameter is null, then check only
*/
int str_to_esi(const char *str, esi_t *esi)
{
int i;
unsigned int a[ESI_BYTES];
if (!str)
return 0;
if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x",
a + 0, a + 1, a + 2, a + 3,
a + 4, a + 5, a + 6, a + 7,
a + 8, a + 9)
!= ESI_BYTES) {
/* error in incoming str length */
return 0;
}
/* valid ESI */
if (!esi)
return 1;
for (i = 0; i < ESI_BYTES; ++i)
esi->val[i] = a[i] & 0xff;
return 1;
}
char *esi_to_str(const esi_t *esi, char *buf, int size)
{
char *ptr;
if (!esi)
return NULL;
if (!buf)
ptr = (char *)XMALLOC(MTYPE_TMP,
ESI_STR_LEN * sizeof(char));
else {
assert(size >= ESI_STR_LEN);
ptr = buf;
}
snprintf(ptr, ESI_STR_LEN,
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
esi->val[0], esi->val[1], esi->val[2],
esi->val[3], esi->val[4], esi->val[5],
esi->val[6], esi->val[7], esi->val[8],
esi->val[9]);
return ptr;
}

View File

@ -39,6 +39,9 @@
#define ETH_ALEN 6
#endif
#define ESI_BYTES 10
#define ESI_STR_LEN (3* ESI_BYTES)
#define ETHER_ADDR_STRLEN (3*ETH_ALEN)
/*
* there isn't a portable ethernet address type. We define our
@ -213,6 +216,8 @@ static inline int is_evpn_prefix_ipaddr_none(const struct prefix_evpn *evp)
return IS_IPADDR_NONE(&(evp)->prefix.macip_addr.ip);
if (evp->prefix.route_type == 3)
return IS_IPADDR_NONE(&(evp)->prefix.imet_addr.ip);
if (evp->prefix.route_type == 4)
return IS_IPADDR_NONE(&(evp)->prefix.es_addr.ip);
if (evp->prefix.route_type == 5)
return IS_IPADDR_NONE(&(evp)->prefix.prefix_addr.ip);
return 0;
@ -224,6 +229,8 @@ static inline int is_evpn_prefix_ipaddr_v4(const struct prefix_evpn *evp)
return IS_IPADDR_V4(&(evp)->prefix.macip_addr.ip);
if (evp->prefix.route_type == 3)
return IS_IPADDR_V4(&(evp)->prefix.imet_addr.ip);
if (evp->prefix.route_type == 4)
return IS_IPADDR_V4(&(evp)->prefix.es_addr.ip);
if (evp->prefix.route_type == 5)
return IS_IPADDR_V4(&(evp)->prefix.prefix_addr.ip);
return 0;
@ -235,6 +242,8 @@ static inline int is_evpn_prefix_ipaddr_v6(const struct prefix_evpn *evp)
return IS_IPADDR_V6(&(evp)->prefix.macip_addr.ip);
if (evp->prefix.route_type == 3)
return IS_IPADDR_V6(&(evp)->prefix.imet_addr.ip);
if (evp->prefix.route_type == 4)
return IS_IPADDR_V6(&(evp)->prefix.es_addr.ip);
if (evp->prefix.route_type == 5)
return IS_IPADDR_V6(&(evp)->prefix.prefix_addr.ip);
return 0;
@ -432,6 +441,11 @@ extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
extern unsigned prefix_hash_key(void *pp);
extern int str_to_esi(const char *str, esi_t *esi);
extern char *esi_to_str(const esi_t *esi, char *buf, int size);
extern void prefix_hexdump(const struct prefix *p);
extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
static inline int ipv6_martian(struct in6_addr *addr)
{
struct in6_addr localhost_addr;
@ -482,5 +496,4 @@ static inline int is_host_route(struct prefix *p)
return (p->prefixlen == IPV6_MAX_BITLEN);
return 0;
}
#endif /* _ZEBRA_PREFIX_H */

View File

@ -2760,6 +2760,16 @@ static int zclient_read(struct thread *thread)
if (zclient->fec_update)
(*zclient->fec_update)(command, zclient, length);
break;
case ZEBRA_LOCAL_ES_ADD:
if (zclient->local_es_add)
(*zclient->local_es_add)(command, zclient, length,
vrf_id);
break;
case ZEBRA_LOCAL_ES_DEL:
if (zclient->local_es_del)
(*zclient->local_es_del)(command, zclient, length,
vrf_id);
break;
case ZEBRA_VNI_ADD:
if (zclient->local_vni_add)
(*zclient->local_vni_add)(command, zclient, length,

View File

@ -124,6 +124,8 @@ typedef enum {
ZEBRA_ADVERTISE_DEFAULT_GW,
ZEBRA_ADVERTISE_SUBNET,
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_LOCAL_ES_ADD,
ZEBRA_LOCAL_ES_DEL,
ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL,
ZEBRA_L3VNI_ADD,
@ -237,6 +239,8 @@ struct zclient {
int (*redistribute_route_del)(int, struct zclient *, uint16_t,
vrf_id_t);
int (*fec_update)(int, struct zclient *, uint16_t);
int (*local_es_add)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_es_del)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t);