mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 02:46:26 +00:00
Merge pull request #12081 from sworleys/EMM-upstream
Rework of Various Handling in EVPN for Extended Mac Mobility
This commit is contained in:
commit
f8d69be43f
1033
bgpd/bgp_evpn.c
1033
bgpd/bgp_evpn.c
File diff suppressed because it is too large
Load Diff
@ -471,7 +471,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
|
||||
struct prefix_rd *prd;
|
||||
|
||||
if (vpn) {
|
||||
rt_table = vpn->route_table;
|
||||
rt_table = vpn->ip_table;
|
||||
prd = &vpn->prd;
|
||||
} else {
|
||||
rt_table = es->route_table;
|
||||
@ -498,9 +498,8 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
|
||||
/* Next, locate route node in the global EVPN routing table.
|
||||
* Note that this table is a 2-level tree (RD-level + Prefix-level)
|
||||
*/
|
||||
global_dest =
|
||||
bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
|
||||
(const struct prefix_evpn *)p, prd);
|
||||
global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi,
|
||||
safi, p, prd, NULL);
|
||||
if (global_dest) {
|
||||
|
||||
/* Delete route entry in the global EVPN table. */
|
||||
@ -675,8 +674,9 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp,
|
||||
if (route_changed) {
|
||||
struct bgp_path_info *global_pi;
|
||||
|
||||
dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
|
||||
p, &es->es_base_frag->prd);
|
||||
dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
|
||||
p, &es->es_base_frag->prd,
|
||||
NULL);
|
||||
bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest,
|
||||
attr_new, &global_pi, &route_changed);
|
||||
|
||||
@ -960,7 +960,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
|
||||
bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
|
||||
|
||||
/* First, create (or fetch) route node within the VNI. */
|
||||
dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
|
||||
dest = bgp_node_get(vpn->ip_table, (struct prefix *)p);
|
||||
|
||||
/* Create or update route entry. */
|
||||
ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
|
||||
@ -1015,8 +1015,8 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
|
||||
if (route_changed) {
|
||||
struct bgp_path_info *global_pi;
|
||||
|
||||
dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
|
||||
p, global_rd);
|
||||
dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
|
||||
p, global_rd, NULL);
|
||||
bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
|
||||
attr_new, &global_pi, &route_changed);
|
||||
|
||||
|
@ -112,9 +112,10 @@ struct bgpevpn {
|
||||
*/
|
||||
struct hash *remote_ip_hash;
|
||||
|
||||
/* Route table for EVPN routes for
|
||||
/* Route tables for EVPN routes for
|
||||
* this VNI. */
|
||||
struct bgp_table *route_table;
|
||||
struct bgp_table *ip_table;
|
||||
struct bgp_table *mac_table;
|
||||
|
||||
/* RB tree of ES-EVIs */
|
||||
struct bgp_es_evi_rb_head es_evi_rb_tree;
|
||||
@ -543,10 +544,10 @@ static inline void evpn_type1_prefix_global_copy(struct prefix_evpn *global_p,
|
||||
/* EAD prefix in the global table doesn't include the VTEP-IP so
|
||||
* we need to create a different copy for the VNI
|
||||
*/
|
||||
static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
|
||||
struct prefix_evpn *vni_p,
|
||||
const struct prefix_evpn *global_p,
|
||||
struct in_addr originator_ip)
|
||||
static inline struct prefix_evpn *
|
||||
evpn_type1_prefix_vni_ip_copy(struct prefix_evpn *vni_p,
|
||||
const struct prefix_evpn *global_p,
|
||||
struct in_addr originator_ip)
|
||||
{
|
||||
memcpy(vni_p, global_p, sizeof(*vni_p));
|
||||
vni_p->prefix.ead_addr.ip.ipa_type = IPADDR_V4;
|
||||
@ -555,6 +556,77 @@ static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
|
||||
return vni_p;
|
||||
}
|
||||
|
||||
static inline void evpn_type2_prefix_global_copy(
|
||||
struct prefix_evpn *global_p, const struct prefix_evpn *vni_p,
|
||||
const struct ethaddr *mac, const struct ipaddr *ip)
|
||||
{
|
||||
memcpy(global_p, vni_p, sizeof(*global_p));
|
||||
|
||||
if (mac)
|
||||
global_p->prefix.macip_addr.mac = *mac;
|
||||
|
||||
if (ip)
|
||||
global_p->prefix.macip_addr.ip = *ip;
|
||||
}
|
||||
|
||||
static inline void
|
||||
evpn_type2_prefix_vni_ip_copy(struct prefix_evpn *vni_p,
|
||||
const struct prefix_evpn *global_p)
|
||||
{
|
||||
memcpy(vni_p, global_p, sizeof(*vni_p));
|
||||
memset(&vni_p->prefix.macip_addr.mac, 0, sizeof(struct ethaddr));
|
||||
}
|
||||
|
||||
static inline void
|
||||
evpn_type2_prefix_vni_mac_copy(struct prefix_evpn *vni_p,
|
||||
const struct prefix_evpn *global_p)
|
||||
{
|
||||
memcpy(vni_p, global_p, sizeof(*vni_p));
|
||||
memset(&vni_p->prefix.macip_addr.ip, 0, sizeof(struct ipaddr));
|
||||
}
|
||||
|
||||
/* Get MAC of path_info prefix */
|
||||
static inline struct ethaddr *
|
||||
evpn_type2_path_info_get_mac(const struct bgp_path_info *local_pi)
|
||||
{
|
||||
assert(local_pi->extra);
|
||||
return &local_pi->extra->vni_info.mac;
|
||||
}
|
||||
|
||||
/* Get IP of path_info prefix */
|
||||
static inline struct ipaddr *
|
||||
evpn_type2_path_info_get_ip(const struct bgp_path_info *local_pi)
|
||||
{
|
||||
assert(local_pi->extra);
|
||||
return &local_pi->extra->vni_info.ip;
|
||||
}
|
||||
|
||||
/* Set MAC of path_info prefix */
|
||||
static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi,
|
||||
const struct ethaddr mac)
|
||||
{
|
||||
assert(local_pi->extra);
|
||||
local_pi->extra->vni_info.mac = mac;
|
||||
}
|
||||
|
||||
/* Set IP of path_info prefix */
|
||||
static inline void evpn_type2_path_info_set_ip(struct bgp_path_info *local_pi,
|
||||
const struct ipaddr ip)
|
||||
{
|
||||
assert(local_pi->extra);
|
||||
local_pi->extra->vni_info.ip = ip;
|
||||
}
|
||||
|
||||
/* Is the IP empty for the RT's dest? */
|
||||
static inline bool is_evpn_type2_dest_ipaddr_none(const struct bgp_dest *dest)
|
||||
{
|
||||
const struct prefix_evpn *evp =
|
||||
(const struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
||||
|
||||
assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
|
||||
return is_evpn_prefix_ipaddr_none(evp);
|
||||
}
|
||||
|
||||
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
|
||||
safi_t safi)
|
||||
{
|
||||
@ -651,14 +723,39 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
int vni_list_cmp(void *p1, void *p2);
|
||||
extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
struct bgp_dest *dest);
|
||||
extern struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table,
|
||||
afi_t afi, safi_t safi,
|
||||
const struct prefix_evpn *evp,
|
||||
struct prefix_rd *prd);
|
||||
extern struct bgp_dest *
|
||||
bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
|
||||
bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi,
|
||||
const struct prefix_evpn *evp, struct prefix_rd *prd,
|
||||
const struct bgp_path_info *local_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
|
||||
const struct prefix_evpn *evp,
|
||||
struct prefix_rd *prd);
|
||||
struct prefix_rd *prd,
|
||||
const struct bgp_path_info *local_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_vni_ip_node_get(struct bgp_table *const table,
|
||||
const struct prefix_evpn *evp,
|
||||
const struct bgp_path_info *parent_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table,
|
||||
const struct prefix_evpn *evp,
|
||||
const struct bgp_path_info *parent_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_vni_mac_node_get(struct bgp_table *const table,
|
||||
const struct prefix_evpn *evp,
|
||||
const struct bgp_path_info *parent_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table,
|
||||
const struct prefix_evpn *evp,
|
||||
const struct bgp_path_info *parent_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_vni_node_get(struct bgpevpn *vpn, const struct prefix_evpn *p,
|
||||
const struct bgp_path_info *parent_pi);
|
||||
extern struct bgp_dest *
|
||||
bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, const struct prefix_evpn *p,
|
||||
const struct bgp_path_info *parent_pi);
|
||||
|
||||
extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import);
|
||||
extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp,
|
||||
struct bgpevpn *vpn,
|
||||
struct bgp_node *rn,
|
||||
|
@ -57,6 +57,8 @@ struct vni_walk_ctx {
|
||||
struct in_addr vtep_ip;
|
||||
json_object *json;
|
||||
int detail;
|
||||
int type;
|
||||
bool mac_table;
|
||||
};
|
||||
|
||||
int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx,
|
||||
@ -517,7 +519,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
|
||||
json, "sviInterface",
|
||||
ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id));
|
||||
} else {
|
||||
vty_out(vty, "VNI: %d", vpn->vni);
|
||||
vty_out(vty, "VNI: %u", vpn->vni);
|
||||
if (is_vni_live(vpn))
|
||||
vty_out(vty, " (known to the kernel)");
|
||||
vty_out(vty, "\n");
|
||||
@ -735,7 +737,8 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
|
||||
|
||||
if (detail)
|
||||
route_vty_out_detail(
|
||||
vty, bgp, rn, pi, AFI_L2VPN, SAFI_EVPN,
|
||||
vty, bgp, rn, bgp_dest_get_prefix(rn),
|
||||
pi, AFI_L2VPN, SAFI_EVPN,
|
||||
RPKI_NOT_BEING_USED, json_path);
|
||||
else
|
||||
route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
|
||||
@ -770,9 +773,10 @@ static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi,
|
||||
bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
|
||||
}
|
||||
|
||||
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
|
||||
struct vty *vty, struct in_addr vtep_ip,
|
||||
json_object *json, int detail)
|
||||
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
struct vty *vty, int type, bool mac_table,
|
||||
struct in_addr vtep_ip, json_object *json,
|
||||
int detail)
|
||||
{
|
||||
struct bgp_dest *dest;
|
||||
struct bgp_path_info *pi;
|
||||
@ -783,7 +787,11 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
|
||||
|
||||
prefix_cnt = path_cnt = 0;
|
||||
|
||||
table = vpn->route_table;
|
||||
if (mac_table)
|
||||
table = vpn->mac_table;
|
||||
else
|
||||
table = vpn->ip_table;
|
||||
|
||||
tbl_ver = table->version;
|
||||
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
|
||||
const struct prefix_evpn *evp =
|
||||
@ -818,6 +826,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
|
||||
* with code that already exists).
|
||||
*/
|
||||
for (; pi; pi = pi->next) {
|
||||
struct prefix tmp_p;
|
||||
json_object *json_path = NULL;
|
||||
|
||||
if (vtep_ip.s_addr != INADDR_ANY
|
||||
@ -825,16 +834,43 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
|
||||
&(pi->attr->nexthop)))
|
||||
continue;
|
||||
|
||||
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
||||
/*
|
||||
* VNI IP/MAC table prefixes don't have MAC/IP
|
||||
* respectively so make sure it's set from path
|
||||
* info here.
|
||||
*/
|
||||
if (is_evpn_prefix_ipaddr_none(evp)) {
|
||||
/* VNI MAC -> Global */
|
||||
evpn_type2_prefix_global_copy(
|
||||
(struct prefix_evpn *)&tmp_p,
|
||||
evp, NULL /* mac */,
|
||||
evpn_type2_path_info_get_ip(
|
||||
pi));
|
||||
} else {
|
||||
/* VNI IP -> Global */
|
||||
evpn_type2_prefix_global_copy(
|
||||
(struct prefix_evpn *)&tmp_p,
|
||||
evp,
|
||||
evpn_type2_path_info_get_mac(
|
||||
pi),
|
||||
NULL /* ip */);
|
||||
}
|
||||
} else
|
||||
memcpy(&tmp_p, p, sizeof(tmp_p));
|
||||
|
||||
|
||||
if (json)
|
||||
json_path = json_object_new_array();
|
||||
|
||||
if (detail)
|
||||
route_vty_out_detail(vty, bgp, dest, pi,
|
||||
route_vty_out_detail(vty, bgp, dest, &tmp_p, pi,
|
||||
AFI_L2VPN, SAFI_EVPN,
|
||||
RPKI_NOT_BEING_USED,
|
||||
json_path);
|
||||
|
||||
else
|
||||
route_vty_out(vty, p, pi, 0, SAFI_EVPN,
|
||||
route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN,
|
||||
json_path, false);
|
||||
|
||||
if (json)
|
||||
@ -887,21 +923,57 @@ static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg)
|
||||
json_object *json_vni = NULL;
|
||||
char vni_str[VNI_STR_LEN];
|
||||
|
||||
snprintf(vni_str, sizeof(vni_str), "%d", vpn->vni);
|
||||
snprintf(vni_str, sizeof(vni_str), "%u", vpn->vni);
|
||||
if (json) {
|
||||
json_vni = json_object_new_object();
|
||||
json_object_int_add(json_vni, "vni", vpn->vni);
|
||||
} else {
|
||||
vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
|
||||
vty_out(vty, "\nVNI: %u\n\n", vpn->vni);
|
||||
}
|
||||
|
||||
show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni,
|
||||
wctx->detail);
|
||||
show_vni_routes(wctx->bgp, vpn, wctx->vty, wctx->type, wctx->mac_table,
|
||||
wctx->vtep_ip, json_vni, wctx->detail);
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json, vni_str, json_vni);
|
||||
}
|
||||
|
||||
static void show_vni_routes_all_hash(struct hash_bucket *bucket, void *arg)
|
||||
{
|
||||
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
|
||||
struct vni_walk_ctx *wctx = arg;
|
||||
struct vty *vty = wctx->vty;
|
||||
json_object *json = wctx->json;
|
||||
json_object *json_vni = NULL;
|
||||
json_object *json_vni_mac = NULL;
|
||||
char vni_str[VNI_STR_LEN];
|
||||
|
||||
snprintf(vni_str, sizeof(vni_str), "%u", vpn->vni);
|
||||
if (json) {
|
||||
json_vni = json_object_new_object();
|
||||
json_object_int_add(json_vni, "vni", vpn->vni);
|
||||
} else {
|
||||
vty_out(vty, "\nVNI: %u\n\n", vpn->vni);
|
||||
}
|
||||
|
||||
show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, false, wctx->vtep_ip,
|
||||
json_vni, wctx->detail);
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json, vni_str, json_vni);
|
||||
|
||||
if (json)
|
||||
json_vni_mac = json_object_new_object();
|
||||
else
|
||||
vty_out(vty, "\nVNI: %u MAC Table\n\n", vpn->vni);
|
||||
|
||||
show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, true, wctx->vtep_ip,
|
||||
json_vni_mac, wctx->detail);
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json_vni, "macTable", json_vni_mac);
|
||||
}
|
||||
|
||||
static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
|
||||
json_object *json)
|
||||
{
|
||||
@ -2322,9 +2394,9 @@ static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
|
||||
/*
|
||||
* Display EVPN routes for all VNIs - vty handler.
|
||||
*/
|
||||
static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
|
||||
struct in_addr vtep_ip, json_object *json,
|
||||
int detail)
|
||||
static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, int type,
|
||||
bool mac_table, struct in_addr vtep_ip,
|
||||
json_object *json, int detail)
|
||||
{
|
||||
uint32_t num_vnis;
|
||||
struct vni_walk_ctx wctx;
|
||||
@ -2335,6 +2407,8 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
|
||||
memset(&wctx, 0, sizeof(wctx));
|
||||
wctx.bgp = bgp;
|
||||
wctx.vty = vty;
|
||||
wctx.type = type;
|
||||
wctx.mac_table = mac_table;
|
||||
wctx.vtep_ip = vtep_ip;
|
||||
wctx.json = json;
|
||||
wctx.detail = detail;
|
||||
@ -2343,6 +2417,32 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
|
||||
&wctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display EVPN routes for all VNIs & all types - vty handler.
|
||||
*/
|
||||
static void evpn_show_routes_vni_all_type_all(struct vty *vty, struct bgp *bgp,
|
||||
struct in_addr vtep_ip,
|
||||
json_object *json, int detail)
|
||||
{
|
||||
uint32_t num_vnis;
|
||||
struct vni_walk_ctx wctx;
|
||||
|
||||
num_vnis = hashcount(bgp->vnihash);
|
||||
if (!num_vnis)
|
||||
return;
|
||||
|
||||
memset(&wctx, 0, sizeof(struct vni_walk_ctx));
|
||||
wctx.bgp = bgp;
|
||||
wctx.vty = vty;
|
||||
wctx.vtep_ip = vtep_ip;
|
||||
wctx.json = json;
|
||||
wctx.detail = detail;
|
||||
hash_iterate(bgp->vnihash,
|
||||
(void (*)(struct hash_bucket *,
|
||||
void *))show_vni_routes_all_hash,
|
||||
&wctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display EVPN routes for a VNI -- for specific type-3 route (vty handler).
|
||||
*/
|
||||
@ -2371,7 +2471,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
|
||||
|
||||
/* See if route exists. */
|
||||
build_evpn_type3_prefix(&p, orig_ip);
|
||||
dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
|
||||
dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
|
||||
if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
|
||||
if (!json)
|
||||
vty_out(vty, "%% Network not in table\n");
|
||||
@ -2386,7 +2486,8 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
|
||||
json_paths = json_object_new_array();
|
||||
|
||||
/* Prefix and num paths displayed once per prefix. */
|
||||
route_vty_out_detail_header(vty, bgp, dest, NULL, afi, safi, json);
|
||||
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
|
||||
NULL, afi, safi, json);
|
||||
|
||||
/* Display each path for this prefix. */
|
||||
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
|
||||
@ -2395,8 +2496,9 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
|
||||
if (json)
|
||||
json_path = json_object_new_array();
|
||||
|
||||
route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
|
||||
RPKI_NOT_BEING_USED, json_path);
|
||||
route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest),
|
||||
pi, afi, safi, RPKI_NOT_BEING_USED,
|
||||
json_path);
|
||||
|
||||
if (json)
|
||||
json_object_array_add(json_paths, json_path);
|
||||
@ -2427,12 +2529,15 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
|
||||
{
|
||||
struct bgpevpn *vpn;
|
||||
struct prefix_evpn p;
|
||||
struct prefix_evpn tmp_p;
|
||||
struct bgp_dest *dest;
|
||||
struct bgp_path_info *pi;
|
||||
uint32_t path_cnt = 0;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
json_object *json_paths = NULL;
|
||||
struct ethaddr empty_mac = {};
|
||||
const struct prefix_evpn *evp;
|
||||
|
||||
afi = AFI_L2VPN;
|
||||
safi = SAFI_EVPN;
|
||||
@ -2445,9 +2550,10 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
|
||||
return;
|
||||
}
|
||||
|
||||
build_evpn_type2_prefix(&p, mac ? mac : &empty_mac, ip);
|
||||
|
||||
/* See if route exists. Look for both non-sticky and sticky. */
|
||||
build_evpn_type2_prefix(&p, mac, ip);
|
||||
dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
|
||||
dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
|
||||
if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
|
||||
if (!json)
|
||||
vty_out(vty, "%% Network not in table\n");
|
||||
@ -2458,21 +2564,68 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* MAC is per-path, we have to walk the path_info's and look for it
|
||||
* first here.
|
||||
*/
|
||||
if (ip && mac) {
|
||||
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
|
||||
if (memcmp(mac, evpn_type2_path_info_get_mac(pi),
|
||||
sizeof(*mac)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pi) {
|
||||
if (!json)
|
||||
vty_out(vty, "%% Network not in table\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (json)
|
||||
json_paths = json_object_new_array();
|
||||
|
||||
/* Prefix and num paths displayed once per prefix. */
|
||||
route_vty_out_detail_header(vty, bgp, dest, NULL, afi, safi, json);
|
||||
route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL,
|
||||
afi, safi, json);
|
||||
|
||||
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
|
||||
|
||||
/* Display each path for this prefix. */
|
||||
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
|
||||
json_object *json_path = NULL;
|
||||
|
||||
/* skip non-matching MACs */
|
||||
if (ip && mac &&
|
||||
memcmp(mac, evpn_type2_path_info_get_mac(pi),
|
||||
sizeof(*mac)) != 0)
|
||||
continue;
|
||||
|
||||
if (json)
|
||||
json_path = json_object_new_array();
|
||||
|
||||
route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
|
||||
RPKI_NOT_BEING_USED, json_path);
|
||||
/*
|
||||
* VNI table MAC-IP prefixes don't have MAC so
|
||||
* make sure it's set from path info
|
||||
* here.
|
||||
*/
|
||||
if (is_evpn_prefix_ipaddr_none(evp)) {
|
||||
/* VNI MAC -> Global */
|
||||
evpn_type2_prefix_global_copy(
|
||||
(struct prefix_evpn *)&tmp_p, evp,
|
||||
NULL /* mac */,
|
||||
evpn_type2_path_info_get_ip(pi));
|
||||
} else {
|
||||
/* VNI IP -> Global */
|
||||
evpn_type2_prefix_global_copy(
|
||||
(struct prefix_evpn *)&tmp_p, evp,
|
||||
evpn_type2_path_info_get_mac(pi),
|
||||
NULL /* ip */);
|
||||
}
|
||||
|
||||
route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p,
|
||||
pi, afi, safi, RPKI_NOT_BEING_USED,
|
||||
json_path);
|
||||
|
||||
if (json)
|
||||
json_object_array_add(json_paths, json_path);
|
||||
@ -2516,8 +2669,8 @@ static void evpn_show_routes_esi(struct vty *vty, struct bgp *bgp,
|
||||
* If the vtep_ip is non zero, only routes behind that vtep are shown
|
||||
*/
|
||||
static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
|
||||
int type, struct in_addr vtep_ip,
|
||||
json_object *json)
|
||||
int type, bool mac_table,
|
||||
struct in_addr vtep_ip, json_object *json)
|
||||
{
|
||||
struct bgpevpn *vpn;
|
||||
|
||||
@ -2530,7 +2683,7 @@ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
|
||||
}
|
||||
|
||||
/* Walk this VNI's route table and display appropriate routes. */
|
||||
show_vni_routes(bgp, vpn, type, vty, vtep_ip, json, 0);
|
||||
show_vni_routes(bgp, vpn, vty, type, mac_table, vtep_ip, json, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2568,7 +2721,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
|
||||
}
|
||||
|
||||
/* Prefix and num paths displayed once per prefix. */
|
||||
route_vty_out_detail_header(vty, bgp, dest, prd, afi, safi, json);
|
||||
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
|
||||
prd, afi, safi, json);
|
||||
|
||||
if (json)
|
||||
json_paths = json_object_new_array();
|
||||
@ -2580,8 +2734,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
|
||||
if (json)
|
||||
json_path = json_object_new_array();
|
||||
|
||||
route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
|
||||
RPKI_NOT_BEING_USED, json_path);
|
||||
route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest),
|
||||
pi, afi, safi, RPKI_NOT_BEING_USED,
|
||||
json_path);
|
||||
|
||||
if (json)
|
||||
json_object_array_add(json_paths, json_path);
|
||||
@ -2673,8 +2828,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
|
||||
}
|
||||
|
||||
/* Prefix and num paths displayed once per prefix. */
|
||||
route_vty_out_detail_header(vty, bgp, dest, prd, afi,
|
||||
safi, json_prefix);
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest, bgp_dest_get_prefix(dest), prd,
|
||||
afi, safi, json_prefix);
|
||||
|
||||
prefix_cnt++;
|
||||
}
|
||||
@ -2689,8 +2845,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
|
||||
if (json)
|
||||
json_path = json_object_new_array();
|
||||
|
||||
route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
|
||||
RPKI_NOT_BEING_USED, json_path);
|
||||
route_vty_out_detail(
|
||||
vty, bgp, dest, bgp_dest_get_prefix(dest), pi,
|
||||
afi, safi, RPKI_NOT_BEING_USED, json_path);
|
||||
|
||||
if (json)
|
||||
json_object_array_add(json_paths, json_path);
|
||||
@ -2807,7 +2964,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
|
||||
} else
|
||||
/* Prefix and num paths displayed once per prefix. */
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest, (struct prefix_rd *)rd_destp,
|
||||
vty, bgp, dest, p, (struct prefix_rd *)rd_destp,
|
||||
AFI_L2VPN, SAFI_EVPN, json_prefix);
|
||||
|
||||
/* For EVPN, the prefix is displayed for each path (to
|
||||
@ -2822,7 +2979,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
|
||||
if (json)
|
||||
json_path = json_object_new_array();
|
||||
|
||||
route_vty_out_detail(vty, bgp, dest, pi, AFI_L2VPN,
|
||||
route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN,
|
||||
SAFI_EVPN, RPKI_NOT_BEING_USED,
|
||||
json_path);
|
||||
|
||||
@ -2960,6 +3117,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
|
||||
if (detail)
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest),
|
||||
(struct prefix_rd *)rd_destp, AFI_L2VPN,
|
||||
SAFI_EVPN, json_prefix);
|
||||
|
||||
@ -2979,9 +3137,10 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
|
||||
|
||||
if (detail) {
|
||||
route_vty_out_detail(
|
||||
vty, bgp, dest, pi, AFI_L2VPN,
|
||||
SAFI_EVPN, RPKI_NOT_BEING_USED,
|
||||
json_path);
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest), pi,
|
||||
AFI_L2VPN, SAFI_EVPN,
|
||||
RPKI_NOT_BEING_USED, json_path);
|
||||
} else
|
||||
route_vty_out(vty, p, pi, 0, SAFI_EVPN,
|
||||
json_path, false);
|
||||
@ -3297,7 +3456,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
|
||||
struct ecommunity *ecom;
|
||||
|
||||
if (is_vni_configured(vpn)) {
|
||||
vty_out(vty, " vni %d\n", vpn->vni);
|
||||
vty_out(vty, " vni %u\n", vpn->vni);
|
||||
if (is_rd_configured(vpn))
|
||||
vty_out(vty, " rd %pRD\n", &vpn->prd);
|
||||
|
||||
@ -4562,28 +4721,32 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
|
||||
as_type, as, show_flags);
|
||||
}
|
||||
|
||||
static int bgp_evpn_cli_parse_type_cmp(int *type, const char *type_str)
|
||||
{
|
||||
if ((strncmp(type_str, "ma", 2) == 0) || (strmatch(type_str, "2")))
|
||||
*type = BGP_EVPN_MAC_IP_ROUTE;
|
||||
else if ((strncmp(type_str, "mu", 2) == 0) || (strmatch(type_str, "3")))
|
||||
*type = BGP_EVPN_IMET_ROUTE;
|
||||
else if ((strncmp(type_str, "es", 2) == 0) || (strmatch(type_str, "4")))
|
||||
*type = BGP_EVPN_ES_ROUTE;
|
||||
else if ((strncmp(type_str, "ea", 2) == 0) || (strmatch(type_str, "1")))
|
||||
*type = BGP_EVPN_AD_ROUTE;
|
||||
else if ((strncmp(type_str, "p", 1) == 0) || (strmatch(type_str, "5")))
|
||||
*type = BGP_EVPN_IP_PREFIX_ROUTE;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv, int argc)
|
||||
{
|
||||
int type_idx = 0;
|
||||
|
||||
if (argv_find(argv, argc, "type", &type_idx)) {
|
||||
/* Specific type is requested */
|
||||
if ((strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
|
||||
|| (strmatch(argv[type_idx + 1]->arg, "2")))
|
||||
*type = BGP_EVPN_MAC_IP_ROUTE;
|
||||
else if ((strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
|
||||
|| (strmatch(argv[type_idx + 1]->arg, "3")))
|
||||
*type = BGP_EVPN_IMET_ROUTE;
|
||||
else if ((strncmp(argv[type_idx + 1]->arg, "es", 2) == 0)
|
||||
|| (strmatch(argv[type_idx + 1]->arg, "4")))
|
||||
*type = BGP_EVPN_ES_ROUTE;
|
||||
else if ((strncmp(argv[type_idx + 1]->arg, "ea", 2) == 0)
|
||||
|| (strmatch(argv[type_idx + 1]->arg, "1")))
|
||||
*type = BGP_EVPN_AD_ROUTE;
|
||||
else if ((strncmp(argv[type_idx + 1]->arg, "p", 1) == 0)
|
||||
|| (strmatch(argv[type_idx + 1]->arg, "5")))
|
||||
*type = BGP_EVPN_IP_PREFIX_ROUTE;
|
||||
else
|
||||
if (bgp_evpn_cli_parse_type_cmp(type,
|
||||
argv[type_idx + 1]->arg) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -4881,7 +5044,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd,
|
||||
}
|
||||
}
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json);
|
||||
evpn_show_routes_vni(vty, bgp, vni, type, false, vtep_ip, json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
@ -5063,7 +5226,464 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
|
||||
}
|
||||
}
|
||||
|
||||
evpn_show_routes_vni_all(vty, bgp, vtep_ip, json, da);
|
||||
evpn_show_routes_vni_all(vty, bgp, 0, false, vtep_ip, json, da);
|
||||
|
||||
if (uj) {
|
||||
vty_json(vty, json);
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN ALL routing tables - for all VNIs.
|
||||
*/
|
||||
DEFPY(show_bgp_vni_all,
|
||||
show_bgp_vni_all_cmd,
|
||||
"show bgp vni all [vtep A.B.C.D$addr] [detail$detail] [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_ALL_HELP_STR
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
DETAIL_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni_all_type_all(vty, bgp, addr, json, !!detail);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN EAD routing table - for all VNIs.
|
||||
*/
|
||||
DEFPY(show_bgp_vni_all_ead,
|
||||
show_bgp_vni_all_ead_cmd,
|
||||
"show bgp vni all type <1|ead> [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_ALL_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_1_HELP_STR
|
||||
EVPN_TYPE_1_HELP_STR
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
DETAIL_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_AD_ROUTE, false, addr, json,
|
||||
!!detail);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN MAC routing table - for all VNIs.
|
||||
*/
|
||||
DEFPY(show_bgp_vni_all_macip_mac,
|
||||
show_bgp_vni_all_macip_mac_cmd,
|
||||
"show bgp vni all type <2|macip> mac [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_ALL_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
"MAC Table\n"
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
DETAIL_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, true, addr,
|
||||
json, !!detail);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN IP routing table - for all VNIs.
|
||||
*/
|
||||
DEFPY(show_bgp_vni_all_macip_ip,
|
||||
show_bgp_vni_all_macip_ip_cmd,
|
||||
"show bgp vni all type <2|macip> ip [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_ALL_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
"IP Table\n"
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
DETAIL_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, false, addr,
|
||||
json, !!detail);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN Multicast routing table - for all VNIs.
|
||||
*/
|
||||
DEFPY(show_bgp_vni_all_imet,
|
||||
show_bgp_vni_all_imet_cmd,
|
||||
"show bgp vni all type <3|multicast> [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_ALL_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_3_HELP_STR
|
||||
EVPN_TYPE_3_HELP_STR
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
DETAIL_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_IMET_ROUTE, false, addr,
|
||||
json, !!detail);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN ALL routing tables - for select VNI
|
||||
*/
|
||||
DEFPY(show_bgp_vni,
|
||||
show_bgp_vni_cmd,
|
||||
"show bgp vni "CMD_VNI_RANGE"$vni [vtep A.B.C.D$addr] [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_NUM_HELP_STR
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
json_object *json_mac = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj) {
|
||||
json = json_object_new_object();
|
||||
json_mac = json_object_new_object();
|
||||
}
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, 0, false, addr, json);
|
||||
|
||||
if (!uj)
|
||||
vty_out(vty, "\n\nMAC Table:\n\n");
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, 0, true, addr, json_mac);
|
||||
|
||||
if (uj) {
|
||||
json_object_object_add(json, "macTable", json_mac);
|
||||
vty_json(vty, json);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN EAD routing table - for select VNI
|
||||
*/
|
||||
DEFPY(show_bgp_vni_ead,
|
||||
show_bgp_vni_ead_cmd,
|
||||
"show bgp vni "CMD_VNI_RANGE"$vni type <1|ead> [vtep A.B.C.D$addr] [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_NUM_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_1_HELP_STR
|
||||
EVPN_TYPE_1_HELP_STR
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_AD_ROUTE, false, addr,
|
||||
json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN MAC-IP MAC routing table - for select VNI
|
||||
*/
|
||||
DEFPY(show_bgp_vni_macip_mac,
|
||||
show_bgp_vni_macip_mac_cmd,
|
||||
"show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac [vtep A.B.C.D$addr] [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_NUM_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
"MAC Table\n"
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, true, addr,
|
||||
json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN MAC-IP IP routing table - for select VNI
|
||||
*/
|
||||
DEFPY(show_bgp_vni_macip_ip,
|
||||
show_bgp_vni_macip_ip_cmd,
|
||||
"show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> ip [vtep A.B.C.D$addr] [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_NUM_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
"IP Table\n"
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, false, addr,
|
||||
json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN Multicast routing table - for select VNI
|
||||
*/
|
||||
DEFPY(show_bgp_vni_imet,
|
||||
show_bgp_vni_imet_cmd,
|
||||
"show bgp vni "CMD_VNI_RANGE"$vni type <3|multicast> [vtep A.B.C.D$addr] [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_NUM_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_3_HELP_STR
|
||||
EVPN_TYPE_3_HELP_STR
|
||||
VTEP_HELP_STR
|
||||
VTEP_IP_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_IMET_ROUTE, false, addr,
|
||||
json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN MACIP MAC routing table - for select VNI & MAC
|
||||
*/
|
||||
DEFPY(show_bgp_vni_macip_mac_addr,
|
||||
show_bgp_vni_macip_mac_addr_cmd,
|
||||
"show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac X:X:X:X:X:X [json$uj]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
VNI_HELP_STR
|
||||
VNI_NUM_HELP_STR
|
||||
EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR
|
||||
"MAC Table\n"
|
||||
MAC_STR
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_route_vni_macip(vty, bgp, vni, &mac->eth_addr, NULL, json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN MACIP IP routing table - for select VNI & IP
|
||||
*/
|
||||
DEFPY(show_bgp_vni_macip_ip_addr, show_bgp_vni_macip_ip_addr_cmd,
|
||||
"show bgp vni " CMD_VNI_RANGE
|
||||
"$vni type <2|macip> ip <A.B.C.D|X:X::X:X> [json$uj]",
|
||||
SHOW_STR BGP_STR VNI_HELP_STR VNI_NUM_HELP_STR EVPN_TYPE_HELP_STR
|
||||
EVPN_TYPE_2_HELP_STR EVPN_TYPE_2_HELP_STR
|
||||
"IP Table\n" IP_ADDR_STR IP6_ADDR_STR JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
json_object *json = NULL;
|
||||
struct ipaddr ip_addr = {.ipa_type = IPADDR_NONE};
|
||||
|
||||
bgp = bgp_get_evpn();
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
/* check if we need json output */
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
if (sockunion_family(ip) == AF_INET) {
|
||||
ip_addr.ipa_type = IPADDR_V4;
|
||||
ip_addr.ipaddr_v4.s_addr = sockunion2ip(ip);
|
||||
} else {
|
||||
ip_addr.ipa_type = IPADDR_V6;
|
||||
memcpy(&ip_addr.ipaddr_v6, &ip->sin6.sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
}
|
||||
evpn_show_route_vni_macip(vty, bgp, vni, NULL, &ip_addr, json);
|
||||
|
||||
if (uj)
|
||||
vty_json(vty, json);
|
||||
@ -6755,6 +7375,20 @@ void bgp_ethernetvpn_init(void)
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
|
||||
|
||||
/* "show bgp vni" commands. */
|
||||
install_element(VIEW_NODE, &show_bgp_vni_all_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_all_ead_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_all_macip_mac_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_all_macip_ip_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_all_imet_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_ead_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_macip_mac_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_macip_ip_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_imet_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_macip_mac_addr_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_vni_macip_ip_addr_cmd);
|
||||
|
||||
/* "show bgp evpn" commands. */
|
||||
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
|
||||
|
@ -27,6 +27,12 @@ extern void bgp_ethernetvpn_init(void);
|
||||
|
||||
#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
|
||||
#define EVPN_HELP_STR "Ethernet Virtual Private Network\n"
|
||||
#define VNI_HELP_STR "VXLAN Network Identifier\n"
|
||||
#define VNI_NUM_HELP_STR "VNI number\n"
|
||||
#define VNI_ALL_HELP_STR "All VNIs\n"
|
||||
#define DETAIL_HELP_STR "Print Detailed Output\n"
|
||||
#define VTEP_HELP_STR "Remote VTEP\n"
|
||||
#define VTEP_IP_HELP_STR "Remote VTEP IP address\n"
|
||||
|
||||
extern int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc,
|
||||
int *oly_idx,
|
||||
|
117
bgpd/bgp_route.c
117
bgpd/bgp_route.c
@ -10215,12 +10215,14 @@ static void route_vty_out_detail_es_info(struct vty *vty,
|
||||
}
|
||||
|
||||
void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
struct bgp_path_info *path, afi_t afi, safi_t safi,
|
||||
const struct prefix *p, struct bgp_path_info *path,
|
||||
afi_t afi, safi_t safi,
|
||||
enum rpki_states rpki_curr_state,
|
||||
json_object *json_paths)
|
||||
{
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
char buf1[BUFSIZ];
|
||||
char tag_buf[30];
|
||||
struct attr *attr = path->attr;
|
||||
time_t tbuf;
|
||||
json_object *json_bestpath = NULL;
|
||||
@ -10251,6 +10253,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
uint32_t bos = 0;
|
||||
uint32_t exp = 0;
|
||||
mpls_label_t label = MPLS_INVALID_LABEL;
|
||||
tag_buf[0] = '\0';
|
||||
|
||||
if (json_paths) {
|
||||
json_path = json_object_new_object();
|
||||
@ -10260,13 +10263,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
|
||||
if (safi == SAFI_EVPN) {
|
||||
if (!json_paths)
|
||||
vty_out(vty, " Route %pRN", bn);
|
||||
vty_out(vty, " Route %pFX", p);
|
||||
}
|
||||
|
||||
if (path->extra) {
|
||||
char tag_buf[30];
|
||||
|
||||
tag_buf[0] = '\0';
|
||||
if (path->extra && path->extra->num_labels) {
|
||||
bgp_evpn_label2str(path->extra->label,
|
||||
path->extra->num_labels, tag_buf,
|
||||
@ -10285,44 +10285,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path->extra && path->extra->parent && !json_paths) {
|
||||
struct bgp_path_info *parent_ri;
|
||||
struct bgp_dest *dest, *pdest;
|
||||
|
||||
parent_ri = (struct bgp_path_info *)path->extra->parent;
|
||||
dest = parent_ri->net;
|
||||
if (dest && dest->pdest) {
|
||||
pdest = dest->pdest;
|
||||
if (is_pi_family_evpn(parent_ri)) {
|
||||
vty_out(vty,
|
||||
" Imported from %pRD:%pFX, VNI %s",
|
||||
(struct prefix_rd *)
|
||||
bgp_dest_get_prefix(
|
||||
pdest),
|
||||
(struct prefix_evpn *)
|
||||
bgp_dest_get_prefix(
|
||||
dest),
|
||||
tag_buf);
|
||||
if (attr->es_flags & ATTR_ES_L3_NHG)
|
||||
vty_out(vty, ", L3NHG %s",
|
||||
(attr->es_flags
|
||||
& ATTR_ES_L3_NHG_ACTIVE)
|
||||
? "active"
|
||||
: "inactive");
|
||||
vty_out(vty, "\n");
|
||||
|
||||
} else
|
||||
vty_out(vty,
|
||||
" Imported from %pRD:%pFX\n",
|
||||
(struct prefix_rd *)
|
||||
bgp_dest_get_prefix(
|
||||
pdest),
|
||||
(struct prefix_evpn *)
|
||||
bgp_dest_get_prefix(
|
||||
dest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (safi == SAFI_EVPN
|
||||
@ -10342,6 +10304,41 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
if (safi == SAFI_EVPN && !json_path)
|
||||
vty_out(vty, "\n");
|
||||
|
||||
|
||||
if (path->extra && path->extra->parent && !json_paths) {
|
||||
struct bgp_path_info *parent_ri;
|
||||
struct bgp_dest *dest, *pdest;
|
||||
|
||||
parent_ri = (struct bgp_path_info *)path->extra->parent;
|
||||
dest = parent_ri->net;
|
||||
if (dest && dest->pdest) {
|
||||
pdest = dest->pdest;
|
||||
if (is_pi_family_evpn(parent_ri)) {
|
||||
vty_out(vty,
|
||||
" Imported from %pRD:%pFX, VNI %s",
|
||||
(struct prefix_rd *)bgp_dest_get_prefix(
|
||||
pdest),
|
||||
(struct prefix_evpn *)
|
||||
bgp_dest_get_prefix(dest),
|
||||
tag_buf);
|
||||
if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG))
|
||||
vty_out(vty, ", L3NHG %s",
|
||||
CHECK_FLAG(
|
||||
attr->es_flags,
|
||||
ATTR_ES_L3_NHG_ACTIVE)
|
||||
? "active"
|
||||
: "inactive");
|
||||
vty_out(vty, "\n");
|
||||
|
||||
} else
|
||||
vty_out(vty, " Imported from %pRD:%pFX\n",
|
||||
(struct prefix_rd *)bgp_dest_get_prefix(
|
||||
pdest),
|
||||
(struct prefix_evpn *)
|
||||
bgp_dest_get_prefix(dest));
|
||||
}
|
||||
}
|
||||
|
||||
/* Line1 display AS-path, Aggregator */
|
||||
if (attr->aspath) {
|
||||
if (json_paths) {
|
||||
@ -10421,10 +10418,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
|
||||
/* Line2 display Next-hop, Neighbor, Router-id */
|
||||
/* Display the nexthop */
|
||||
const struct prefix *bn_p = bgp_dest_get_prefix(bn);
|
||||
|
||||
if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET ||
|
||||
bn_p->family == AF_EVPN) &&
|
||||
if ((p->family == AF_INET || p->family == AF_ETHERNET ||
|
||||
p->family == AF_EVPN) &&
|
||||
(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN ||
|
||||
!BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
|
||||
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|
||||
@ -10537,7 +10533,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
||||
/* This path was originated locally */
|
||||
if (path->peer == bgp->peer_self) {
|
||||
|
||||
if (safi == SAFI_EVPN || (bn_p->family == AF_INET &&
|
||||
if (safi == SAFI_EVPN || (p->family == AF_INET &&
|
||||
!BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
|
||||
if (json_paths)
|
||||
json_object_string_add(json_peer, "peerId",
|
||||
@ -11561,8 +11557,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|
||||
prd = bgp_rd_from_dest(dest, safi);
|
||||
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest, prd, table->afi,
|
||||
safi, jtemp);
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest), prd,
|
||||
table->afi, safi, jtemp);
|
||||
|
||||
json_object_array_add(json_paths, jtemp);
|
||||
|
||||
@ -11588,7 +11585,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|
||||
else {
|
||||
if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL))
|
||||
route_vty_out_detail(
|
||||
vty, bgp, dest, pi,
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest), pi,
|
||||
family2afi(dest_p->family),
|
||||
safi, RPKI_NOT_BEING_USED,
|
||||
json_paths);
|
||||
@ -11809,12 +11807,11 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
|
||||
|
||||
/* Header of detailed BGP route information */
|
||||
void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
|
||||
struct bgp_dest *dest,
|
||||
const struct prefix_rd *prd,
|
||||
afi_t afi, safi_t safi, json_object *json)
|
||||
struct bgp_dest *dest, const struct prefix *p,
|
||||
const struct prefix_rd *prd, afi_t afi,
|
||||
safi_t safi, json_object *json)
|
||||
{
|
||||
struct bgp_path_info *pi;
|
||||
const struct prefix *p;
|
||||
struct peer *peer;
|
||||
struct listnode *node, *nnode;
|
||||
char buf1[RD_ADDRSTRLEN];
|
||||
@ -11844,7 +11841,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
|
||||
|
||||
mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos);
|
||||
|
||||
p = bgp_dest_get_prefix(dest);
|
||||
has_valid_label = bgp_is_valid_label(&label);
|
||||
|
||||
if (safi == SAFI_EVPN) {
|
||||
@ -12052,8 +12048,9 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
|
||||
|
||||
if (header) {
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, bgp_node, pfx_rd,
|
||||
AFI_IP, safi, json_header);
|
||||
vty, bgp, bgp_node,
|
||||
bgp_dest_get_prefix(bgp_node), pfx_rd, AFI_IP,
|
||||
safi, json_header);
|
||||
header = 0;
|
||||
}
|
||||
(*display)++;
|
||||
@ -12064,8 +12061,10 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
|
||||
|| (pathtype == BGP_PATH_SHOW_MULTIPATH
|
||||
&& (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH)
|
||||
|| CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))))
|
||||
route_vty_out_detail(vty, bgp, bgp_node, pi, AFI_IP,
|
||||
safi, rpki_curr_state, json_paths);
|
||||
route_vty_out_detail(vty, bgp, bgp_node,
|
||||
bgp_dest_get_prefix(bgp_node), pi,
|
||||
AFI_IP, safi, rpki_curr_state,
|
||||
json_paths);
|
||||
}
|
||||
|
||||
if (json && json_paths) {
|
||||
|
@ -214,9 +214,14 @@ struct bgp_path_info_extra {
|
||||
} vnc;
|
||||
#endif
|
||||
|
||||
/* For imported routes into a VNI (or VRF), this points to the parent.
|
||||
/*
|
||||
* For imported routes into a VNI (or VRF)
|
||||
*/
|
||||
void *parent;
|
||||
void *parent; /* parent from global table */
|
||||
union {
|
||||
struct ethaddr mac; /* MAC set here for VNI IP table */
|
||||
struct ipaddr ip; /* IP set here for VNI MAC table */
|
||||
} vni_info;
|
||||
|
||||
/*
|
||||
* Some tunnelish parameters follow. Maybe consolidate into an
|
||||
@ -849,10 +854,11 @@ extern bool bgp_zebra_has_route_changed(struct bgp_path_info *selected);
|
||||
|
||||
extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
|
||||
struct bgp_dest *dest,
|
||||
const struct prefix *p,
|
||||
const struct prefix_rd *prd, afi_t afi,
|
||||
safi_t safi, json_object *json);
|
||||
extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
|
||||
struct bgp_dest *bn,
|
||||
struct bgp_dest *bn, const struct prefix *p,
|
||||
struct bgp_path_info *path, afi_t afi,
|
||||
safi_t safi, enum rpki_states,
|
||||
json_object *json_paths);
|
||||
|
@ -4135,6 +4135,10 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
|
||||
|
||||
EVPN prefixes can also be filtered by EVPN route type.
|
||||
|
||||
.. clicmd:: show bgp vni <all|VNI> [vtep VTEP] [type <ead|1|macip|2|multicast|3>] [<detail|json>]
|
||||
|
||||
Display per-VNI EVPN routing table in bgp. Filter route-type, vtep, or VNI.
|
||||
|
||||
.. clicmd:: show bgp [afi] [safi] [all] summary [json]
|
||||
|
||||
Show a bgp peer summary for the specified address family, and subsequent
|
||||
|
@ -383,6 +383,8 @@ struct cmd_node {
|
||||
#define SHOW_STR "Show running system information\n"
|
||||
#define IP_STR "IP information\n"
|
||||
#define IPV6_STR "IPv6 information\n"
|
||||
#define IP_ADDR_STR "IPv4 Address\n"
|
||||
#define IP6_ADDR_STR "IPv6 Address\n"
|
||||
#define SRTE_STR "SR-TE information\n"
|
||||
#define SRTE_COLOR_STR "SR-TE Color information\n"
|
||||
#define NO_STR "Negate a command or set its defaults\n"
|
||||
|
@ -1327,11 +1327,11 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
|
||||
uint8_t flags, uint32_t seq,
|
||||
const esi_t *esi)
|
||||
{
|
||||
struct sync_mac_ip_ctx ctx;
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
bool sticky;
|
||||
bool remote_gw;
|
||||
struct zebra_neigh *n = NULL;
|
||||
struct zebra_mac *mac = NULL;
|
||||
|
||||
sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
|
||||
remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
||||
@ -1352,22 +1352,30 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
|
||||
return;
|
||||
}
|
||||
|
||||
if (ipa_len) {
|
||||
if (!ipa_len) {
|
||||
/* MAC update */
|
||||
(void)zebra_evpn_proc_sync_mac_update(zevpn, macaddr, ipa_len,
|
||||
ipaddr, flags, seq, esi);
|
||||
} else {
|
||||
/* MAC-IP update */
|
||||
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
||||
if (!mac) {
|
||||
mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr,
|
||||
ipa_len, ipaddr,
|
||||
flags, seq, esi);
|
||||
}
|
||||
if (!mac)
|
||||
return;
|
||||
|
||||
n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
|
||||
if (n
|
||||
&& !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq,
|
||||
true))
|
||||
return;
|
||||
|
||||
zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr,
|
||||
flags, seq, esi, mac);
|
||||
}
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.mac = zebra_evpn_proc_sync_mac_update(
|
||||
zevpn, macaddr, ipa_len, ipaddr, flags, seq, esi, &ctx);
|
||||
if (ctx.ignore_macip || !ctx.mac || !ipa_len)
|
||||
return;
|
||||
|
||||
zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, flags, seq,
|
||||
esi, &ctx);
|
||||
}
|
||||
|
||||
/************************** remote mac-ip handling **************************/
|
||||
@ -1452,14 +1460,30 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr,
|
||||
}
|
||||
|
||||
zvrf = zebra_vrf_get_evpn();
|
||||
if (zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len,
|
||||
ipaddr, &mac, vtep_ip, flags, seq,
|
||||
esi)
|
||||
!= 0)
|
||||
if (!zvrf)
|
||||
return;
|
||||
|
||||
zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip,
|
||||
flags, seq);
|
||||
if (!ipa_len) {
|
||||
/* MAC update */
|
||||
zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, vtep_ip,
|
||||
flags, seq, esi);
|
||||
} else {
|
||||
/* MAC-IP update
|
||||
* Add auto MAC if it doesn't exist.
|
||||
*/
|
||||
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
||||
if (!mac) {
|
||||
mac = zebra_evpn_mac_add_auto(zevpn, macaddr);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"Neigh %pIA: MAC %pEA not found, Auto MAC created",
|
||||
ipaddr, macaddr);
|
||||
}
|
||||
|
||||
zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac,
|
||||
vtep_ip, flags, seq);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a remote MACIP delete from BGP. */
|
||||
@ -1504,7 +1528,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
|
||||
|
||||
if (n && !mac) {
|
||||
zlog_warn(
|
||||
"Failed to locate MAC %pEA for neigh %pIA VNI %u upon remote MACIP DEL",
|
||||
"Failed to locate MAC %pEA for Neigh %pIA VNI %u upon remote MACIP DEL",
|
||||
macaddr, ipaddr, vni);
|
||||
return;
|
||||
}
|
||||
@ -1512,8 +1536,13 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
|
||||
/* If the remote mac or neighbor doesn't exist there is nothing
|
||||
* more to do. Otherwise, uninstall the entry and then remove it.
|
||||
*/
|
||||
if (!mac && !n)
|
||||
if (!mac && !n) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"Failed to locate MAC %pEA & Neigh %pIA VNI %u upon remote MACIP DEL",
|
||||
macaddr, ipaddr, vni);
|
||||
return;
|
||||
}
|
||||
|
||||
zvrf = zevpn->vxlan_if->vrf->info;
|
||||
|
||||
|
@ -1179,6 +1179,25 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add Auto MAC entry.
|
||||
*/
|
||||
struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn,
|
||||
const struct ethaddr *macaddr)
|
||||
{
|
||||
struct zebra_mac *mac;
|
||||
|
||||
mac = zebra_evpn_mac_add(zevpn, macaddr);
|
||||
if (!mac)
|
||||
return NULL;
|
||||
|
||||
zebra_evpn_mac_clear_fwd_info(mac);
|
||||
memset(&mac->flags, 0, sizeof(uint32_t));
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
|
||||
struct zebra_mac *mac)
|
||||
{
|
||||
@ -1592,43 +1611,44 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
|
||||
|
||||
static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
|
||||
struct zebra_mac *mac,
|
||||
uint32_t seq, uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr,
|
||||
bool sync)
|
||||
uint32_t seq, bool sync)
|
||||
{
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
char mac_buf[MAC_BUF_SIZE];
|
||||
uint32_t tmp_seq;
|
||||
const char *n_type;
|
||||
bool is_local = false;
|
||||
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
||||
tmp_seq = mac->loc_seq;
|
||||
n_type = "local";
|
||||
is_local = true;
|
||||
} else {
|
||||
tmp_seq = mac->rem_seq;
|
||||
n_type = "remote";
|
||||
}
|
||||
|
||||
if (seq < tmp_seq) {
|
||||
|
||||
if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
|
||||
sync ? "sync" : "rem", zevpn->vni,
|
||||
n_type, &mac->macaddr, tmp_seq,
|
||||
mac->flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if the mac was never advertised to bgp we must accept
|
||||
* whatever sequence number bgp sends
|
||||
* XXX - check with Vivek
|
||||
*/
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
|
||||
&& !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
|
||||
|| IS_ZEBRA_DEBUG_VXLAN) {
|
||||
char mac_buf[MAC_BUF_SIZE];
|
||||
|
||||
if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC ||
|
||||
IS_ZEBRA_DEBUG_VXLAN) {
|
||||
zlog_debug(
|
||||
"%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s",
|
||||
"%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
|
||||
sync ? "sync" : "rem", zevpn->vni,
|
||||
n_type,
|
||||
&mac->macaddr,
|
||||
ipa_len ? " IP " : "",
|
||||
ipa_len ? ipaddr2str(ipaddr, ipbuf,
|
||||
sizeof(ipbuf))
|
||||
: "",
|
||||
tmp_seq,
|
||||
n_type, &mac->macaddr, tmp_seq,
|
||||
zebra_evpn_zebra_mac_flag_dump(
|
||||
mac, mac_buf, sizeof(mac_buf)));
|
||||
}
|
||||
@ -1637,30 +1657,26 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
|
||||
char mac_buf[MAC_BUF_SIZE];
|
||||
|
||||
zlog_debug(
|
||||
"%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s",
|
||||
"%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
|
||||
sync ? "sync" : "rem", zevpn->vni, n_type,
|
||||
&mac->macaddr,
|
||||
ipa_len ? " IP " : "",
|
||||
ipa_len ? ipaddr2str(ipaddr, ipbuf,
|
||||
sizeof(ipbuf))
|
||||
: "",
|
||||
tmp_seq,
|
||||
&mac->macaddr, tmp_seq,
|
||||
zebra_evpn_zebra_mac_flag_dump(
|
||||
mac, mac_buf, sizeof(mac_buf)));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
struct zebra_evpn *zevpn, const struct ethaddr *macaddr,
|
||||
uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
|
||||
uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx)
|
||||
struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
|
||||
const struct ethaddr *macaddr,
|
||||
uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr,
|
||||
uint8_t flags, uint32_t seq,
|
||||
const esi_t *esi)
|
||||
{
|
||||
struct zebra_mac *mac;
|
||||
bool inform_bgp = false;
|
||||
@ -1672,6 +1688,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
bool old_local = false;
|
||||
bool old_bgp_ready;
|
||||
bool new_bgp_ready;
|
||||
bool created = false;
|
||||
|
||||
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
||||
if (!mac) {
|
||||
@ -1680,8 +1697,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
*/
|
||||
inform_bgp = true;
|
||||
inform_dataplane = true;
|
||||
ctx->mac_created = true;
|
||||
ctx->mac_inactive = true;
|
||||
|
||||
/* create the MAC and associate it with the dest ES */
|
||||
mac = zebra_evpn_mac_add(zevpn, macaddr);
|
||||
@ -1699,6 +1714,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
|
||||
old_bgp_ready = false;
|
||||
new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
|
||||
created = true;
|
||||
} else {
|
||||
uint32_t old_flags;
|
||||
uint32_t new_flags;
|
||||
@ -1723,14 +1739,10 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
: "",
|
||||
sticky ? " sticky" : "",
|
||||
remote_gw ? " remote_gw" : "");
|
||||
ctx->ignore_macip = true;
|
||||
return NULL;
|
||||
}
|
||||
if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
|
||||
ipaddr, true)) {
|
||||
ctx->ignore_macip = true;
|
||||
if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
|
||||
old_static = zebra_evpn_mac_is_static(mac);
|
||||
@ -1739,12 +1751,11 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
new_flags = 0;
|
||||
SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
|
||||
/* retain old local activity flag */
|
||||
if (old_flags & ZEBRA_MAC_LOCAL) {
|
||||
if (old_flags & ZEBRA_MAC_LOCAL)
|
||||
new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
|
||||
} else {
|
||||
else
|
||||
new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
|
||||
ctx->mac_inactive = true;
|
||||
}
|
||||
|
||||
if (ipa_len) {
|
||||
/* if mac-ip route do NOT update the peer flags
|
||||
* i.e. retain only flags as is
|
||||
@ -1797,7 +1808,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
if (es_change) {
|
||||
inform_bgp = true;
|
||||
inform_dataplane = true;
|
||||
ctx->mac_inactive = true;
|
||||
}
|
||||
|
||||
/* if peer-flag is being set notify dataplane that the
|
||||
@ -1828,8 +1838,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
char mac_buf[MAC_BUF_SIZE];
|
||||
|
||||
zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
|
||||
ctx->mac_created ? "created" : "updated",
|
||||
zevpn->vni, macaddr,
|
||||
created ? "created" : "updated", zevpn->vni, macaddr,
|
||||
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
|
||||
zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
|
||||
sizeof(mac_buf)),
|
||||
@ -1848,22 +1857,15 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
zebra_evpn_process_neigh_on_local_mac_change(
|
||||
zevpn, mac, seq_change, es_change);
|
||||
|
||||
if (inform_dataplane) {
|
||||
if (ipa_len)
|
||||
/* if the mac is being created as a part of MAC-IP
|
||||
* route wait for the neigh to be updated or
|
||||
* created before programming the mac
|
||||
*/
|
||||
ctx->mac_dp_update_deferred = true;
|
||||
else
|
||||
/* program the local mac in the kernel. when the ES
|
||||
* change we need to force the dataplane to reset
|
||||
* the activity as we are yet to establish activity
|
||||
* locally
|
||||
*/
|
||||
zebra_evpn_sync_mac_dp_install(
|
||||
mac, ctx->mac_inactive,
|
||||
false /* force_clear_static */, __func__);
|
||||
if (inform_dataplane && !ipa_len) {
|
||||
/* program the local mac in the kernel. when the ES
|
||||
* change we need to force the dataplane to reset
|
||||
* the activity as we are yet to establish activity
|
||||
* locally
|
||||
*/
|
||||
zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
|
||||
false /* force_clear_static */,
|
||||
__func__);
|
||||
}
|
||||
|
||||
return mac;
|
||||
@ -1987,13 +1989,12 @@ void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
|
||||
zebra_evpn_print_mac_hash_detail(bucket, ctxt);
|
||||
}
|
||||
|
||||
int zebra_evpn_mac_remote_macip_add(
|
||||
struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
|
||||
const struct ethaddr *macaddr, uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr, struct zebra_mac **macp,
|
||||
struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi)
|
||||
int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
|
||||
struct zebra_vrf *zvrf,
|
||||
const struct ethaddr *macaddr,
|
||||
struct in_addr vtep_ip, uint8_t flags,
|
||||
uint32_t seq, const esi_t *esi)
|
||||
{
|
||||
char buf1[INET6_ADDRSTRLEN];
|
||||
bool sticky;
|
||||
bool remote_gw;
|
||||
int update_mac = 0;
|
||||
@ -2015,11 +2016,8 @@ int zebra_evpn_mac_remote_macip_add(
|
||||
&& CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC",
|
||||
zevpn->vni, macaddr,
|
||||
ipa_len ? " IP " : "",
|
||||
ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1))
|
||||
: "");
|
||||
"Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
|
||||
zevpn->vni, macaddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2040,10 +2038,6 @@ int zebra_evpn_mac_remote_macip_add(
|
||||
if (!mac) {
|
||||
mac = zebra_evpn_mac_add(zevpn, macaddr);
|
||||
zebra_evpn_es_mac_ref(mac, esi);
|
||||
|
||||
/* Is this MAC created for a MACIP? */
|
||||
if (ipa_len)
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
||||
} else {
|
||||
/* When host moves but changes its (MAC,IP)
|
||||
* binding, BGP may install a MACIP entry that
|
||||
@ -2053,8 +2047,8 @@ int zebra_evpn_mac_remote_macip_add(
|
||||
* the sequence number and ignore this update
|
||||
* if appropriate.
|
||||
*/
|
||||
if (!zebra_evpn_mac_is_bgp_seq_ok(
|
||||
zevpn, mac, seq, ipa_len, ipaddr, false))
|
||||
if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq,
|
||||
false))
|
||||
return -1;
|
||||
|
||||
old_es_present = !!mac->es;
|
||||
@ -2138,12 +2132,7 @@ int zebra_evpn_mac_remote_macip_add(
|
||||
/* Update seq number. */
|
||||
mac->rem_seq = seq;
|
||||
|
||||
/* If there is no IP, return after clearing AUTO flag of MAC. */
|
||||
if (!ipa_len) {
|
||||
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
||||
return -1;
|
||||
}
|
||||
*macp = mac;
|
||||
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -176,17 +176,6 @@ struct rmac_walk_ctx {
|
||||
struct json_object *json;
|
||||
};
|
||||
|
||||
/* temporary datastruct to pass info between the mac-update and
|
||||
* neigh-update while handling mac-ip routes
|
||||
*/
|
||||
struct sync_mac_ip_ctx {
|
||||
bool ignore_macip;
|
||||
bool mac_created;
|
||||
bool mac_inactive;
|
||||
bool mac_dp_update_deferred;
|
||||
struct zebra_mac *mac;
|
||||
};
|
||||
|
||||
/**************************** SYNC MAC handling *****************************/
|
||||
/* if the mac has been added of a mac-route from the peer
|
||||
* or if it is being referenced by a neigh added by the
|
||||
@ -232,6 +221,8 @@ struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevi,
|
||||
const struct ethaddr *mac);
|
||||
struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevi,
|
||||
const struct ethaddr *macaddr);
|
||||
struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevi,
|
||||
const struct ethaddr *macaddr);
|
||||
int zebra_evpn_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac);
|
||||
int zebra_evpn_macip_send_msg_to_client(uint32_t id,
|
||||
const struct ethaddr *macaddr,
|
||||
@ -255,20 +246,22 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
|
||||
int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
|
||||
uint32_t flags, bool force);
|
||||
void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevi);
|
||||
struct zebra_mac *zebra_evpn_proc_sync_mac_update(
|
||||
struct zebra_evpn *zevi, const struct ethaddr *macaddr,
|
||||
uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
|
||||
uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx);
|
||||
struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevi,
|
||||
const struct ethaddr *macaddr,
|
||||
uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr,
|
||||
uint8_t flags, uint32_t seq,
|
||||
const esi_t *esi);
|
||||
void zebra_evpn_sync_mac_del(struct zebra_mac *mac);
|
||||
void zebra_evpn_rem_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac);
|
||||
void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt);
|
||||
void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
|
||||
void *ctxt);
|
||||
int zebra_evpn_mac_remote_macip_add(
|
||||
struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
|
||||
const struct ethaddr *macaddr, uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr, struct zebra_mac **macp,
|
||||
struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi);
|
||||
int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
|
||||
struct zebra_vrf *zvrf,
|
||||
const struct ethaddr *macaddr,
|
||||
struct in_addr vtep_ip, uint8_t flags,
|
||||
uint32_t seq, const esi_t *esi);
|
||||
|
||||
int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
|
||||
struct zebra_evpn *zevpn,
|
||||
|
@ -501,22 +501,33 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(struct zebra_evpn *zevpn,
|
||||
{
|
||||
uint32_t tmp_seq;
|
||||
const char *n_type;
|
||||
bool is_local = false;
|
||||
|
||||
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
||||
tmp_seq = n->loc_seq;
|
||||
n_type = "local";
|
||||
is_local = true;
|
||||
} else {
|
||||
tmp_seq = n->rem_seq;
|
||||
n_type = "remote";
|
||||
}
|
||||
|
||||
if (seq < tmp_seq) {
|
||||
if (is_local && !zebra_evpn_neigh_is_ready_for_bgp(n)) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH ||
|
||||
IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s-macip not ready vni %u %s mac %pEA IP %pIA lower seq %u f 0x%x",
|
||||
sync ? "sync" : "remote", zevpn->vni,
|
||||
n_type, macaddr, &n->ip, tmp_seq,
|
||||
n->flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if the neigh was never advertised to bgp we must accept
|
||||
* whatever sequence number bgp sends
|
||||
* XXX - check with Vivek
|
||||
*/
|
||||
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
|
||||
&& !zebra_evpn_neigh_is_ready_for_bgp(n)) {
|
||||
if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
|
||||
|| IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
@ -615,11 +626,10 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n)
|
||||
struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
|
||||
struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
|
||||
const esi_t *esi, struct sync_mac_ip_ctx *ctx)
|
||||
const esi_t *esi, struct zebra_mac *mac)
|
||||
{
|
||||
struct interface *ifp = NULL;
|
||||
bool is_router;
|
||||
struct zebra_mac *mac = ctx->mac;
|
||||
uint32_t tmp_seq;
|
||||
bool old_router = false;
|
||||
bool old_bgp_ready = false;
|
||||
@ -780,8 +790,8 @@ struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
|
||||
inform_bgp = true;
|
||||
|
||||
new_mac_static = zebra_evpn_mac_is_static(mac);
|
||||
if ((old_mac_static != new_mac_static) || ctx->mac_dp_update_deferred)
|
||||
zebra_evpn_sync_mac_dp_install(mac, ctx->mac_inactive,
|
||||
if (old_mac_static != new_mac_static)
|
||||
zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
|
||||
false /* force_clear_static */,
|
||||
__func__);
|
||||
|
||||
@ -1275,10 +1285,12 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
|
||||
zlog_debug("AUTO MAC %pEA created for neigh %pIA on VNI %u",
|
||||
macaddr, ip, zevpn->vni);
|
||||
|
||||
zmac = zebra_evpn_mac_add(zevpn, macaddr);
|
||||
zebra_evpn_mac_clear_fwd_info(zmac);
|
||||
memset(&zmac->flags, 0, sizeof(uint32_t));
|
||||
SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
|
||||
zmac = zebra_evpn_mac_add_auto(zevpn, macaddr);
|
||||
if (!zmac) {
|
||||
zlog_debug("Failed to add MAC %pEA VNI %u", macaddr,
|
||||
zevpn->vni);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
|
||||
/*
|
||||
@ -2233,6 +2245,12 @@ void zebra_evpn_neigh_remote_uninstall(struct zebra_evpn *zevpn,
|
||||
zebra_evpn_neigh_del(zevpn, n);
|
||||
zebra_evpn_deref_ip2mac(zevpn, mac);
|
||||
}
|
||||
} else {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s: IP %pIA MAC %pEA (flags 0x%x) found doesn't match MAC %pEA, ignoring Neigh DEL",
|
||||
__func__, ipaddr, &n->emac, n->flags,
|
||||
&mac->macaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n);
|
||||
struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
|
||||
struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len,
|
||||
const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
|
||||
const esi_t *esi, struct sync_mac_ip_ctx *ctx);
|
||||
const esi_t *esi, struct zebra_mac *mac);
|
||||
void zebra_evpn_neigh_del_all(struct zebra_evpn *zevpn, int uninstall,
|
||||
int upd_client, uint32_t flags);
|
||||
struct zebra_neigh *zebra_evpn_neigh_lookup(struct zebra_evpn *zevpn,
|
||||
|
@ -3747,6 +3747,27 @@ DEFPY (clear_evpn_dup_addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFPY_HIDDEN (evpn_accept_bgp_seq,
|
||||
evpn_accept_bgp_seq_cmd,
|
||||
"evpn accept-bgp-seq",
|
||||
"EVPN\n"
|
||||
"Accept all sequence numbers from BGP\n")
|
||||
{
|
||||
zebra_vxlan_set_accept_bgp_seq(true);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY_HIDDEN (no_evpn_accept_bgp_seq,
|
||||
no_evpn_accept_bgp_seq_cmd,
|
||||
"no evpn accept-bgp-seq",
|
||||
NO_STR
|
||||
"EVPN\n"
|
||||
"Accept all sequence numbers from BGP\n")
|
||||
{
|
||||
zebra_vxlan_set_accept_bgp_seq(false);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Static ip route configuration write function. */
|
||||
static int zebra_ip_config(struct vty *vty)
|
||||
{
|
||||
@ -3952,6 +3973,9 @@ static int config_write_protocol(struct vty *vty)
|
||||
|
||||
zebra_pbr_config_write(vty);
|
||||
|
||||
if (!zebra_vxlan_get_accept_bgp_seq())
|
||||
vty_out(vty, "no evpn accept-bgp-seq\n");
|
||||
|
||||
/* Include nexthop-group config */
|
||||
if (!zebra_nhg_kernel_nexthops_enabled())
|
||||
vty_out(vty, "no zebra nexthop kernel enable\n");
|
||||
@ -4589,6 +4613,8 @@ void zebra_vty_init(void)
|
||||
install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd);
|
||||
install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd);
|
||||
install_element(CONFIG_NODE, &evpn_accept_bgp_seq_cmd);
|
||||
install_element(CONFIG_NODE, &no_evpn_accept_bgp_seq_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &show_neigh_cmd);
|
||||
|
||||
|
@ -69,6 +69,9 @@ DEFINE_HOOK(zebra_rmac_update,
|
||||
const char *reason),
|
||||
(rmac, zl3vni, delete, reason));
|
||||
|
||||
/* config knobs */
|
||||
static bool accept_bgp_seq = true;
|
||||
|
||||
/* static function declarations */
|
||||
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
|
||||
void **args);
|
||||
@ -6284,6 +6287,17 @@ extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Config knob for accepting lower sequence numbers */
|
||||
void zebra_vxlan_set_accept_bgp_seq(bool set)
|
||||
{
|
||||
accept_bgp_seq = set;
|
||||
}
|
||||
|
||||
bool zebra_vxlan_get_accept_bgp_seq(void)
|
||||
{
|
||||
return accept_bgp_seq;
|
||||
}
|
||||
|
||||
/* Cleanup BGP EVPN configuration upon client disconnect */
|
||||
extern void zebra_evpn_init(void)
|
||||
{
|
||||
|
@ -225,6 +225,9 @@ extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
|
||||
struct ethaddr *macaddr,
|
||||
vlanid_t vid);
|
||||
|
||||
extern void zebra_vxlan_set_accept_bgp_seq(bool set);
|
||||
extern bool zebra_vxlan_get_accept_bgp_seq(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user