From: Mitesh Kanjariya Date: Sun, 8 Oct 2017 01:49:27 +0000 (-0700) Subject: zebra, lib: zebra changes for symmetric routing support X-Git-Tag: frr-4.0-dev~58^2~75 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=b7cfce934fc04185d2f51252843cd611ddaac16a;p=matthieu%2Ffrr.git zebra, lib: zebra changes for symmetric routing support Signed-off-by: Mitesh Kanjariya --- diff --git a/lib/log.c b/lib/log.c index 7589934b69..bf65ac7c7d 100644 --- a/lib/log.c +++ b/lib/log.c @@ -945,6 +945,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), DESC_ENTRY(ZEBRA_VNI_ADD), DESC_ENTRY(ZEBRA_VNI_DEL), + DESC_ENTRY(ZEBRA_L3VNI_ADD), + DESC_ENTRY(ZEBRA_L3VNI_DEL), DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD), DESC_ENTRY(ZEBRA_REMOTE_VTEP_DEL), DESC_ENTRY(ZEBRA_MACIP_ADD), diff --git a/lib/prefix.c b/lib/prefix.c index 10f77bda87..f1c25d24d9 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -301,7 +301,7 @@ static const struct in6_addr maskbytes6[] = { #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) -static int is_zero_mac(const struct ethaddr *mac) +int is_zero_mac(struct ethaddr *mac) { int i = 0; diff --git a/lib/prefix.h b/lib/prefix.h index 0732cf1290..aa857f330c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -348,6 +348,7 @@ extern void masklen2ip6(const int, struct in6_addr *); extern const char *inet6_ntoa(struct in6_addr); +extern int is_zero_mac(struct ethaddr *); extern int prefix_str2mac(const char *str, struct ethaddr *mac); extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size); diff --git a/lib/vrf.c b/lib/vrf.c index 056f778a3e..6a0ab55b81 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -225,6 +225,17 @@ static void vrf_disable(struct vrf *vrf) (*vrf_master.vrf_disable_hook)(vrf); } +const char *vrf_id_to_name(vrf_id_t vrf_id) +{ + struct vrf *vrf; + + vrf = vrf_lookup_by_id(vrf_id); + if (vrf) + return vrf->name; + + return NULL; +} + vrf_id_t vrf_name_to_id(const char *name) { struct vrf *vrf; diff --git a/lib/vrf.h b/lib/vrf.h index e93e993776..19e8ac9162 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -103,6 +103,7 @@ extern struct vrf_name_head vrfs_by_name; extern struct vrf *vrf_lookup_by_id(vrf_id_t); extern struct vrf *vrf_lookup_by_name(const char *); extern struct vrf *vrf_get(vrf_id_t, const char *); +extern const char *vrf_id_to_name(vrf_id_t); extern vrf_id_t vrf_name_to_id(const char *); #define VRF_GET_ID(V, NAME) \ diff --git a/lib/zclient.c b/lib/zclient.c index 655e4e1a80..4f3b9b3fa6 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2205,6 +2205,16 @@ static int zclient_read(struct thread *thread) (*zclient->local_vni_del)(command, zclient, length, vrf_id); break; + case ZEBRA_L3VNI_ADD: + if (zclient->local_l3vni_add) + (*zclient->local_l3vni_add)(command, zclient, length, + vrf_id); + break; + case ZEBRA_L3VNI_DEL: + if (zclient->local_l3vni_del) + (*zclient->local_l3vni_del)(command, zclient, length, + vrf_id); + break; case ZEBRA_MACIP_ADD: if (zclient->local_macip_add) (*zclient->local_macip_add)(command, zclient, length, diff --git a/lib/zclient.h b/lib/zclient.h index de58044671..d89b29a9e5 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -112,6 +112,8 @@ typedef enum { ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_VNI_ADD, ZEBRA_VNI_DEL, + ZEBRA_L3VNI_ADD, + ZEBRA_L3VNI_DEL, ZEBRA_REMOTE_VTEP_ADD, ZEBRA_REMOTE_VTEP_DEL, ZEBRA_MACIP_ADD, @@ -200,6 +202,8 @@ struct zclient { int (*fec_update)(int, struct zclient *, uint16_t); int (*local_vni_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t); + int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t); + int (*local_l3vni_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); diff --git a/zebra/main.c b/zebra/main.c index 5eb8e75b87..ada9f5e4e3 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -300,7 +300,6 @@ int main(int argc, char **argv) zebra_if_init(); zebra_debug_init(); router_id_cmd_init(); - zebra_vty_init(); access_list_init(); prefix_list_init(); #if defined(HAVE_RTADV) @@ -322,6 +321,10 @@ int main(int argc, char **argv) * routing socket. */ zebra_ns_init(); + /* Initialize show/config command after the vrf initialization is + * complete */ + zebra_vty_init(); + #if defined(HANDLE_ZAPI_FUZZING) if (fuzzing) { zserv_read_file(fuzzing); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 602dc5ea41..5ede948e0a 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -30,6 +30,7 @@ #include "zebra_vrf.h" #include "zebra_memory.h" #include "rt.h" +#include "zebra_vxlan.h" DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space") @@ -49,6 +50,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) #endif zns->if_table = route_table_init(); + zebra_vxlan_ns_init(zns); kernel_init(zns); interface_list(zns); route_read(zns); @@ -61,6 +63,7 @@ int zebra_ns_disable(ns_id_t ns_id, void **info) struct zebra_ns *zns = (struct zebra_ns *)(*info); route_table_finish(zns->if_table); + zebra_vxlan_ns_disable(zns); #if defined(HAVE_RTADV) rtadv_terminate(zns); #endif diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 6cfba93e50..0c340d8d59 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -49,6 +49,9 @@ struct zebra_ns { struct route_table *if_table; + /* L3-VNI hash table (for EVPN). Only in default instance */ + struct hash *l3vni_table; + #if defined(HAVE_RTADV) struct rtadv rtadv; #endif /* HAVE_RTADV */ diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 0d0a8dd747..d2e3f94b47 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -250,6 +250,10 @@ static int zebra_vrf_delete(struct vrf *vrf) route_table_finish(zvrf->rnh_table[afi]); route_table_finish(zvrf->import_check_table[afi]); } + + /* cleanup evpn states for vrf */ + zebra_vxlan_vrf_delete(zvrf); + list_delete_all_node(zvrf->rid_all_sorted_list); list_delete_all_node(zvrf->rid_lo_sorted_list); XFREE(MTYPE_ZEBRA_VRF, zvrf); @@ -474,6 +478,7 @@ static int vrf_config_write(struct vty *vty) if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); + vty_out(vty, " vni %u\n", zvrf->l3vni); vty_out(vty, "!\n"); } } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 1dfc0b3eb8..c7a0717ee8 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -24,6 +24,7 @@ #include #include +#include /* MPLS (Segment Routing) global block */ typedef struct mpls_srgb_t_ { @@ -114,6 +115,9 @@ struct zebra_vrf { */ int advertise_gw_macip; + /* l3-vni info */ + vni_t l3vni; + /* Route Installs */ uint64_t installs; uint64_t removals; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e4407d7316..c82072ab35 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -49,6 +49,7 @@ #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/ipforward.h" +#include "zebra/zebra_vxlan_private.h" extern int allow_delete; @@ -65,6 +66,14 @@ static void vty_show_ip_route_summary(struct vty *vty, static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table); +/* + * special macro to allow us to get the correct zebra_vrf + */ +#define ZEBRA_DECLVAR_CONTEXT(A, B) \ + struct vrf *A = VTY_GET_CONTEXT(vrf); \ + struct zebra_vrf *B = \ + (vrf) ? vrf->info : NULL; \ + /* VNI range as per RFC 7432 */ #define CMD_VNI_RANGE "(1-16777215)" @@ -1889,6 +1898,80 @@ DEFUN (show_vrf, return CMD_SUCCESS; } +DEFUN (vrf_vni_mapping, + vrf_vni_mapping_cmd, + "vni " CMD_VNI_RANGE, + "VNI\n" + "VNI-ID\n") +{ + int ret = 0; + + ZEBRA_DECLVAR_CONTEXT(vrf, zvrf); + vni_t vni = strtoul(argv[1]->arg, NULL, 10); + char err[ERR_STR_SZ]; + + assert(vrf); + assert(zvrf); + + ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, 1); + if (ret != 0) { + vty_out(vty, "%s\n", err); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_vrf_vni_mapping, + no_vrf_vni_mapping_cmd, + "no vni " CMD_VNI_RANGE, + NO_STR + "VNI\n" + "VNI-ID") +{ + int ret = 0; + char err[ERR_STR_SZ]; + vni_t vni = strtoul(argv[2]->arg, NULL, 10); + + ZEBRA_DECLVAR_CONTEXT(vrf, zvrf); + + assert(vrf); + assert(zvrf); + + ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, 0); + if (ret != 0) { + vty_out(vty, "%s\n", err); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* show vrf */ +DEFUN (show_vrf_vni, + show_vrf_vni_cmd, + "show vrf vni", + SHOW_STR + "VRF\n" + "VNI\n") +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + zvrf = vrf->info; + if (!zvrf) + continue; + + vty_out(vty, "vrf: %s VNI: %u", + zvrf_name(zvrf), + zvrf->l3vni); + vty_out(vty, "\n"); + } + + return CMD_SUCCESS; +} + DEFUN (show_evpn_vni, show_evpn_vni_cmd, "show evpn vni [json]", @@ -1924,6 +2007,109 @@ DEFUN (show_evpn_vni_vni, return CMD_SUCCESS; } +DEFUN (show_evpn_l3vni, + show_evpn_l3vni_cmd, + "show evpn l3vni [json]", + SHOW_STR + "EVPN\n" + "L3 VNI\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + + zebra_vxlan_print_l3vnis(vty, uj); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_l3vni_vni, + show_evpn_l3vni_vni_cmd, + "show evpn l3vni " CMD_VNI_RANGE "[json]", + SHOW_STR + "EVPN\n" + "L3 VxLAN Network Identifier\n" + "VNI number\n" + JSON_STR) +{ + vni_t vni; + u_char uj = use_json(argc, argv); + + vni = strtoul(argv[3]->arg, NULL, 10); + zebra_vxlan_print_l3vni(vty, vni, uj); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_rmac_l3vni, + show_evpn_rmac_l3vni_cmd, + "show evpn rmac l3vni " CMD_VNI_RANGE "[json]", + SHOW_STR + "EVPN\n" + "RMAC\n" + "L3-VNI\n" + "VNI number\n" + JSON_STR) +{ + vni_t l3vni = 0; + u_char uj = use_json(argc, argv); + + l3vni = strtoul(argv[4]->arg, NULL, 10); + zebra_vxlan_print_rmacs_l3vni(vty, l3vni, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_evpn_rmac_l3vni_all, + show_evpn_rmac_l3vni_all_cmd, + "show evpn rmac l3vni all [json]", + SHOW_STR + "EVPN\n" + "RMAC addresses\n" + "L3-VNI\n" + "All VNIs\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + + zebra_vxlan_print_rmacs_all_l3vni(vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_evpn_nh_l3vni, + show_evpn_nh_l3vni_cmd, + "show evpn next-hops l3vni " CMD_VNI_RANGE "[json]", + SHOW_STR + "EVPN\n" + "Remote Vteps\n" + "L3-VNI\n" + "VNI number\n" + JSON_STR) +{ + vni_t l3vni; + u_char uj = use_json(argc, argv); + + l3vni = strtoul(argv[4]->arg, NULL, 10); + zebra_vxlan_print_nh_l3vni(vty, l3vni, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_evpn_nh_l3vni_all, + show_evpn_nh_l3vni_all_cmd, + "show evpn next-hops l3vni all [json]", + SHOW_STR + "EVPN\n" + "Remote VTEPs\n" + "L3-VNI\n" + "All VNIs\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + + zebra_vxlan_print_nh_all_l3vni(vty, uj); + + return CMD_SUCCESS; +} + DEFUN (show_evpn_mac_vni, show_evpn_mac_vni_cmd, "show evpn mac vni " CMD_VNI_RANGE "[json]", @@ -2594,6 +2780,7 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &no_zebra_packet_process_cmd); install_element(VIEW_NODE, &show_vrf_cmd); + install_element(VIEW_NODE, &show_vrf_vni_cmd); install_element(VIEW_NODE, &show_route_cmd); install_element(VIEW_NODE, &show_route_detail_cmd); install_element(VIEW_NODE, &show_route_summary_cmd); @@ -2619,6 +2806,12 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_vni_cmd); install_element(VIEW_NODE, &show_evpn_vni_vni_cmd); + install_element(VIEW_NODE, &show_evpn_l3vni_cmd); + install_element(VIEW_NODE, &show_evpn_l3vni_vni_cmd); + install_element(VIEW_NODE, &show_evpn_rmac_l3vni_cmd); + install_element(VIEW_NODE, &show_evpn_rmac_l3vni_all_cmd); + install_element(VIEW_NODE, &show_evpn_nh_l3vni_cmd); + install_element(VIEW_NODE, &show_evpn_nh_l3vni_all_cmd); install_element(VIEW_NODE, &show_evpn_mac_vni_cmd); install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd); install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd); @@ -2628,4 +2821,10 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_neigh_vni_all_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd); + + install_element(CONFIG_NODE, &vrf_vni_mapping_cmd); + install_element(CONFIG_NODE, &no_vrf_vni_mapping_cmd); + install_element(VRF_NODE, &vrf_vni_mapping_cmd); + install_element(VRF_NODE, &no_vrf_vni_mapping_cmd); + } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 9c70b55a1a..cecd8b981b 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -49,6 +49,7 @@ #include "lib/json.h" DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); +DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC"); DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); @@ -91,11 +92,49 @@ static int zvni_neigh_send_del_to_client(vni_t vni, struct ethaddr *macaddr, u_char flags); static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n); static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n); -static zebra_vni_t *zvni_map_svi(struct interface *ifp, +static zebra_vni_t *zvni_from_svi(struct interface *ifp, struct interface *br_if); static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if); +/* l3-vni next-hop neigh related APIs */ +/*static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, + struct ipaddr *ip); +static void *zl3vni_nh_alloc(void *p); +static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, + struct ipaddr *vtep_ip, + struct ethaddr *rmac); +static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); +static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); +static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);*/ + +/* l3-vni rmac related APIs */ +static void zl3vni_print_rmac_hash(struct hash_backet *, void *); +static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *, void *); +/*static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac); +static void *zl3vni_rmac_alloc(void *p); +static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac); +static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); +static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); +static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, + zebra_mac_t *zrmac);*/ + +/* l3-vni related APIs*/ +static int is_vni_l3(vni_t); +static zebra_l3vni_t *zl3vni_lookup(vni_t vni); +static void *zl3vni_alloc(void *p); +static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id); +static int zl3vni_del(zebra_l3vni_t *zl3vni); +static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t); +static vni_t zvni_get_l3vni(zebra_vni_t *zvni); +static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni); +static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni); +static void zvni_get_rmac(zebra_vni_t *zvni, struct ethaddr *rmac); +static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni); +static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni); + static unsigned int mac_hash_keymake(void *p); static int mac_cmp(const void *p1, const void *p2); static void *zvni_mac_alloc(void *p); @@ -603,6 +642,180 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) } } +static void zl3vni_print_nh_hash(struct hash_backet *backet, + void *ctx) +{ + struct nh_walk_ctx *wctx = NULL; + struct vty *vty = NULL; + struct json_object *json = NULL; + struct json_object *json_nh = NULL; + zebra_neigh_t *n = NULL; + char buf1[ETHER_ADDR_STRLEN]; + + wctx = (struct nh_walk_ctx *)ctx; + vty = wctx->vty; + json = wctx->json; + if (json) + json_nh = json_object_new_object(); + n = (zebra_neigh_t *)backet->data; + if (!n) + return; + + if (!json) { + vty_out(vty, "%15s %-17s %6d\n", + inet_ntoa(n->r_vtep_ip), + prefix_mac2str(&n->emac, buf1, sizeof(buf1)), + n->nh_refcnt); + } else { + json_object_string_add(json_nh, "vtep-ip", + inet_ntoa(n->r_vtep_ip)); + json_object_string_add(json_nh, "rmac", + prefix_mac2str(&n->emac, buf1, + sizeof(buf1))); + json_object_int_add(json_nh, "refCnt", n->nh_refcnt); + } +} + +static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, + void *ctx) +{ + struct vty *vty = NULL; + json_object *json = NULL; + json_object *json_vni = NULL; + json_object *json_mac = NULL; + zebra_l3vni_t *zl3vni = NULL; + u_int32_t num_rmacs; + struct rmac_walk_ctx *wctx = NULL; + char vni_str[VNI_STR_LEN]; + + wctx = (struct rmac_walk_ctx *)ctx; + vty = (struct vty *)wctx->vty; + json = (struct json_object *)wctx->json; + + zl3vni = (zebra_l3vni_t *)backet->data; + if (!zl3vni) { + if (json) + vty_out(vty, "{}\n"); + return; + } + + num_rmacs = hashcount(zl3vni->rmac_table); + if (!num_rmacs) + return; + + if (json) { + json_vni = json_object_new_object(); + json_mac = json_object_new_array(); + snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); + } + + if (json == NULL) { + vty_out(vty, "\nVNI %u #MACs %u\n\n", + zl3vni->vni, num_rmacs); + vty_out(vty, "%-17s %-21s %-6s\n", "MAC", + "Remote VTEP", "Refcnt"); + } else + json_object_int_add(json_vni, "numRmacs", num_rmacs); + + /* assign per-vni to wctx->json object to fill macs + * under the vni. Re-assign primary json object to fill + * next vni information. + */ + wctx->json = json_mac; + hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, wctx); + wctx->json = json; + if (json) { + json_object_object_add(json_vni, "rmacs", json_mac); + json_object_object_add(json, vni_str, json_vni); + } +} + +static void zl3vni_print_rmac_hash(struct hash_backet *backet, + void *ctx) +{ + zebra_mac_t *zrmac = NULL; + struct rmac_walk_ctx *wctx = NULL; + struct vty *vty = NULL; + struct json_object *json = NULL; + struct json_object *json_rmac = NULL; + char buf[ETHER_ADDR_STRLEN]; + + wctx = (struct rmac_walk_ctx *)ctx; + vty = wctx->vty; + json = wctx->json; + if (json) + json_rmac = json_object_new_object(); + zrmac = (zebra_mac_t *)backet->data; + if (!zrmac) + return; + + if (!json) { + vty_out(vty, "%-17s %-21s %-6d\n", + prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), + inet_ntoa(zrmac->fwd_info.r_vtep_ip), + zrmac->rmac_refcnt); + } else { + json_object_string_add(json_rmac, "rmac", + prefix_mac2str(&zrmac->macaddr, buf, + sizeof(buf))); + json_object_string_add(json_rmac, "vtep-ip", + inet_ntoa(zrmac->fwd_info.r_vtep_ip)); + json_object_int_add(json_rmac, "refcnt", zrmac->rmac_refcnt); + json_object_array_add(json, json_rmac); + } +} + +/* print a specific L3 VNI entry */ +static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) +{ + char buf[ETHER_ADDR_STRLEN]; + struct vty *vty = NULL; + json_object *json = NULL; + zebra_vni_t *zvni = NULL; + json_object *json_vni_list = NULL; + struct listnode *node = NULL, *nnode = NULL; + + vty = ctx[0]; + json = ctx[1]; + + if (!json) { + vty_out(vty, "VNI: %u\n", zl3vni->vni); + vty_out(vty, " Vxlan-Intf: %s\n", + zl3vni_vxlan_if_name(zl3vni)); + vty_out(vty, " SVI-If: %s\n", + zl3vni_svi_if_name(zl3vni)); + vty_out(vty, " State: %s\n", + zl3vni_state2str(zl3vni)); + vty_out(vty, " Vrf: %s\n", + zl3vni_vrf_name(zl3vni)); + vty_out(vty, " Rmac: %s\n", + zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); + vty_out(vty, " L2-VNIs: "); + for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) + vty_out(vty, "%u ", zvni->vni); + vty_out(vty, "\n"); + } else { + json_vni_list = json_object_new_array(); + json_object_int_add(json, "vni", zl3vni->vni); + json_object_string_add(json, "vxlan-intf", + zl3vni_vxlan_if_name(zl3vni)); + json_object_string_add(json, "svi-if", + zl3vni_svi_if_name(zl3vni)); + json_object_string_add(json, "state", + zl3vni_state2str(zl3vni)); + json_object_string_add(json, "vrf", + zl3vni_vrf_name(zl3vni)); + json_object_string_add(json, "rmac", + zl3vni_rmac2str(zl3vni, buf, + sizeof(buf))); + for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) { + json_object_array_add(json_vni_list, + json_object_new_int(zvni->vni)); + } + json_object_object_add(json, "l2-vnis", json_vni_list); + } +} + /* * Print a specific VNI entry. */ @@ -619,10 +832,14 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) vty = ctxt[0]; json = ctxt[1]; - if (json == NULL) + if (json == NULL) { vty_out(vty, "VNI: %u\n", zvni->vni); - else + vty_out(vty, " VRF: %s\n", vrf_id_to_name(zvni->vrf_id)); + } else { json_object_int_add(json, "vni", zvni->vni); + json_object_string_add(json, "vrf", + vrf_id_to_name(zvni->vrf_id)); + } if (!zvni->vxlan_if) { // unexpected if (json == NULL) @@ -682,6 +899,47 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) } } +/* print a L3 VNI hash entry */ +static void zl3vni_print_hash(struct hash_backet *backet, + void *ctx[]) +{ + char buf[ETHER_ADDR_STRLEN]; + struct vty *vty = NULL; + json_object *json = NULL; + zebra_l3vni_t *zl3vni = NULL; + + vty = ctx[0]; + json = ctx[1]; + + zl3vni = (zebra_l3vni_t *)backet->data; + if (!zl3vni) + return; + + if (!json) { + vty_out(vty, "%-10u %-20s %-20s %-5s %-37s %-18s\n", + zl3vni->vni, + zl3vni_vxlan_if_name(zl3vni), + zl3vni_svi_if_name(zl3vni), + zl3vni_state2str(zl3vni), + zl3vni_vrf_name(zl3vni), + zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); + } else { + json_object_int_add(json, "vni", zl3vni->vni); + json_object_string_add(json, "vxlan-if", + zl3vni_vxlan_if_name(zl3vni)); + json_object_string_add(json, "svi-if", + zl3vni_svi_if_name(zl3vni)); + json_object_string_add(json, "state", + zl3vni_state2str(zl3vni)); + json_object_string_add(json, "vrf", + zl3vni_vrf_name(zl3vni)); + json_object_string_add(json, "rmac", + zl3vni_rmac2str(zl3vni, buf, + sizeof(buf))); + } + +} + /* * Print a VNI hash entry - called for display of all VNIs. */ @@ -714,10 +972,12 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) num_macs = num_valid_macs(zvni); num_neigh = hashcount(zvni->neigh_table); if (json == NULL) - vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni, + vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u %-37s\n", + zvni->vni, zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh, - num_vteps); + num_vteps, + vrf_id_to_name(zvni->vrf_id)); else { char vni_str[VNI_STR_LEN]; snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); @@ -753,11 +1013,11 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ipaddr *ip, u_char flags, u_int16_t cmd) { - struct zserv *client; - struct stream *s; - int ipa_len; char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; + int ipa_len; + struct zserv *client = NULL; + struct stream *s = NULL; client = zebra_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ @@ -785,12 +1045,13 @@ static int zvni_macip_send_msg_to_client(vni_t vni, stream_putc(s, flags); /* sticky mac/gateway mac */ + /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s", + "Send MACIP %s flags 0x%x MAC %s IP %s L2-VNI %u to %s", (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags, prefix_mac2str(macaddr, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2)), vni, @@ -1000,7 +1261,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni, if (IS_ZEBRA_NEIGH_INACTIVE(n)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "neigh %s (MAC %s) on VNI %u is now ACTIVE", + "neigh %s (MAC %s) on L2-VNI %u is now ACTIVE", ipaddr2str(&n->ip, buf2, sizeof(buf2)), prefix_mac2str(&n->emac, buf, @@ -1040,7 +1301,7 @@ static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni, if (IS_ZEBRA_NEIGH_ACTIVE(n)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "neigh %s (MAC %s) on VNI %u is now INACTIVE", + "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE", ipaddr2str(&n->ip, buf2, sizeof(buf2)), prefix_mac2str(&n->emac, buf, @@ -1077,7 +1338,7 @@ static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni, if (IS_ZEBRA_NEIGH_ACTIVE(n)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "neigh %s (MAC %s) on VNI %u INACTIVE", + "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE", ipaddr2str(&n->ip, buf2, sizeof(buf2)), prefix_mac2str(&n->emac, buf, @@ -1302,12 +1563,17 @@ static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, struct ethaddr *macaddr, struct ipaddr *ip) { - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; - zebra_neigh_t *n = NULL; - zebra_mac_t *mac = NULL; + vni_t l3vni = 0; + struct ethaddr rmac; char buf[ETHER_ADDR_STRLEN]; + char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; + zebra_neigh_t *n = NULL; + zebra_mac_t *mac = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + + memset(&rmac, 0, sizeof(struct ethaddr)); zif = zvni->vxlan_if->info; if (!zif) @@ -1315,6 +1581,12 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, vxl = &zif->l2info.vxl; + /* get the l3-vni */ + l3vni = zvni_get_l3vni(zvni); + + /* get the rmac */ + zvni_get_rmac(zvni, &rmac); + mac = zvni_mac_lookup(zvni, macaddr); if (!mac) { mac = zvni_mac_add(zvni, macaddr); @@ -1353,8 +1625,10 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP", + "SVI %s(%u) L2-VNI %u L3-VNI %u RMAC %s , sending GW MAC %s IP %s add to BGP", ifp->name, ifp->ifindex, zvni->vni, + l3vni, + prefix_mac2str(&rmac, buf1, sizeof(buf1)), prefix_mac2str(macaddr, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2))); @@ -1370,10 +1644,21 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, struct ipaddr *ip) { - zebra_neigh_t *n = NULL; - zebra_mac_t *mac = NULL; + vni_t l3vni = 0; + struct ethaddr rmac; + char buf[ETHER_ADDR_STRLEN]; char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; + zebra_neigh_t *n = NULL; + zebra_mac_t *mac = NULL; + + memset(&rmac, 0, sizeof(struct ethaddr)); + + /* get the l30vni */ + l3vni = zvni_get_l3vni(zvni); + + /* get the rmac */ + zvni_get_rmac(zvni, &rmac); /* If the neigh entry is not present nothing to do*/ n = zvni_neigh_lookup(zvni, ip); @@ -1395,8 +1680,9 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", - ifp->name, ifp->ifindex, zvni->vni, + "SVI %s(%u) L2-VNI %u, L3-VNI %u RMAC %s sending GW MAC %s IP %s del to BGP", + ifp->name, ifp->ifindex, zvni->vni, l3vni, + prefix_mac2str(&rmac, buf, sizeof(buf)), prefix_mac2str(&(n->emac), buf1, sizeof(buf1)), ipaddr2str(ip, buf2, sizeof(buf2))); @@ -1747,7 +2033,8 @@ static zebra_vni_t *zvni_map_vlan(struct interface *ifp, * Map SVI and associated bridge to a VNI. This is invoked upon getting * neighbor notifications, to see if they are of interest. */ -static zebra_vni_t *zvni_map_svi(struct interface *ifp, struct interface *br_if) +static zebra_vni_t *zvni_from_svi(struct interface *ifp, + struct interface *br_if) { struct zebra_ns *zns; struct route_node *rn; @@ -2133,13 +2420,15 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) zserv_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); stream_putl(s, zvni->vni); stream_put_in_addr(s, &zvni->local_vtep_ip); + stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */ /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Send VNI_ADD %u %s to %s", + zlog_debug("Send VNI_ADD %u %s tenant vrf %s to %s", zvni->vni, inet_ntoa(zvni->local_vtep_ip), + vrf_id_to_name(zvni->vrf_id), zebra_route_string(client->proto)); client->vniadd_cnt++; @@ -2189,10 +2478,9 @@ static void zvni_build_hash_table() /* Walk VxLAN interfaces and create VNI hash. */ zns = zebra_ns_lookup(NS_DEFAULT); for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { + vni_t vni; struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; - zebra_vni_t *zvni; - vni_t vni; ifp = (struct interface *)rn->info; if (!ifp) @@ -2200,39 +2488,80 @@ static void zvni_build_hash_table() zif = ifp->info; if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) continue; - vxl = &zif->l2info.vxl; + vxl = &zif->l2info.vxl; vni = vxl->vni; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Create VNI hash for intf %s(%u) VNI %u local IP %s", - ifp->name, ifp->ifindex, vni, - inet_ntoa(vxl->vtep_ip)); + if (is_vni_l3(vni)) { + zebra_l3vni_t *zl3vni = NULL; - /* VNI hash entry is not expected to exist. */ - zvni = zvni_lookup(vni); - if (zvni) { - zlog_err( - "VNI hash already present for IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - continue; - } + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("create L3-VNI hash for Intf %s(%u) L3-VNI %u", + ifp->name, ifp->ifindex, vni); - zvni = zvni_add(vni); - if (!zvni) { - zlog_err( - "Failed to add VNI hash, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return; - } + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + zlog_err( + "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return; + } - zvni->local_vtep_ip = vxl->vtep_ip; - zvni->vxlan_if = ifp; + /* associate with vxlan_if */ + zl3vni->vxlan_if = ifp; - /* Inform BGP if interface is up and mapped to bridge. */ - if (if_is_operative(ifp) && zif->brslave_info.br_if) - zvni_send_add_to_client(zvni); + /* we need to associate with SVI. + * we can associate with svi-if only after association + * with vxlan-intf is complete */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + + } else { + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; + struct interface *vlan_if = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %s", + ifp->name, ifp->ifindex, vni, + inet_ntoa(vxl->vtep_ip)); + + /* VNI hash entry is not expected to exist. */ + zvni = zvni_lookup(vni); + if (zvni) { + zlog_err( + "VNI hash already present for IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); + continue; + } + + zvni = zvni_add(vni); + if (!zvni) { + zlog_err( + "Failed to add VNI hash, IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); + return; + } + + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->vxlan_if = ifp; + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zvni->vrf_id = vlan_if->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); + if (zl3vni) + listnode_add_sort(zl3vni->l2vnis, zvni); + } + + + /* Inform BGP if intf is up and mapped to bridge. */ + if (if_is_operative(ifp) && zif->brslave_info.br_if) + zvni_send_add_to_client(zvni); + } } } @@ -2351,12 +2680,18 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) */ static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf) { - zebra_vni_t *zvni; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; zvni = (zebra_vni_t *)backet->data; if (!zvni) return; + /* remove from l3-vni list */ + zl3vni = zl3vni_from_vrf(zvni->vrf_id); + if (zl3vni) + listnode_delete(zl3vni->l2vnis, zvni); + /* Free up all neighbors and MACs, if any. */ zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); @@ -2368,109 +2703,993 @@ static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf) zvni_del(zvni); } +/* + * Look up MAC hash entry. + */ +/*static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac) +{ + zebra_mac_t tmp; + zebra_mac_t *pmac; + + memset(&tmp, 0, sizeof(tmp)); + memcpy(&tmp.macaddr, rmac, ETH_ALEN); + pmac = hash_lookup(zl3vni->rmac_table, &tmp); -/* Public functions */ + return pmac; +}*/ /* - * Display Neighbors for a VNI (VTY command handler). + * Callback to allocate RMAC hash entry. */ -void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni, u_char use_json) +/*static void *zl3vni_rmac_alloc(void *p) { - zebra_vni_t *zvni; - u_int32_t num_neigh; - struct neigh_walk_ctx wctx; - json_object *json = NULL; + const zebra_mac_t *tmp_rmac = p; + zebra_mac_t *zrmac; - if (!is_evpn_enabled()) - return; - zvni = zvni_lookup(vni); - if (!zvni) { - if (use_json) - vty_out(vty, "{}\n"); - else - vty_out(vty, "%% VNI %u does not exist\n", vni); - return; - } - num_neigh = hashcount(zvni->neigh_table); - if (!num_neigh) - return; + zrmac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t)); + *zrmac = *tmp_rmac; - if (use_json) - json = json_object_new_object(); + return ((void *)zrmac); +}*/ - /* Since we have IPv6 addresses to deal with which can vary widely in - * size, we try to be a bit more elegant in display by first computing - * the maximum width. - */ - memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); - wctx.zvni = zvni; - wctx.vty = vty; - wctx.addr_width = 15; - wctx.json = json; - hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); +/* + * Add RMAC entry to l3-vni + */ +/*static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac) +{ + zebra_mac_t tmp_rmac; + zebra_mac_t *zrmac = NULL; - if (!use_json) { - vty_out(vty, - "Number of ARPs (local and remote) known for this VNI: %u\n", - num_neigh); - vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", - "Type", "MAC", "Remote VTEP"); - } else - json_object_int_add(json, "numArpNd", num_neigh); + memset(&tmp_rmac, 0, sizeof(zebra_mac_t)); + memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN); + zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc); + assert(zrmac); - hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } -} + zrmac->neigh_list = list_new(); + zrmac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp; + + return zrmac; +}*/ /* - * Display neighbors across all VNIs (VTY command handler). + * Delete MAC entry. */ -void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, - u_char use_json) +/*static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, + zebra_mac_t *zrmac) { - json_object *json = NULL; - void *args[2]; + zebra_mac_t *tmp_rmac; - if (!is_evpn_enabled()) - return; + list_delete(zrmac->neigh_list); - if (use_json) - json = json_object_new_object(); + tmp_rmac = hash_release(zl3vni->rmac_table, zrmac); + if (tmp_rmac) + XFREE(MTYPE_MAC, tmp_rmac); - args[0] = vty; - args[1] = json; - hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, - void *))zvni_print_neigh_hash_all_vni, - args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } -} + return 0; +}*/ /* - * Display specific neighbor for a VNI, if present (VTY command handler). + * Install remote RMAC into the kernel. */ -void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, - struct zebra_vrf *zvrf, vni_t vni, - struct ipaddr *ip, u_char use_json) +/*static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, + zebra_mac_t *zrmac) { - zebra_vni_t *zvni; - zebra_neigh_t *n; - json_object *json = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; - if (!is_evpn_enabled()) - return; - zvni = zvni_lookup(vni); - if (!zvni) { - if (use_json) + if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) || + !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) + return 0; + + zif = zl3vni->vxlan_if->info; + if (!zif) + return -1; + + vxl = &zif->l2info.vxl; + + return kernel_add_mac(zl3vni->vxlan_if, vxl->access_vlan, + &zrmac->macaddr, + zrmac->fwd_info.r_vtep_ip, 0); +}*/ + +/* + * Uninstall remote RMAC from the kernel. + */ +/*static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, + zebra_mac_t *zrmac) +{ + char buf[ETHER_ADDR_STRLEN]; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + + if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) || + !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) + return 0; + + if (!zl3vni->vxlan_if) { + zlog_err("RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", + prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), + zl3vni->vni, zl3vni); + return -1; + } + + zif = zl3vni->vxlan_if->info; + if (!zif) + return -1; + + vxl = &zif->l2info.vxl; + + return kernel_del_mac(zl3vni->vxlan_if, vxl->access_vlan, + &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); +}*/ + +/* + * Look up nh hash entry on a l3-vni. + */ +/*static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, + struct ipaddr *ip) +{ + zebra_neigh_t tmp; + zebra_neigh_t *n; + + memset(&tmp, 0, sizeof(tmp)); + memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); + n = hash_lookup(zl3vni->nh_table, &tmp); + + return n; +}*/ + + +/* + * Callback to allocate NH hash entry on L3-VNI. + */ +/*static void *zl3vni_nh_alloc(void *p) +{ + const zebra_neigh_t *tmp_n = p; + zebra_neigh_t *n; + + n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t)); + *n = *tmp_n; + + return ((void *)n); +}*/ + +/* + * Add neighbor entry. + */ +/*static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, + struct ipaddr *ip, + struct ethaddr *mac) +{ + zebra_neigh_t tmp_n; + zebra_neigh_t *n = NULL; + + memset(&tmp_n, 0, sizeof(zebra_neigh_t)); + memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); + n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc); + assert(n); + + memcpy(&n->emac, mac, ETH_ALEN); + + return n; +}*/ + +/* + * Delete neighbor entry. + */ +/*static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, + zebra_neigh_t *n) +{ + zebra_neigh_t *tmp_n; + + tmp_n = hash_release(zl3vni->nh_table, n); + if (tmp_n) + XFREE(MTYPE_NEIGH, tmp_n); + + return 0; +}*/ + +/* + * Install remote nh as neigh into the kernel. + */ +/*static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, + zebra_neigh_t *n) +{ + if (!is_l3vni_oper_up(zl3vni)) + return -1; + + if (!(n->flags & ZEBRA_NEIGH_REMOTE) || + !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) + return 0; + + return kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac); +}*/ + +/* + * Uninstall remote nh from the kernel. + */ +/*static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, + zebra_neigh_t *n) +{ + if (!is_l3vni_oper_up(zl3vni)) + return -1; + + if (!(n->flags & ZEBRA_NEIGH_REMOTE) || + !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) + return 0; + + return kernel_del_neigh(zl3vni->svi_if, &n->ip); +}*/ + +/* + * Hash function for L3 VNI. + */ +static unsigned int l3vni_hash_keymake(void *p) +{ + const zebra_l3vni_t *zl3vni = p; + + return jhash_1word(zl3vni->vni, 0); +} + +/* + * Compare 2 L3 VNI hash entries. + */ +static int l3vni_hash_cmp(const void *p1, const void *p2) +{ + const zebra_l3vni_t *zl3vni1 = p1; + const zebra_l3vni_t *zl3vni2 = p2; + + return (zl3vni1->vni == zl3vni2->vni); +} + +/* + * Callback to allocate L3 VNI hash entry. + */ +static void *zl3vni_alloc(void *p) +{ + zebra_l3vni_t *zl3vni = NULL; + const zebra_l3vni_t *tmp_l3vni = p; + + zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(zebra_l3vni_t)); + zl3vni->vni = tmp_l3vni->vni; + return ((void *)zl3vni); +} + +/* + * Look up L3 VNI hash entry. + */ +static zebra_l3vni_t *zl3vni_lookup(vni_t vni) +{ + struct zebra_ns *zns; + zebra_l3vni_t tmp_l3vni; + zebra_l3vni_t *zl3vni = NULL; + + zns = zebra_ns_lookup(NS_DEFAULT); + assert(zns); + memset(&tmp_l3vni, 0, sizeof(zebra_l3vni_t)); + tmp_l3vni.vni = vni; + zl3vni = hash_lookup(zns->l3vni_table, &tmp_l3vni); + + return zl3vni; +} + +/* + * Add L3 VNI hash entry. + */ +static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id) +{ + zebra_l3vni_t tmp_zl3vni; + struct zebra_ns *zns = NULL; + zebra_l3vni_t *zl3vni = NULL; + + zns = zebra_ns_lookup(NS_DEFAULT); + assert(zns); + + memset(&tmp_zl3vni, 0, sizeof(zebra_l3vni_t)); + tmp_zl3vni.vni = vni; + + zl3vni = hash_get(zns->l3vni_table, &tmp_zl3vni, zl3vni_alloc); + assert(zl3vni); + + zl3vni->vrf_id = vrf_id; + zl3vni->svi_if = NULL; + zl3vni->vxlan_if = NULL; + zl3vni->l2vnis = list_new(); + zl3vni->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp; + + /* Create hash table for remote RMAC */ + zl3vni->rmac_table = + hash_create(mac_hash_keymake, mac_cmp, + "Zebra L3-VNI RMAC-Table"); + + /* Create hash table for neighbors */ + zl3vni->nh_table = hash_create(neigh_hash_keymake, neigh_cmp, + "Zebra L3-VNI next-hop table"); + + return zl3vni; +} + +/* + * Delete L3 VNI hash entry. + */ +static int zl3vni_del(zebra_l3vni_t *zl3vni) +{ + struct zebra_ns *zns; + zebra_l3vni_t *tmp_zl3vni; + + zns = zebra_ns_lookup(NS_DEFAULT); + assert(zns); + + /* free the list of l2vnis */ + list_delete_and_null(&zl3vni->l2vnis); + zl3vni->l2vnis = NULL; + + /* Free the rmac table */ + hash_free(zl3vni->rmac_table); + zl3vni->rmac_table = NULL; + + /* Free the nh table */ + hash_free(zl3vni->nh_table); + zl3vni->nh_table = NULL; + + /* Free the VNI hash entry and allocated memory. */ + tmp_zl3vni = hash_release(zns->l3vni_table, zl3vni); + if (tmp_zl3vni) + XFREE(MTYPE_ZL3VNI, tmp_zl3vni); + + return 0; +} + +static int is_vni_l3(vni_t vni) +{ + zebra_l3vni_t *zl3vni = NULL; + + zl3vni = zl3vni_lookup(vni); + if (zl3vni) + return 1; + return 0; +} + +static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) +{ + struct zebra_ns *zns = NULL; + struct route_node *rn = NULL; + struct interface *ifp = NULL; + + /* loop through all vxlan-interface */ + zns = zebra_ns_lookup(NS_DEFAULT); + for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { + + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + + ifp = (struct interface *)rn->info; + if (!ifp) + continue; + + zif = ifp->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + continue; + + vxl = &zif->l2info.vxl; + if (vxl->vni == zl3vni->vni) + return ifp; + } + + return NULL; +} + +static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) +{ + struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ + struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */ + + if (!zl3vni->vxlan_if) + return NULL; + + zif = zl3vni->vxlan_if->info; + if (!zif) + return NULL; + + vxl = &zif->l2info.vxl; + + return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); +} + +static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id) +{ + struct zebra_vrf *zvrf = NULL; + + zvrf = zebra_vrf_lookup_by_id(vrf_id); + if (!zvrf) + return NULL; + + return zl3vni_lookup(zvrf->l3vni); +} + +/* + * Map SVI and associated bridge to a VNI. This is invoked upon getting + * neighbor notifications, to see if they are of interest. + */ +static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp, + struct interface *br_if) +{ + int found = 0; + vlanid_t vid = 0; + u_char bridge_vlan_aware = 0; + zebra_l3vni_t *zl3vni = NULL; + struct zebra_ns *zns = NULL; + struct route_node *rn = NULL; + struct zebra_if *zif = NULL; + struct interface *tmp_if = NULL; + struct zebra_l2info_bridge *br = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + + if (!br_if) + return NULL; + + /* Make sure the linked interface is a bridge. */ + if (!IS_ZEBRA_IF_BRIDGE(br_if)) + return NULL; + + /* Determine if bridge is VLAN-aware or not */ + zif = br_if->info; + assert(zif); + br = &zif->l2info.br; + bridge_vlan_aware = br->vlan_aware; + if (bridge_vlan_aware) { + struct zebra_l2info_vlan *vl; + + if (!IS_ZEBRA_IF_VLAN(ifp)) + return NULL; + + zif = ifp->info; + assert(zif); + vl = &zif->l2info.vl; + vid = vl->vid; + } + + /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ + /* TODO: Optimize with a hash. */ + zns = zebra_ns_lookup(NS_DEFAULT); + for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { + tmp_if = (struct interface *)rn->info; + if (!tmp_if) + continue; + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + continue; + if (!if_is_operative(tmp_if)) + continue; + vxl = &zif->l2info.vxl; + + if (zif->brslave_info.br_if != br_if) + continue; + + if (!bridge_vlan_aware || vxl->access_vlan == vid) { + found = 1; + break; + } + } + + if (!found) + return NULL; + + zl3vni = zl3vni_lookup(vxl->vni); + return zl3vni; +} + +/* + * Inform BGP about l3-vni. + */ +static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) +{ + struct stream *s = NULL; + struct zserv *client = NULL; + struct ethaddr rmac; + char buf[ETHER_ADDR_STRLEN]; + + client = zebra_find_client(ZEBRA_ROUTE_BGP); + /* BGP may not be running. */ + if (!client) + return 0; + + /* get the rmac */ + memset(&rmac, 0, sizeof(struct ethaddr)); + zl3vni_get_rmac(zl3vni, &rmac); + + s = client->obuf; + stream_reset(s); + + zserv_create_header(s, ZEBRA_L3VNI_ADD, + zl3vni_vrf_id(zl3vni)); + stream_putl(s, zl3vni->vni); + stream_put(s, &rmac, sizeof(struct ethaddr)); + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Send L3_VNI_ADD %u VRF %s RMAC %s to %s", + zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), + prefix_mac2str(&rmac, buf, sizeof(buf)), + zebra_route_string(client->proto)); + + client->l3vniadd_cnt++; + return zebra_server_send_message(client); +} + +/* + * Inform BGP about local l3-VNI deletion. + */ +static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) +{ + struct stream *s = NULL; + struct zserv *client = NULL; + + client = zebra_find_client(ZEBRA_ROUTE_BGP); + /* BGP may not be running. */ + if (!client) + return 0; + + s = client->obuf; + stream_reset(s); + + zserv_create_header(s, ZEBRA_L3VNI_DEL, + zl3vni_vrf_id(zl3vni)); + stream_putl(s, zl3vni->vni); + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", + zl3vni->vni, + vrf_id_to_name(zl3vni_vrf_id(zl3vni)), + zebra_route_string(client->proto)); + + client->l3vnidel_cnt++; + return zebra_server_send_message(client); +} + +static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni) +{ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("L3-VNI %u is UP - send add to BGP and update all neigh enries", + zl3vni->vni); + + /* send l3vni add to BGP */ + zl3vni_send_add_to_client(zl3vni); +} + +static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni) +{ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("L3-VNI %u is Down - send del to BGP and update all neigh enries", + zl3vni->vni); + + /* send l3-vni del to BGP*/ + zl3vni_send_del_to_client(zl3vni); +} + +static void zvni_add_to_l3vni_list(struct hash_backet *backet, + void *ctxt) +{ + zebra_vni_t *zvni = (zebra_vni_t *) backet->data; + zebra_l3vni_t *zl3vni = (zebra_l3vni_t *) ctxt; + + if (zvni->vrf_id == zl3vni_vrf_id(zl3vni)) + listnode_add_sort(zl3vni->l2vnis, zvni); +} + +/* l3vni from zvni */ +static vni_t zvni_get_l3vni(zebra_vni_t *zvni) +{ + zebra_l3vni_t *zl3vni = NULL; + + zl3vni = zl3vni_from_vrf(zvni->vrf_id); + if (!zl3vni || !is_l3vni_oper_up(zl3vni)) + return 0; + + return zl3vni->vni; +} + +/* rmac from l3vni */ +static void zvni_get_rmac(zebra_vni_t *zvni, + struct ethaddr *rmac) +{ + zebra_l3vni_t *zl3vni = NULL; + + zl3vni = zl3vni_from_vrf(zvni->vrf_id); + if (!zl3vni || !is_l3vni_oper_up(zl3vni)) + return; + + if (zl3vni->svi_if) + memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN); +} + +/* + * handle transition of vni from l2 to l3 and vice versa + */ +static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, + vni_t vni, int add) +{ + zebra_vni_t *zvni = NULL; + + /* There is a possibility that VNI notification was already received + * from kernel and we programmed it as L2-VNI + * In such a case we need to delete this L2-VNI first, so + * that it can be reprogrammed as L3-VNI in the system. It is also + * possible that the vrf-vni mapping is removed from FRR while the vxlan + * interface is still present in kernel. In this case to keep it + * symmetric, we will delete the l3-vni and reprogram it as l2-vni */ + if (add) { + /* Locate hash entry */ + zvni = zvni_lookup(vni); + if (!zvni) + return 0; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Del L2-VNI %u - transition to L3-VNI", + vni); + + /* Delete VNI from BGP. */ + zvni_send_del_to_client(zvni->vni); + + /* Free up all neighbors and MAC, if any. */ + zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH); + zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC); + + /* Free up all remote VTEPs, if any. */ + zvni_vtep_del_all(zvni, 0); + + /* Delete the hash entry. */ + if (zvni_del(zvni)) { + zlog_err("Failed to del VNI hash %p, VNI %u", + zvni, zvni->vni); + return -1; + } + } else { + /* TODO_MITESH: This needs to be thought through. We don't have + * enough information at this point to reprogram the vni as + * l2-vni. One way is to store the required info in l3-vni and + * used it solely for this purpose */ + } + + return 0; +} + +/* Public functions */ + +void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, + vni_t l3vni, + u_char use_json) +{ + zebra_l3vni_t *zl3vni; + u_int32_t num_rmacs; + struct rmac_walk_ctx wctx; + json_object *json = NULL; + json_object *json_rmac = NULL; + + if (!is_evpn_enabled()) + return; + + zl3vni = zl3vni_lookup(l3vni); + if (!zl3vni) { + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); + return; + } + num_rmacs = hashcount(zl3vni->rmac_table); + if (!num_rmacs) + return; + + if (use_json) { + json = json_object_new_object(); + json_rmac = json_object_new_array(); + } + + memset(&wctx, 0, sizeof(struct rmac_walk_ctx)); + wctx.vty = vty; + wctx.json = json_rmac; + + if (!use_json) { + vty_out(vty, + "Number of Remote RMACs known for this VNI: %u\n", + num_rmacs); + vty_out(vty, "%-17s %-21s %-6s\n", "MAC", + "Remote VTEP", "Refcnt"); + } else + json_object_int_add(json, "numRmacs", num_rmacs); + + hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx); + + if (use_json) { + json_object_object_add(json, "rmacs", json_rmac); + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, + u_char use_json) +{ + struct zebra_ns *zns = NULL; + struct rmac_walk_ctx wctx; + json_object *json = NULL; + + if (!is_evpn_enabled()) { + if (use_json) + vty_out(vty, "{}\n"); + return; + } + + zns = zebra_ns_lookup(NS_DEFAULT); + if (!zns) + return; + + if (use_json) + json = json_object_new_object(); + + memset(&wctx, 0, sizeof(struct rmac_walk_ctx)); + wctx.vty = vty; + wctx.json = json; + + hash_iterate(zns->l3vni_table, zl3vni_print_rmac_hash_all_vni, &wctx); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +void zebra_vxlan_print_nh_l3vni(struct vty *vty, + vni_t l3vni, + u_char use_json) +{ + u_int32_t num_nh; + struct nh_walk_ctx *wctx; + json_object *json = NULL; + json_object *json_nh = NULL; + zebra_l3vni_t *zl3vni = NULL; + + if (!is_evpn_enabled()) + return; + + zl3vni = zl3vni_lookup(l3vni); + if (!zl3vni) { + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); + return; + } + + num_nh = hashcount(zl3vni->nh_table); + if (!num_nh) + return; + + if (use_json) { + json = json_object_new_object(); + json_nh = json_object_new_array(); + } + + wctx->vty = vty; + wctx->json = json_nh; + + if (!use_json) { + vty_out(vty, + "Number of NH Neighbors known for this VNI: %u\n", + num_nh); + vty_out(vty, "%15s %-17s %6s\n", "IP", + "RMAC", "Refcnt"); + } else + json_object_int_add(json, "numNh", num_nh); + + hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); + + if (use_json) { + json_object_object_add(json, "next-hop-neighbors", json_nh); + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, + u_char use_json) +{ + return; +} + +/* + * Display L3 VNI information (VTY command handler). + */ +void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, u_char use_json) +{ + void *args[2]; + json_object *json = NULL; + zebra_l3vni_t *zl3vni = NULL; + + args[0] = vty; + args[1] = json; + + if (!is_evpn_enabled()) + return; + + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + + if (use_json) + json = json_object_new_object(); + + zl3vni_print(zl3vni, (void *)args); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +/* + * Display L3 VNI hash table (VTY command handler). + */ +void zebra_vxlan_print_l3vnis(struct vty *vty, u_char use_json) +{ + u_int32_t num_vnis; + void *args[2]; + json_object *json = NULL; + struct zebra_ns *zns = NULL; + + args[0] = vty; + args[1] = json; + + if (!is_evpn_enabled()) + return; + + zns = zebra_ns_lookup(NS_DEFAULT); + assert(zns); + + num_vnis = hashcount(zns->l3vni_table); + if (!num_vnis) { + if (use_json) + vty_out(vty, "{}\n"); + return; + } + + if (use_json) { + json = json_object_new_object(); + json_object_int_add(json, "numVnis", num_vnis); + } else { + vty_out(vty, "Number of L3 VNIs: %u\n", num_vnis); + vty_out(vty, "%-10s %-20s %-20s %-5s %-37s %-18s\n", "VNI", + "Vx-intf", "L3-SVI", "State", "VRF", "Rmac"); + } + + hash_iterate(zns->l3vni_table, + (void (*)(struct hash_backet *, void *))zl3vni_print_hash, + args); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +/* + * Display Neighbors for a VNI (VTY command handler). + */ +void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, u_char use_json) +{ + zebra_vni_t *zvni; + u_int32_t num_neigh; + struct neigh_walk_ctx wctx; + json_object *json = NULL; + + if (!is_evpn_enabled()) + return; + zvni = zvni_lookup(vni); + if (!zvni) { + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + num_neigh = hashcount(zvni->neigh_table); + if (!num_neigh) + return; + + if (use_json) + json = json_object_new_object(); + + /* Since we have IPv6 addresses to deal with which can vary widely in + * size, we try to be a bit more elegant in display by first computing + * the maximum width. + */ + memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); + wctx.zvni = zvni; + wctx.vty = vty; + wctx.addr_width = 15; + wctx.json = json; + hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); + + if (!use_json) { + vty_out(vty, + "Number of ARPs (local and remote) known for this VNI: %u\n", + num_neigh); + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", + "Type", "MAC", "Remote VTEP"); + } else + json_object_int_add(json, "numArpNd", num_neigh); + + hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +/* + * Display neighbors across all VNIs (VTY command handler). + */ +void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, + u_char use_json) +{ + json_object *json = NULL; + void *args[2]; + + if (!is_evpn_enabled()) + return; + + if (use_json) + json = json_object_new_object(); + + args[0] = vty; + args[1] = json; + hash_iterate(zvrf->vni_table, + (void (*)(struct hash_backet *, + void *))zvni_print_neigh_hash_all_vni, + args); + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +/* + * Display specific neighbor for a VNI, if present (VTY command handler). + */ +void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, + struct zebra_vrf *zvrf, vni_t vni, + struct ipaddr *ip, u_char use_json) +{ + zebra_vni_t *zvni; + zebra_neigh_t *n; + json_object *json = NULL; + + if (!is_evpn_enabled()) + return; + zvni = zvni_lookup(vni); + if (!zvni) { + if (use_json) vty_out(vty, "{}\n"); else vty_out(vty, "%% VNI %u does not exist\n", vni); @@ -2789,9 +4008,9 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, vty_out(vty, "Advertise gateway mac-ip: %s\n", zvrf->advertise_gw_macip ? "Yes" : "No"); vty_out(vty, "Number of VNIs: %u\n", num_vnis); - vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", + vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s %-37s\n", "VNI", "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", - "# Remote VTEPs"); + "# Remote VTEPs", "VRF"); } args[0] = vty; args[1] = json; @@ -2816,16 +4035,21 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, int zebra_vxlan_local_neigh_del(struct interface *ifp, struct interface *link_if, struct ipaddr *ip) { - zebra_vni_t *zvni; - zebra_neigh_t *n; + vni_t l3vni = 0; + struct ethaddr rmac; char buf[INET6_ADDRSTRLEN]; + char buf1[INET6_ADDRSTRLEN]; char buf2[ETHER_ADDR_STRLEN]; - zebra_mac_t *zmac; + zebra_neigh_t *n = NULL; + zebra_vni_t *zvni = NULL; + zebra_mac_t *zmac = NULL; + + memset(&rmac, 0, sizeof(struct ethaddr)); /* We are only interested in neighbors on an SVI that resides on top * of a VxLAN bridge. */ - zvni = zvni_map_svi(ifp, link_if); + zvni = zvni_from_svi(ifp, link_if); if (!zvni) return 0; if (!zvni->vxlan_if) { @@ -2835,10 +4059,17 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, return -1; } + /* get the l3-vni */ + l3vni = zvni_get_l3vni(zvni); + + /* get the rmac */ + zvni_get_rmac(zvni, &rmac); + if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Del neighbor %s intf %s(%u) -> VNI %u", + zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u L3-VNI %u RMAC %s", ipaddr2str(ip, buf, sizeof(buf)), - ifp->name, ifp->ifindex, zvni->vni); + ifp->name, ifp->ifindex, zvni->vni, + l3vni, prefix_mac2str(&rmac, buf1, sizeof(buf1))); /* If entry doesn't exist, nothing to do. */ n = zvni_neigh_lookup(zvni, ip); @@ -2891,27 +4122,38 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, struct ethaddr *macaddr, u_int16_t state, u_char ext_learned) { - zebra_vni_t *zvni; - zebra_neigh_t *n; - zebra_mac_t *zmac, *old_zmac; + vni_t l3vni = 0; + struct ethaddr rmac; char buf[ETHER_ADDR_STRLEN]; + char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; + zebra_vni_t *zvni = NULL; + zebra_neigh_t *n = NULL; + zebra_mac_t *zmac = NULL, *old_zmac = NULL; + + memset(&rmac, 0, sizeof(struct ethaddr)); /* We are only interested in neighbors on an SVI that resides on top * of a VxLAN bridge. */ - zvni = zvni_map_svi(ifp, link_if); + zvni = zvni_from_svi(ifp, link_if); if (!zvni) return 0; + /* get the l3-vni */ + l3vni = zvni_get_l3vni(zvni); + + /* get the rmac */ + zvni_get_rmac(zvni, &rmac); + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x " - "%s-> VNI %u", + "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s-> L2-VNI %u L3-VNI %u RMAC %s", ipaddr2str(ip, buf2, sizeof(buf2)), prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, state, ext_learned ? "ext-learned " : "", - zvni->vni); + zvni->vni, l3vni, + prefix_mac2str(&rmac, buf1, sizeof(buf1))); /* create a dummy MAC if the MAC is not already present */ zmac = zvni_mac_lookup(zvni, macaddr); @@ -3015,12 +4257,15 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* Inform BGP. */ if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("neigh %s (MAC %s) is now ACTIVE on VNI %u", + zlog_debug("neigh %s (MAC %s) is now ACTIVE on L2-VNI %u L3-VNI %u with RMAC %s", ipaddr2str(ip, buf2, sizeof(buf2)), prefix_mac2str(macaddr, buf, sizeof(buf)), - zvni->vni); + zvni->vni, + l3vni, + prefix_mac2str(&rmac, buf1, sizeof(buf1))); ZEBRA_NEIGH_SET_ACTIVE(n); + return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0); } @@ -3034,6 +4279,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, struct stream *s; vni_t vni; struct ethaddr macaddr; + struct ethaddr rmac; struct ipaddr ip; struct in_addr vtep_ip; zebra_vni_t *zvni; @@ -3042,9 +4288,15 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, u_short l = 0, ipa_len; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + char buf3[INET6_ADDRSTRLEN]; struct interface *ifp = NULL; struct zebra_if *zif = NULL; + memset(&macaddr, 0, sizeof(struct ethaddr)); + memset(&rmac, 0, sizeof(struct ethaddr)); + memset(&ip, 0, sizeof(struct ipaddr)); + memset(&vtep_ip, 0, sizeof(struct in_addr)); + s = client->ibuf; while (l < length) { @@ -3066,13 +4318,16 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, l += 4 + ETH_ALEN + 4 + ipa_len; STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); l += IPV4_MAX_BYTELEN; + stream_get(&rmac.octet, s, ETH_ALEN); + l += ETH_ALEN; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Recv MACIP Del MAC %s IP %s VNI %u Remote VTEP %s from %s", + "Recv MACIP Del MAC %s IP %s VNI %u Remote VTEP %s RMAC %s from %s", prefix_mac2str(&macaddr, buf, sizeof(buf)), ipaddr2str(&ip, buf1, sizeof(buf1)), vni, inet_ntoa(vtep_ip), + prefix_mac2str(&rmac, buf3, sizeof(buf3)), zebra_route_string(client->proto)); /* Locate VNI hash entry - expected to exist. */ @@ -3175,6 +4430,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, struct stream *s; vni_t vni; struct ethaddr macaddr; + struct ethaddr rmac; struct ipaddr ip; struct in_addr vtep_ip; zebra_vni_t *zvni; @@ -3185,10 +4441,16 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, int update_mac = 0, update_neigh = 0; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + char buf2[ETHER_ADDR_STRLEN]; u_char sticky; struct interface *ifp = NULL; struct zebra_if *zif = NULL; + memset(&macaddr, 0, sizeof(struct ethaddr)); + memset(&rmac, 0, sizeof(struct ethaddr)); + memset(&ip, 0, sizeof(struct ipaddr)); + memset(&vtep_ip, 0, sizeof(struct in_addr)); + if (!EVPN_ENABLED(zvrf)) { zlog_warn("%s: EVPN Not turned on yet we have received a remote_macip add zapi callback", __PRETTY_FUNCTION__); @@ -3222,13 +4484,18 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, STREAM_GETC(s, sticky); l++; + /* Get router mac */ + stream_get(&rmac.octet, s, ETH_ALEN); + l += ETH_ALEN; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s", + "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s RMAC %s from %s", sticky ? "sticky " : "", prefix_mac2str(&macaddr, buf, sizeof(buf)), ipaddr2str(&ip, buf1, sizeof(buf1)), vni, inet_ntoa(vtep_ip), + prefix_mac2str(&rmac, buf2, sizeof(buf2)), zebra_route_string(client->proto)); /* Locate VNI hash entry - expected to exist. */ @@ -3898,14 +5165,14 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, svi_if_link = if_lookup_by_index_per_ns( zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex); - zvni = zvni_map_svi(svi_if, svi_if_link); + zvni = zvni_from_svi(svi_if, svi_if_link); } } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) { /* * If it is a vlan unaware bridge then svi is the bridge * itself */ - zvni = zvni_map_svi(svi_if, svi_if); + zvni = zvni_from_svi(svi_if, svi_if); } } else if (IS_ZEBRA_IF_VLAN(ifp)) { struct zebra_if *svi_if_zif = @@ -3917,9 +5184,9 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, svi_if_link = if_lookup_by_index_per_ns( zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex); if (svi_if_zif && svi_if_link) - zvni = zvni_map_svi(ifp, svi_if_link); + zvni = zvni_from_svi(ifp, svi_if_link); } else if (IS_ZEBRA_IF_BRIDGE(ifp)) { - zvni = zvni_map_svi(ifp, ifp); + zvni = zvni_from_svi(ifp, ifp); } if (!zvni) @@ -3958,56 +5225,108 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, } /* - * Handle SVI interface going down. At this point, this is a NOP since - * the kernel deletes the neighbor entries on this SVI (if any). + * Handle SVI interface going down. + * SVI can be associated to either L3-VNI or L2-VNI. + * For L2-VNI: At this point, this is a NOP since + * the kernel deletes the neighbor entries on this SVI (if any). + * We only need to update the vrf corresponding to zvni. + * For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete + * from bgp */ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) { + zebra_l3vni_t *zl3vni = NULL; + + zl3vni = zl3vni_from_svi(ifp, link_if); + if (zl3vni) { + + /* process l3-vni down */ + zebra_vxlan_process_l3vni_oper_down(zl3vni); + + /* remove association with svi-if */ + zl3vni->svi_if = NULL; + } else { + zebra_vni_t *zvni = NULL; + + /* since we dont have svi corresponding to zvni, we associate it + * to default vrf. Note: the corresponding neigh entries on the + * SVI would have already been deleted */ + zvni = zvni_from_svi(ifp, link_if); + if (zvni) { + zvni->vrf_id = VRF_DEFAULT; + + /* update the tenant vrf in BGP */ + zvni_send_add_to_client(zvni); + } + } return 0; } /* - * Handle SVI interface coming up. This may or may not be of interest, - * but if this is a SVI on a VxLAN bridge, we need to install any remote - * neighbor entries (which will be used for EVPN ARP suppression). + * Handle SVI interface coming up. + * SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni + * vxlan intf). + * For L2-VNI: we need to install any remote neighbors entried (used for + * apr-suppression) + * For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI */ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) { - zebra_vni_t *zvni; - struct neigh_walk_ctx n_wctx; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; - zvni = zvni_map_svi(ifp, link_if); - if (!zvni) - return 0; + zl3vni = zl3vni_from_svi(ifp, link_if); + if (zl3vni) { - if (!zvni->vxlan_if) { - zlog_err("VNI %u hash %p doesn't have intf upon SVI up", - zvni->vni, zvni); - return -1; - } + /* associate with svi */ + zl3vni->svi_if = ifp; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("SVI %s(%u) VNI %u is UP, installing neighbors", - ifp->name, ifp->ifindex, zvni->vni); + /* process oper-up */ + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } else { + + /* process SVI up for l2-vni */ + struct neigh_walk_ctx n_wctx; + + zvni = zvni_from_svi(ifp, link_if); + if (!zvni) + return 0; + + if (!zvni->vxlan_if) { + zlog_err("VNI %u hash %p doesn't have intf upon SVI up", + zvni->vni, zvni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("SVI %s(%u) VNI %u VRF %s is UP, installing neighbors", + ifp->name, ifp->ifindex, zvni->vni, + vrf_id_to_name(ifp->vrf_id)); - /* Install any remote neighbors for this VNI. */ - memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); - n_wctx.zvni = zvni; - hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, &n_wctx); + /* update the vrf information for l2-vni and inform bgp */ + zvni->vrf_id = ifp->vrf_id; + zvni_send_add_to_client(zvni); + + /* Install any remote neighbors for this VNI. */ + memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); + n_wctx.zvni = zvni; + hash_iterate(zvni->neigh_table, + zvni_install_neigh_hash, + &n_wctx); + } return 0; } /* - * Handle VxLAN interface down - update BGP if required, and do - * internal cleanup. + * Handle VxLAN interface down */ int zebra_vxlan_if_down(struct interface *ifp) { - struct zebra_if *zif; - zebra_vni_t *zvni; - struct zebra_l2info_vxlan *vxl; vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -4018,31 +5337,55 @@ int zebra_vxlan_if_down(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) VNI %u is DOWN", - ifp->name, ifp->ifindex, vni); - /* Locate hash entry; it is expected to exist. */ - zvni = zvni_lookup(vni); - if (!zvni) { - zlog_err( - "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } + if (is_vni_l3(vni)) { + + /* process-if-down for l3-vni */ + zebra_l3vni_t *zl3vni = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", + ifp->name, ifp->ifindex, vni); + + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + zlog_err( + "Failed to locate L3-VNI hash at DOWN, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + + zebra_vxlan_process_l3vni_oper_down(zl3vni); + + } else { + /* process if-down for l2-vni */ + zebra_vni_t *zvni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", + ifp->name, ifp->ifindex, vni); - assert(zvni->vxlan_if == ifp); + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup(vni); + if (!zvni) { + zlog_err( + "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } - /* Delete this VNI from BGP. */ - zvni_send_del_to_client(zvni->vni); + assert(zvni->vxlan_if == ifp); - /* Free up all neighbors and MACs, if any. */ - zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); - zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); + /* Delete this VNI from BGP. */ + zvni_send_del_to_client(zvni->vni); - /* Free up all remote VTEPs, if any. */ - zvni_vtep_del_all(zvni, 1); + /* Free up all neighbors and MACs, if any. */ + zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); + zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); + /* Free up all remote VTEPs, if any. */ + zvni_vtep_del_all(zvni, 1); + } return 0; } @@ -4051,10 +5394,9 @@ int zebra_vxlan_if_down(struct interface *ifp) */ int zebra_vxlan_if_up(struct interface *ifp) { - struct zebra_if *zif; - zebra_vni_t *zvni; - struct zebra_l2info_vxlan *vxl; vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -4065,26 +5407,65 @@ int zebra_vxlan_if_up(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) VNI %u is UP", - ifp->name, ifp->ifindex, vni); + if (is_vni_l3(vni)) { - /* Locate hash entry; it is expected to exist. */ - zvni = zvni_lookup(vni); - if (!zvni) { - zlog_err( - "Failed to locate VNI hash at UP, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } + /* Handle L3-VNI add */ + zebra_l3vni_t *zl3vni = NULL; - assert(zvni->vxlan_if == ifp); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L3-VNI %u is UP", + ifp->name, ifp->ifindex, vni); - /* If part of a bridge, inform BGP about this VNI. */ - /* Also, read and populate local MACs and neighbors. */ - if (zif->brslave_info.br_if) { - zvni_send_add_to_client(zvni); - zvni_read_mac_neigh(zvni, ifp); + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + zlog_err( + "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + + /* we need to associate with SVI, if any, we can associate with + * svi-if only after association with vxlan-intf is complete */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } else { + /* Handle L2-VNI add */ + + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; + struct interface *vlan_if = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L2-VNI %u is UP", + ifp->name, ifp->ifindex, vni); + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup(vni); + if (!zvni) { + zlog_err( + "Failed to locate VNI hash at UP, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + + assert(zvni->vxlan_if == ifp); + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zvni->vrf_id = vlan_if->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); + if (zl3vni) + listnode_add_sort(zl3vni->l2vnis, zvni); + } + + /* If part of a bridge, inform BGP about this VNI. */ + /* Also, read and populate local MACs and neighbors. */ + if (zif->brslave_info.br_if) { + zvni_send_add_to_client(zvni); + zvni_read_mac_neigh(zvni, ifp); + } } return 0; @@ -4096,10 +5477,9 @@ int zebra_vxlan_if_up(struct interface *ifp) */ int zebra_vxlan_if_del(struct interface *ifp) { - struct zebra_if *zif; - zebra_vni_t *zvni; - struct zebra_l2info_vxlan *vxl; vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -4110,34 +5490,68 @@ int zebra_vxlan_if_del(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Del VNI %u intf %s(%u)", - vni, ifp->name, ifp->ifindex); + if (is_vni_l3(vni)) { - /* Locate hash entry; it is expected to exist. */ - zvni = zvni_lookup(vni); - if (!zvni) { - zlog_err( - "Failed to locate VNI hash at del, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return 0; - } + /* process if-del for l3-vni */ + zebra_l3vni_t *zl3vni = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Del L3-VNI %u intf %s(%u)", + vni, ifp->name, ifp->ifindex); - /* Delete VNI from BGP. */ - zvni_send_del_to_client(zvni->vni); + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + zlog_err( + "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return 0; + } - /* Free up all neighbors and MAC, if any. */ - zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH); - zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC); + /* process oper-down for l3-vni */ + zebra_vxlan_process_l3vni_oper_down(zl3vni); - /* Free up all remote VTEPs, if any. */ - zvni_vtep_del_all(zvni, 0); + /* remove the association with vxlan_if */ + zl3vni->vxlan_if = NULL; + } else { - /* Delete the hash entry. */ - if (zvni_del(zvni)) { - zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u", - zvni, ifp->name, ifp->ifindex, zvni->vni); - return -1; + /* process if-del for l2-vni*/ + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Del L2-VNI %u intf %s(%u)", + vni, ifp->name, ifp->ifindex); + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup(vni); + if (!zvni) { + zlog_err( + "Failed to locate VNI hash at del, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return 0; + } + + /* remove from l3-vni list */ + zl3vni = zl3vni_from_vrf(zvni->vrf_id); + if (zl3vni) + listnode_delete(zl3vni->l2vnis, zvni); + + /* Delete VNI from BGP. */ + zvni_send_del_to_client(zvni->vni); + + /* Free up all neighbors and MAC, if any. */ + zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH); + zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC); + + /* Free up all remote VTEPs, if any. */ + zvni_vtep_del_all(zvni, 0); + + /* Delete the hash entry. */ + if (zvni_del(zvni)) { + zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u", + zvni, ifp->name, ifp->ifindex, zvni->vni); + return -1; + } } return 0; @@ -4148,10 +5562,9 @@ int zebra_vxlan_if_del(struct interface *ifp) */ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) { - struct zebra_if *zif; - zebra_vni_t *zvni; - struct zebra_l2info_vxlan *vxl; vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -4162,79 +5575,128 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) vxl = &zif->l2info.vxl; vni = vxl->vni; - /* Update VNI hash. */ - zvni = zvni_lookup(vni); - if (!zvni) { - zlog_err( - "Failed to find VNI hash on update, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } + if (is_vni_l3(vni)) { + zebra_l3vni_t *zl3vni = NULL; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Update VNI %u intf %s(%u) VLAN %u local IP %s " - "master %u chg 0x%x", - vni, ifp->name, ifp->ifindex, - vxl->access_vlan, inet_ntoa(vxl->vtep_ip), - zif->brslave_info.bridge_ifindex, chgflags); - - /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) - && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { - /* Delete from client, remove all remote VTEPs */ - /* Also, free up all MACs and neighbors. */ - zvni_send_del_to_client(zvni->vni); - zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); - zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); - zvni_vtep_del_all(zvni, 1); - return 0; - } + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + zlog_err( + "Failed to find L3-VNI hash on update, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } - /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { - /* Remove all existing local neighbors and MACs for this VNI - * (including from BGP) - */ - zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC); - zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC); - } + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Update L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x", + vni, ifp->name, ifp->ifindex, + vxl->access_vlan, inet_ntoa(vxl->vtep_ip), + zif->brslave_info.bridge_ifindex, chgflags); + + /* Removed from bridge? Cleanup and return */ + if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + return 0; + } + + /* access-vlan change - process oper down, associate with new + * svi_if and then process oper up again */ + if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (if_is_operative(ifp)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zl3vni->svi_if = NULL; + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up( + zl3vni); + } + } - zvni->local_vtep_ip = vxl->vtep_ip; - zvni->vxlan_if = ifp; + /* if we have a valid new master, process l3-vni oper up */ + if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } + } else { + zebra_vni_t *zvni = NULL; - /* Take further actions needed. Note that if we are here, there is a - * change of interest. - */ - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - return 0; + /* Update VNI hash. */ + zvni = zvni_lookup(vni); + if (!zvni) { + zlog_err( + "Failed to find L2-VNI hash on update, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } - /* Inform BGP, if there is a change of interest. */ - if (chgflags - & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) - zvni_send_add_to_client(zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Update L2-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x", + vni, ifp->name, ifp->ifindex, + vxl->access_vlan, inet_ntoa(vxl->vtep_ip), + zif->brslave_info.bridge_ifindex, chgflags); + + /* Removed from bridge? Cleanup and return */ + if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { + /* Delete from client, remove all remote VTEPs */ + /* Also, free up all MACs and neighbors. */ + zvni_send_del_to_client(zvni->vni); + zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); + zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); + zvni_vtep_del_all(zvni, 1); + return 0; + } - /* If there is a valid new master or a VLAN mapping change, read and - * populate local MACs and neighbors. Also, reinstall any remote MACs - * and neighbors for this VNI (based on new VLAN). - */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) - zvni_read_mac_neigh(zvni, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { - struct mac_walk_ctx m_wctx; - struct neigh_walk_ctx n_wctx; + /* Handle other changes. */ + if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + /* Remove all existing local neigh and MACs for this VNI + * (including from BGP) + */ + zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC); + zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC); + } - zvni_read_mac_neigh(zvni, ifp); + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->vxlan_if = ifp; - memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); - m_wctx.zvni = zvni; - hash_iterate(zvni->mac_table, zvni_install_mac_hash, &m_wctx); + /* Take further actions needed. + * Note that if we are here, there is a change of interest. + */ + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return 0; - memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); - n_wctx.zvni = zvni; - hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, - &n_wctx); + /* Inform BGP, if there is a change of interest. */ + if (chgflags + & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) + zvni_send_add_to_client(zvni); + + /* If there is a valid new master or a VLAN mapping change, + * read and populate local MACs and neighbors. + * Also, reinstall any remote MACs and neighbors + * for this VNI (based on new VLAN). + */ + if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + zvni_read_mac_neigh(zvni, ifp); + else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + struct mac_walk_ctx m_wctx; + struct neigh_walk_ctx n_wctx; + + zvni_read_mac_neigh(zvni, ifp); + + memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); + m_wctx.zvni = zvni; + hash_iterate(zvni->mac_table, + zvni_install_mac_hash, + &m_wctx); + + memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); + n_wctx.zvni = zvni; + hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, + &n_wctx); + } } return 0; @@ -4245,10 +5707,9 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) */ int zebra_vxlan_if_add(struct interface *ifp) { - struct zebra_if *zif; - zebra_vni_t *zvni; - struct zebra_l2info_vxlan *vxl; vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -4259,37 +5720,186 @@ int zebra_vxlan_if_add(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Add VNI %u intf %s(%u) VLAN %u local IP %s master %u", - vni, ifp->name, ifp->ifindex, - vxl->access_vlan, inet_ntoa(vxl->vtep_ip), - zif->brslave_info.bridge_ifindex); + if (is_vni_l3(vni)) { - /* Create or update VNI hash. */ - zvni = zvni_lookup(vni); - if (!zvni) { - zvni = zvni_add(vni); - if (!zvni) { + /* process if-add for l3-vni*/ + zebra_l3vni_t *zl3vni = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Add L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u", + vni, ifp->name, ifp->ifindex, + vxl->access_vlan, inet_ntoa(vxl->vtep_ip), + zif->brslave_info.bridge_ifindex); + + /* + * we expect the l3-vni has entry to be present here. + * The only place l3-vni is created in zebra is vrf-vni mapping + * command. This might change when we have the switchd support + * for l3-vxlan interface. + */ + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { zlog_err( - "Failed to add VNI hash, IF %s(%u) VNI %u", + "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u", ifp->name, ifp->ifindex, vni); + return 0; + } + + /* associate with vxlan_if */ + zl3vni->vxlan_if = ifp; + + /* Associate with SVI, if any. We can associate with svi-if only + * after association with vxlan_if is complete */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } else { + + /* process if-add for l2-vni */ + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; + struct interface *vlan_if = NULL; + + /* Create or update VNI hash. */ + zvni = zvni_lookup(vni); + if (!zvni) { + zvni = zvni_add(vni); + if (!zvni) { + zlog_err( + "Failed to add VNI hash, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + } + + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->vxlan_if = ifp; + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zvni->vrf_id = vlan_if->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); + if (zl3vni) + listnode_add_sort(zl3vni->l2vnis, zvni); + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s master %u", + vni, + vlan_if ? vrf_id_to_name(vlan_if->vrf_id) : + "Default", + ifp->name, ifp->ifindex, + vxl->access_vlan, inet_ntoa(vxl->vtep_ip), + zif->brslave_info.bridge_ifindex); + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return 0; + + /* Inform BGP */ + zvni_send_add_to_client(zvni); + + /* Read and populate local MACs and neighbors */ + zvni_read_mac_neigh(zvni, ifp); + } + + return 0; +} + +int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, + vni_t vni, char *err, + int add) +{ + zebra_l3vni_t *zl3vni = NULL; + struct zebra_vrf *zvrf_default = NULL; + + zvrf_default = zebra_vrf_lookup_by_id(VRF_DEFAULT); + if (!zvrf_default) + return -1; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("vrf %s vni %u %s", + zvrf_name(zvrf), + vni, + add ? "ADD" : "DEL"); + + if (add) { + + zebra_vxlan_handle_vni_transition(zvrf, vni, add); + + /* check if the vni is already present under zvrf */ + if (zvrf->l3vni) { + snprintf(err, ERR_STR_SZ, + "VNI is already configured under the vrf"); + return -1; + } + + /* check if this VNI is already present in the system */ + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + snprintf(err, ERR_STR_SZ, + "VNI is already configured as L3-VNI"); + return -1; + } + + /* add the L3-VNI to the global table */ + zl3vni = zl3vni_add(vni, zvrf_id(zvrf)); + if (!zl3vni) { + snprintf(err, ERR_STR_SZ, + "Could not add L3-VNI"); + return -1; + } + + /* associate the vrf with vni */ + zvrf->l3vni = vni; + + /* associate with vxlan-intf; + * we need to associate with the vxlan-intf first */ + zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni); + + /* associate with corresponding SVI interface, we can associate + * with svi-if only after vxlan interface association is + * complete */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + + /* formulate l2vni list */ + hash_iterate(zvrf_default->vni_table, + zvni_add_to_l3vni_list, zl3vni); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + + } else { + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + snprintf(err, ERR_STR_SZ, "VNI doesn't exist"); return -1; } + + zebra_vxlan_process_l3vni_oper_down(zl3vni); + + zvrf->l3vni = 0; + zl3vni_del(zl3vni); + + zebra_vxlan_handle_vni_transition(zvrf, vni, add); } + return 0; +} - zvni->local_vtep_ip = vxl->vtep_ip; - zvni->vxlan_if = ifp; +int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) +{ + zebra_l3vni_t *zl3vni = NULL; - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + zl3vni = zl3vni_from_vrf(zvrf_id(zvrf)); + if (!zl3vni) return 0; - /* Inform BGP */ - zvni_send_add_to_client(zvni); - - /* Read and populate local MACs and neighbors */ - zvni_read_mac_neigh(zvni, ifp); + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zl3vni_del(zl3vni); + zebra_vxlan_handle_vni_transition(zvrf, zl3vni->vni, 0); return 0; } @@ -4475,3 +6085,16 @@ void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); hash_free(zvrf->vni_table); } + +/* init the l3vni table */ +void zebra_vxlan_ns_init(struct zebra_ns *zns) +{ + zns->l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp, + "Zebra VRF L3 VNI table"); +} + +/* free l3vni table */ +void zebra_vxlan_ns_disable(struct zebra_ns *zns) +{ + hash_free(zns->l3vni_table); +} diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 290d19bcf3..33e962c484 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -51,6 +51,7 @@ is_evpn_enabled() #define VNI_STR_LEN 32 +extern int zebra_vxlan_vrf_delete(struct zebra_vrf *); extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, u_char use_json); extern void zebra_vxlan_print_macs_all_vni(struct vty *vty, @@ -84,6 +85,14 @@ extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, u_char use_json); extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, u_char use_json); +extern void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char); +extern void zebra_vxlan_print_rmacs_all_l3vni(struct vty*, u_char); +extern void zebra_vxlan_print_nh_l3vni(struct vty*, vni_t, u_char); +extern void zebra_vxlan_print_nh_all_l3vni(struct vty*, u_char); +extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, + u_char use_json); +extern void zebra_vxlan_print_l3vnis(struct vty *vty, + u_char use_json); extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, int add); @@ -129,7 +138,11 @@ extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, extern int zebra_vxlan_advertise_all_vni(struct zserv *client, u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf*, vni_t, char*, + int); extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf); extern void zebra_vxlan_close_tables(struct zebra_vrf *); +extern void zebra_vxlan_ns_init(struct zebra_ns *zns); +extern void zebra_vxlan_ns_disable(struct zebra_ns *zns); #endif /* _ZEBRA_VXLAN_H */ diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c index bbed5ddb05..db828c337e 100644 --- a/zebra/zebra_vxlan_null.c +++ b/zebra/zebra_vxlan_null.c @@ -83,6 +83,30 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf) { } +void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char) +{ +} + +void zebra_vxlan_print_rmacs_all_l3vni(struct vty*, u_char) +{ +} + +void zebra_vxlan_print_nh_l3vni(struct vty*, vni_t, u_char) +{ +} + +void zebra_vxlan_print_nh_all_l3vni(struct vty*, u_char) +{ +} + +void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni) +{ +} + +void zebra_vxlan_print_l3vnis(struct vty *vty) +{ +} + int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) { return 0; diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index fa7d0e9457..c7bb7668ae 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -31,11 +31,14 @@ #include "if.h" #include "linklist.h" +#define ERR_STR_SZ 256 + /* definitions */ typedef struct zebra_vni_t_ zebra_vni_t; typedef struct zebra_vtep_t_ zebra_vtep_t; typedef struct zebra_mac_t_ zebra_mac_t; typedef struct zebra_neigh_t_ zebra_neigh_t; +typedef struct zebra_l3vni_t_ zebra_l3vni_t; /* * VTEP info @@ -75,6 +78,9 @@ struct zebra_vni_t_ { /* Local IP */ struct in_addr local_vtep_ip; + /* tenant VRF, if any */ + vrf_id_t vrf_id; + /* List of local or remote MAC */ struct hash *mac_table; @@ -82,6 +88,124 @@ struct zebra_vni_t_ { struct hash *neigh_table; }; +/* L3 VNI hash table */ +struct zebra_l3vni_t_ { + + /* VNI key */ + vni_t vni; + + /* vrf_id */ + vrf_id_t vrf_id; + + /* kernel interface for l3vni */ + struct interface *vxlan_if; + + /* SVI interface corresponding to the l3vni */ + struct interface *svi_if; + + /* list of L2 VNIs associated with the L3 VNI */ + struct list *l2vnis; + + /* list of remote router-macs */ + struct hash *rmac_table; + + /* list of remote vtep-ip neigh */ + struct hash *nh_table; +}; + +/* get the vx-intf name for l3vni */ +static inline const char *zl3vni_vxlan_if_name(zebra_l3vni_t *zl3vni) +{ + return zl3vni->vxlan_if ? zl3vni->vxlan_if->name : "None"; +} + +/* get the svi intf name for l3vni */ +static inline const char *zl3vni_svi_if_name(zebra_l3vni_t *zl3vni) +{ + return zl3vni->svi_if ? zl3vni->svi_if->name : "None"; +} + +/* get the vrf name for l3vni */ +static inline const char *zl3vni_vrf_name(zebra_l3vni_t *zl3vni) +{ + return vrf_id_to_name(zl3vni->vrf_id); +} + +/* get the rmac string */ +static inline const char *zl3vni_rmac2str(zebra_l3vni_t *zl3vni, char *buf, + int size) +{ + char *ptr; + + if (!buf) + ptr = (char *)XMALLOC(MTYPE_TMP, + ETHER_ADDR_STRLEN * sizeof(char)); + else { + assert(size >= ETHER_ADDR_STRLEN); + ptr = buf; + } + + if (zl3vni->svi_if) + snprintf(ptr, (ETHER_ADDR_STRLEN), + "%02x:%02x:%02x:%02x:%02x:%02x", + (uint8_t)zl3vni->svi_if->hw_addr[0], + (uint8_t)zl3vni->svi_if->hw_addr[1], + (uint8_t)zl3vni->svi_if->hw_addr[2], + (uint8_t)zl3vni->svi_if->hw_addr[3], + (uint8_t)zl3vni->svi_if->hw_addr[4], + (uint8_t)zl3vni->svi_if->hw_addr[5]); + else + snprintf(ptr, ETHER_ADDR_STRLEN, "None"); + + return ptr; +} + +/* + * l3-vni is oper up when: + * 1. it is associated to a vxlan-intf + * 2. Associated vxlan-intf is oper up + * 3. it is associated to an SVI + * 4. associated SVI is oper up + */ +static inline int is_l3vni_oper_up(zebra_l3vni_t *zl3vni) +{ + return (zl3vni && + (zl3vni->vrf_id != VRF_UNKNOWN) && + zl3vni->vxlan_if && if_is_operative(zl3vni->vxlan_if) && + zl3vni->svi_if && if_is_operative(zl3vni->svi_if)); +} + +static inline const char *zl3vni_state2str(zebra_l3vni_t *zl3vni) +{ + if (!zl3vni) + return NULL; + + if (is_l3vni_oper_up(zl3vni)) + return "Up"; + else + return "Down"; + + return NULL; +} + +static inline vrf_id_t zl3vni_vrf_id(zebra_l3vni_t *zl3vni) +{ + return zl3vni->vrf_id; +} + +static inline void zl3vni_get_rmac(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac) +{ + if (!zl3vni) + return; + + if (!is_l3vni_oper_up(zl3vni)) + return; + + if (zl3vni->svi_if && if_is_operative(zl3vni->svi_if)) + memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN); +} + /* * MAC hash table. * @@ -103,6 +227,7 @@ struct zebra_mac_t_ { #define ZEBRA_MAC_REMOTE 0x02 #define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */ #define ZEBRA_MAC_STICKY 0x08 /* Static MAC */ +#define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */ /* Local or remote info. */ union { @@ -116,6 +241,9 @@ struct zebra_mac_t_ { /* List of neigh associated with this mac */ struct list *neigh_list; + + /* Refcnt of number of mac-ips */ + u_int32_t rmac_refcnt; }; /* @@ -141,6 +269,11 @@ struct mac_walk_ctx { struct json_object *json; /* Used for JSON Output */ }; +struct rmac_walk_ctx { + struct vty *vty; + struct json_object *json; +}; + enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; #define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE @@ -175,11 +308,15 @@ struct zebra_neigh_t_ { u_int32_t flags; #define ZEBRA_NEIGH_LOCAL 0x01 #define ZEBRA_NEIGH_REMOTE 0x02 +#define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */ enum zebra_neigh_state state; /* Remote VTEP IP - applicable only for remote neighbors. */ struct in_addr r_vtep_ip; + + /* refcnt of remote mac-ip referring to a NH neigh */ + u_int32_t nh_refcnt; }; /* @@ -206,4 +343,18 @@ struct neigh_walk_ctx { struct json_object *json; /* Used for JSON Output */ }; +/* context for neigh hash walk - update l3vni and rmac */ +struct neigh_l3info_walk_ctx { + + zebra_vni_t *zvni; + zebra_l3vni_t *zl3vni; + int add; +}; + +struct nh_walk_ctx { + + struct vty *vty; + struct json_object *json; +}; + #endif /* _ZEBRA_VXLAN_PRIVATE_H */ diff --git a/zebra/zserv.c b/zebra/zserv.c index 684ba49e7d..4352b78e83 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2979,6 +2979,8 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "Interface Down Notifications: %d\n", client->ifdown_cnt); vty_out(vty, "VNI add notifications: %d\n", client->vniadd_cnt); vty_out(vty, "VNI delete notifications: %d\n", client->vnidel_cnt); + vty_out(vty, "L3-VNI add notifications: %d\n", client->l3vniadd_cnt); + vty_out(vty, "L3-VNI delete notifications: %d\n", client->l3vnidel_cnt); vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt); vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt); diff --git a/zebra/zserv.h b/zebra/zserv.h index c4b4e20df2..63db9d9eb9 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -110,6 +110,8 @@ struct zserv { u_int32_t bfd_client_reg_cnt; u_int32_t vniadd_cnt; u_int32_t vnidel_cnt; + u_int32_t l3vniadd_cnt; + u_int32_t l3vnidel_cnt; u_int32_t macipadd_cnt; u_int32_t macipdel_cnt;