mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-01 00:25:52 +00:00
*: support for evpn type-4 route
Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
parent
68542a6da6
commit
50f74cf131
@ -801,6 +801,20 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
|
|||||||
len = sprintf(
|
len = sprintf(
|
||||||
str_buf + str_pnt,
|
str_buf + str_pnt,
|
||||||
"FS:marking %u", *(pnt+5));
|
"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
|
} else
|
||||||
unk_ecom = 1;
|
unk_ecom = 1;
|
||||||
} else {
|
} else {
|
||||||
|
1145
bgpd/bgp_evpn.c
1145
bgpd/bgp_evpn.c
File diff suppressed because it is too large
Load Diff
@ -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,
|
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
|
||||||
struct in_addr originator_ip,
|
struct in_addr originator_ip,
|
||||||
vrf_id_t tenant_vrf_id);
|
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_on_disable(struct bgp *bgp);
|
||||||
extern void bgp_evpn_cleanup(struct bgp *bgp);
|
extern void bgp_evpn_cleanup(struct bgp *bgp);
|
||||||
extern void bgp_evpn_init(struct bgp *bgp);
|
extern void bgp_evpn_init(struct bgp *bgp);
|
||||||
|
@ -31,9 +31,7 @@
|
|||||||
#define RT_ADDRSTRLEN 28
|
#define RT_ADDRSTRLEN 28
|
||||||
|
|
||||||
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
|
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
|
||||||
#define EVPN_TYPE_2_ROUTE_PREFIXLEN 224
|
#define EVPN_ROUTE_PREFIXLEN 224
|
||||||
#define EVPN_TYPE_3_ROUTE_PREFIXLEN 224
|
|
||||||
#define EVPN_TYPE_5_ROUTE_PREFIXLEN 224
|
|
||||||
|
|
||||||
/* EVPN route types. */
|
/* EVPN route types. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -98,6 +96,38 @@ struct bgpevpn {
|
|||||||
|
|
||||||
DECLARE_QOBJ_TYPE(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.
|
/* Mapping of Import RT to VNIs.
|
||||||
* The Import RTs of all VNIs are maintained in a hash table with each
|
* 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.
|
* 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));
|
|| 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,
|
static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
|
||||||
struct ethaddr *rmac)
|
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));
|
memset(p, 0, sizeof(struct prefix_evpn));
|
||||||
p->family = AF_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;
|
p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
|
||||||
memcpy(&p->prefix.macip_addr.mac.octet, mac->octet, ETH_ALEN);
|
memcpy(&p->prefix.macip_addr.mac.octet, mac->octet, ETH_ALEN);
|
||||||
p->prefix.macip_addr.ip.ipa_type = IPADDR_NONE;
|
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));
|
memset(evp, 0, sizeof(struct prefix_evpn));
|
||||||
evp->family = AF_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.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
|
||||||
evp->prefix.prefix_addr.ip_prefix_length = ip_prefix->prefixlen;
|
evp->prefix.prefix_addr.ip_prefix_length = ip_prefix->prefixlen;
|
||||||
evp->prefix.prefix_addr.ip.ipa_type = ip.ipa_type;
|
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));
|
memset(p, 0, sizeof(struct prefix_evpn));
|
||||||
p->family = AF_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.route_type = BGP_EVPN_IMET_ROUTE;
|
||||||
p->prefix.imet_addr.ip.ipa_type = IPADDR_V4;
|
p->prefix.imet_addr.ip.ipa_type = IPADDR_V4;
|
||||||
p->prefix.imet_addr.ip.ipaddr_v4 = originator_ip;
|
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,
|
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
|
||||||
safi_t safi)
|
safi_t safi)
|
||||||
{
|
{
|
||||||
@ -384,6 +437,20 @@ static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
|
|||||||
return 0;
|
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 evpn_rt_delete_auto(struct bgp *, vni_t, struct list *);
|
||||||
extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
||||||
struct ecommunity *ecomadd);
|
struct ecommunity *ecomadd);
|
||||||
@ -417,4 +484,8 @@ extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
|
|||||||
struct in_addr originator_ip,
|
struct in_addr originator_ip,
|
||||||
vrf_id_t tenant_vrf_id);
|
vrf_id_t tenant_vrf_id);
|
||||||
extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
|
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 */
|
#endif /* _BGP_EVPN_PRIVATE_H */
|
||||||
|
@ -328,6 +328,7 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
|
|||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
|
"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-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, "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
|
||||||
vty_out(vty, "%s", ri_header);
|
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);
|
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)
|
static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
|
||||||
{
|
{
|
||||||
char buf1[RD_ADDRSTRLEN];
|
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);
|
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,
|
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
|
||||||
struct vty *vty, struct in_addr vtep_ip,
|
struct vty *vty, struct in_addr vtep_ip,
|
||||||
json_object *json)
|
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",
|
vty_out(vty, "No EVPN prefixes %sexist for this VNI",
|
||||||
type ? "(of requested type) " : "");
|
type ? "(of requested type) " : "");
|
||||||
else
|
else
|
||||||
vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s",
|
vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
|
||||||
prefix_cnt, path_cnt,
|
prefix_cnt, path_cnt,
|
||||||
type ? " (of requested type)" : "");
|
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[])
|
static void show_vni_entry(struct hash_backet *backet, void *args[])
|
||||||
{
|
{
|
||||||
struct vty *vty;
|
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.
|
* Display EVPN routes for a VNI - vty handler.
|
||||||
* If 'type' is non-zero, only routes matching that type are shown.
|
* 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)
|
* Display specified VNI (vty handler)
|
||||||
*/
|
*/
|
||||||
@ -3027,6 +3243,58 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
|
|||||||
return CMD_SUCCESS;
|
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.
|
* Display EVPN neighbor summary.
|
||||||
*/
|
*/
|
||||||
@ -3056,7 +3324,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
|
|||||||
*/
|
*/
|
||||||
DEFUN(show_bgp_l2vpn_evpn_route,
|
DEFUN(show_bgp_l2vpn_evpn_route,
|
||||||
show_bgp_l2vpn_evpn_route_cmd,
|
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
|
SHOW_STR
|
||||||
BGP_STR
|
BGP_STR
|
||||||
L2VPN_HELP_STR
|
L2VPN_HELP_STR
|
||||||
@ -3065,7 +3333,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
|||||||
"Specify Route type\n"
|
"Specify Route type\n"
|
||||||
"MAC-IP (Type-2) route\n"
|
"MAC-IP (Type-2) route\n"
|
||||||
"Multicast (Type-3) route\n"
|
"Multicast (Type-3) route\n"
|
||||||
"Prefix route\n"
|
"Ethernet Segment (type-4) route \n"
|
||||||
|
"Prefix (type-5 )route\n"
|
||||||
JSON_STR)
|
JSON_STR)
|
||||||
{
|
{
|
||||||
struct bgp *bgp;
|
struct bgp *bgp;
|
||||||
@ -3090,6 +3359,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
|||||||
type = BGP_EVPN_MAC_IP_ROUTE;
|
type = BGP_EVPN_MAC_IP_ROUTE;
|
||||||
else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
|
else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
|
||||||
type = BGP_EVPN_IMET_ROUTE;
|
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)
|
else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
|
||||||
type = BGP_EVPN_IP_PREFIX_ROUTE;
|
type = BGP_EVPN_IP_PREFIX_ROUTE;
|
||||||
else
|
else
|
||||||
@ -3111,7 +3382,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
|||||||
*/
|
*/
|
||||||
DEFUN(show_bgp_l2vpn_evpn_route_rd,
|
DEFUN(show_bgp_l2vpn_evpn_route_rd,
|
||||||
show_bgp_l2vpn_evpn_route_rd_cmd,
|
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
|
SHOW_STR
|
||||||
BGP_STR
|
BGP_STR
|
||||||
L2VPN_HELP_STR
|
L2VPN_HELP_STR
|
||||||
@ -3122,6 +3393,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
|
|||||||
"Specify Route type\n"
|
"Specify Route type\n"
|
||||||
"MAC-IP (Type-2) route\n"
|
"MAC-IP (Type-2) route\n"
|
||||||
"Multicast (Type-3) route\n"
|
"Multicast (Type-3) route\n"
|
||||||
|
"Ethernet Segment route\n"
|
||||||
"Prefix route\n"
|
"Prefix route\n"
|
||||||
JSON_STR)
|
JSON_STR)
|
||||||
{
|
{
|
||||||
@ -3255,6 +3527,50 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
|
|||||||
return CMD_SUCCESS;
|
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.
|
* Display per-VNI EVPN routing table.
|
||||||
*/
|
*/
|
||||||
@ -3583,6 +3899,78 @@ DEFUN(show_bgp_l2vpn_evpn_import_rt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_CUMULUS)
|
#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,
|
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 bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR
|
||||||
"Show VNI\n"
|
"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, &bgp_evpn_default_originate_cmd);
|
||||||
install_element(BGP_EVPN_NODE, &no_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. */
|
/* "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_vni_cmd);
|
||||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_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_cmd);
|
||||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_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_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_cmd);
|
||||||
install_element(VIEW_NODE,
|
install_element(VIEW_NODE,
|
||||||
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
|
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
|
||||||
|
@ -116,6 +116,8 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
|
|||||||
DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
|
DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
|
||||||
|
|
||||||
DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
|
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_IMPORT_RT, "BGP EVPN Import RT")
|
||||||
DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF 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")
|
DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
|
||||||
|
@ -111,6 +111,9 @@ DECLARE_MTYPE(LCOMMUNITY)
|
|||||||
DECLARE_MTYPE(LCOMMUNITY_STR)
|
DECLARE_MTYPE(LCOMMUNITY_STR)
|
||||||
DECLARE_MTYPE(LCOMMUNITY_VAL)
|
DECLARE_MTYPE(LCOMMUNITY_VAL)
|
||||||
|
|
||||||
|
DECLARE_MTYPE(BGP_EVPN_ES)
|
||||||
|
DECLARE_MTYPE(BGP_EVPN_ES_VTEP)
|
||||||
|
|
||||||
DECLARE_MTYPE(BGP_EVPN)
|
DECLARE_MTYPE(BGP_EVPN)
|
||||||
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
|
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
|
||||||
DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
|
DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
|
||||||
|
@ -2107,12 +2107,10 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
|
|||||||
struct bgp_info *mpinfo;
|
struct bgp_info *mpinfo;
|
||||||
|
|
||||||
/* If this is multipath, check all selected paths for any nexthop change
|
/* If this is multipath, check all selected paths for any nexthop change
|
||||||
* or
|
* or attribute change. Some attribute changes (e.g., community) aren't of
|
||||||
* 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
|
* 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
|
* case of BGP nexthop change. This is the behavior when the best path
|
||||||
* has
|
* has an attribute change anyway.
|
||||||
* an attribute change anyway.
|
|
||||||
*/
|
*/
|
||||||
if (CHECK_FLAG(selected->flags, BGP_INFO_IGP_CHANGED)
|
if (CHECK_FLAG(selected->flags, BGP_INFO_IGP_CHANGED)
|
||||||
|| CHECK_FLAG(selected->flags, BGP_INFO_MULTIPATH_CHG))
|
|| CHECK_FLAG(selected->flags, BGP_INFO_MULTIPATH_CHG))
|
||||||
|
@ -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,
|
static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
|
||||||
zebra_size_t length, vrf_id_t vrf_id)
|
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->nexthop_update = bgp_read_nexthop_update;
|
||||||
zclient->import_check_update = bgp_read_import_check_update;
|
zclient->import_check_update = bgp_read_import_check_update;
|
||||||
zclient->fec_update = bgp_read_fec_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_add = bgp_zebra_process_local_vni;
|
||||||
zclient->local_vni_del = bgp_zebra_process_local_vni;
|
zclient->local_vni_del = bgp_zebra_process_local_vni;
|
||||||
zclient->local_macip_add = bgp_zebra_process_local_macip;
|
zclient->local_macip_add = bgp_zebra_process_local_macip;
|
||||||
|
@ -534,6 +534,9 @@ struct bgp {
|
|||||||
|
|
||||||
struct bgp_pbr_config *bgp_pbr_cfg;
|
struct bgp_pbr_config *bgp_pbr_cfg;
|
||||||
|
|
||||||
|
/* local esi hash table */
|
||||||
|
struct hash *esihash;
|
||||||
|
|
||||||
QOBJ_FIELDS
|
QOBJ_FIELDS
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(bgp)
|
DECLARE_QOBJ_TYPE(bgp)
|
||||||
|
@ -945,6 +945,8 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
|
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
|
||||||
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
|
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
|
||||||
DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
|
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_ADD),
|
||||||
DESC_ENTRY(ZEBRA_VNI_DEL),
|
DESC_ENTRY(ZEBRA_VNI_DEL),
|
||||||
DESC_ENTRY(ZEBRA_L3VNI_ADD),
|
DESC_ENTRY(ZEBRA_L3VNI_ADD),
|
||||||
|
68
lib/prefix.c
68
lib/prefix.c
@ -429,6 +429,14 @@ static const struct in6_addr maskbytes6[] = {
|
|||||||
|
|
||||||
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
|
#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 is_zero_mac(struct ethaddr *mac)
|
||||||
{
|
{
|
||||||
int i = 0;
|
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,
|
static const char *prefixevpn_es2str(const struct prefix_evpn *p, char *str,
|
||||||
int size)
|
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;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1540,3 +1553,56 @@ unsigned prefix_hash_key(void *pp)
|
|||||||
offsetof(struct prefix, u.prefix) + PSIZE(copy.prefixlen),
|
offsetof(struct prefix, u.prefix) + PSIZE(copy.prefixlen),
|
||||||
0x55aa5a5a);
|
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;
|
||||||
|
}
|
||||||
|
15
lib/prefix.h
15
lib/prefix.h
@ -39,6 +39,9 @@
|
|||||||
#define ETH_ALEN 6
|
#define ETH_ALEN 6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ESI_BYTES 10
|
||||||
|
#define ESI_STR_LEN (3* ESI_BYTES)
|
||||||
|
|
||||||
#define ETHER_ADDR_STRLEN (3*ETH_ALEN)
|
#define ETHER_ADDR_STRLEN (3*ETH_ALEN)
|
||||||
/*
|
/*
|
||||||
* there isn't a portable ethernet address type. We define our
|
* 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);
|
return IS_IPADDR_NONE(&(evp)->prefix.macip_addr.ip);
|
||||||
if (evp->prefix.route_type == 3)
|
if (evp->prefix.route_type == 3)
|
||||||
return IS_IPADDR_NONE(&(evp)->prefix.imet_addr.ip);
|
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)
|
if (evp->prefix.route_type == 5)
|
||||||
return IS_IPADDR_NONE(&(evp)->prefix.prefix_addr.ip);
|
return IS_IPADDR_NONE(&(evp)->prefix.prefix_addr.ip);
|
||||||
return 0;
|
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);
|
return IS_IPADDR_V4(&(evp)->prefix.macip_addr.ip);
|
||||||
if (evp->prefix.route_type == 3)
|
if (evp->prefix.route_type == 3)
|
||||||
return IS_IPADDR_V4(&(evp)->prefix.imet_addr.ip);
|
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)
|
if (evp->prefix.route_type == 5)
|
||||||
return IS_IPADDR_V4(&(evp)->prefix.prefix_addr.ip);
|
return IS_IPADDR_V4(&(evp)->prefix.prefix_addr.ip);
|
||||||
return 0;
|
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);
|
return IS_IPADDR_V6(&(evp)->prefix.macip_addr.ip);
|
||||||
if (evp->prefix.route_type == 3)
|
if (evp->prefix.route_type == 3)
|
||||||
return IS_IPADDR_V6(&(evp)->prefix.imet_addr.ip);
|
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)
|
if (evp->prefix.route_type == 5)
|
||||||
return IS_IPADDR_V6(&(evp)->prefix.prefix_addr.ip);
|
return IS_IPADDR_V6(&(evp)->prefix.prefix_addr.ip);
|
||||||
return 0;
|
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 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)
|
static inline int ipv6_martian(struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct in6_addr localhost_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 (p->prefixlen == IPV6_MAX_BITLEN);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _ZEBRA_PREFIX_H */
|
#endif /* _ZEBRA_PREFIX_H */
|
||||||
|
@ -2760,6 +2760,16 @@ static int zclient_read(struct thread *thread)
|
|||||||
if (zclient->fec_update)
|
if (zclient->fec_update)
|
||||||
(*zclient->fec_update)(command, zclient, length);
|
(*zclient->fec_update)(command, zclient, length);
|
||||||
break;
|
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:
|
case ZEBRA_VNI_ADD:
|
||||||
if (zclient->local_vni_add)
|
if (zclient->local_vni_add)
|
||||||
(*zclient->local_vni_add)(command, zclient, length,
|
(*zclient->local_vni_add)(command, zclient, length,
|
||||||
|
@ -124,6 +124,8 @@ typedef enum {
|
|||||||
ZEBRA_ADVERTISE_DEFAULT_GW,
|
ZEBRA_ADVERTISE_DEFAULT_GW,
|
||||||
ZEBRA_ADVERTISE_SUBNET,
|
ZEBRA_ADVERTISE_SUBNET,
|
||||||
ZEBRA_ADVERTISE_ALL_VNI,
|
ZEBRA_ADVERTISE_ALL_VNI,
|
||||||
|
ZEBRA_LOCAL_ES_ADD,
|
||||||
|
ZEBRA_LOCAL_ES_DEL,
|
||||||
ZEBRA_VNI_ADD,
|
ZEBRA_VNI_ADD,
|
||||||
ZEBRA_VNI_DEL,
|
ZEBRA_VNI_DEL,
|
||||||
ZEBRA_L3VNI_ADD,
|
ZEBRA_L3VNI_ADD,
|
||||||
@ -237,6 +239,8 @@ struct zclient {
|
|||||||
int (*redistribute_route_del)(int, struct zclient *, uint16_t,
|
int (*redistribute_route_del)(int, struct zclient *, uint16_t,
|
||||||
vrf_id_t);
|
vrf_id_t);
|
||||||
int (*fec_update)(int, struct zclient *, uint16_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_add)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||||
int (*local_vni_del)(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);
|
int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||||
|
Loading…
Reference in New Issue
Block a user