From 036d93c04731308891ac60feadd81ed913fd80e2 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Tue, 30 Jul 2019 11:54:07 -0400 Subject: [PATCH] zebra: use dataplane for vxlan remote mac programming Move vxlan remote MAC install and uninstall to the async dataplane. Signed-off-by: Mark Stapp --- zebra/rt.h | 10 ++-- zebra/rt_netlink.c | 108 +++++++++++++++++++++++++++++++------------ zebra/rt_socket.c | 14 ++---- zebra/zebra_dplane.c | 44 +++++++++++++++++- zebra/zebra_rib.c | 5 ++ zebra/zebra_vxlan.c | 51 +++++++++++++++----- zebra/zebra_vxlan.h | 3 ++ 7 files changed, 177 insertions(+), 58 deletions(-) diff --git a/zebra/rt.h b/zebra/rt.h index 04576671fe..727d2d0c55 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -41,7 +41,7 @@ extern "C" { ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT) /* - * Update or delete a route, LSP, or pseudowire from the kernel, + * Update or delete a route, LSP, pseudowire, or vxlan MAC from the kernel, * using info from a dataplane context. */ extern enum zebra_dplane_result kernel_route_update( @@ -55,6 +55,8 @@ enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx); enum zebra_dplane_result kernel_address_update_ctx( struct zebra_dplane_ctx *ctx); +enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx); + extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, int llalen, ns_id_t ns_id); extern int kernel_interface_set_master(struct interface *master, @@ -68,12 +70,6 @@ extern int kernel_add_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); extern int kernel_del_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); -extern int kernel_add_mac(struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip, - bool sticky); -extern int kernel_del_mac(struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip); - extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac, uint8_t flags); extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b1d0c1e3a6..e48ed9ef8b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2279,33 +2279,70 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, return ret; } -static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip, - int cmd, bool sticky) + +/* + * Netlink-specific handler for MAC updates using dataplane context object. + */ +static enum zebra_dplane_result +netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) { - struct zebra_ns *zns; struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; + int ret; int dst_alen; struct zebra_if *zif; struct interface *br_if; struct zebra_if *br_zif; - char buf[ETHER_ADDR_STRLEN]; int vid_present = 0; char vid_buf[20]; - char dst_buf[30]; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + struct zebra_ns *zns; + struct interface *ifp; + int cmd; + struct in_addr vtep_ip; + vlanid_t vid; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL) + cmd = RTM_NEWNEIGH; + else + cmd = RTM_DELNEIGH; + + /* Locate zebra ns and interface objects from context data */ + zns = zebra_ns_lookup(dplane_ctx_get_ns(ctx)->ns_id); + if (zns == NULL) { + /* Nothing to be done */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("MAC %s on IF %s(%u) - zebra ns unknown", + (cmd == RTM_NEWNEIGH) ? "add" : "del", + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx)); + + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + + ifp = if_lookup_by_index_per_ns(zns, dplane_ctx_get_ifindex(ctx)); + if (ifp == NULL) { + /* Nothing to be done */ + /* Nothing to be done */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("MAC %s on IF %s(%u) - interface unknown", + (cmd == RTM_NEWNEIGH) ? "add" : "del", + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx)); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + + vid = dplane_ctx_mac_get_vlan(ctx); - zns = zvrf->zns; zif = ifp->info; if ((br_if = zif->brslave_info.br_if) == NULL) { - zlog_debug("MAC %s on IF %s(%u) - no mapping to bridge", - (cmd == RTM_NEWNEIGH) ? "add" : "del", ifp->name, - ifp->ifindex); - return -1; + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("MAC %s on IF %s(%u) - no mapping to bridge", + (cmd == RTM_NEWNEIGH) ? "add" : "del", + ifp->name, ifp->ifindex); + return ZEBRA_DPLANE_REQUEST_FAILURE; } memset(&req, 0, sizeof(req)); @@ -2319,16 +2356,19 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; req.ndm.ndm_state = NUD_REACHABLE; - if (sticky) + if (dplane_ctx_mac_is_sticky(ctx)) req.ndm.ndm_state |= NUD_NOARP; else req.ndm.ndm_flags |= NTF_EXT_LEARNED; - addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + addattr_l(&req.n, sizeof(req), NDA_LLADDR, + dplane_ctx_mac_get_addr(ctx), 6); req.ndm.ndm_ifindex = ifp->ifindex; + dst_alen = 4; // TODO: hardcoded + vtep_ip = *(dplane_ctx_mac_get_vtep_ip(ctx)); addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen); - sprintf(dst_buf, " dst %s", inet_ntoa(vtep_ip)); + br_zif = (struct zebra_if *)br_if->info; if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) { addattr16(&req.n, sizeof(req), NDA_VLAN, vid); @@ -2337,16 +2377,29 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, } addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); - if (IS_ZEBRA_DEBUG_KERNEL) + if (IS_ZEBRA_DEBUG_KERNEL) { + char ipbuf[PREFIX_STRLEN]; + char buf[ETHER_ADDR_STRLEN]; + char dst_buf[PREFIX_STRLEN + 10]; + + inet_ntop(AF_INET, &vtep_ip, ipbuf, sizeof(ipbuf)); + snprintf(dst_buf, sizeof(dst_buf), " dst %s", ipbuf); + prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf, sizeof(buf)); + zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s%s", nl_msg_type_to_str(cmd), nl_family_to_str(req.ndm.ndm_family), ifp->name, ifp->ifindex, vid_present ? vid_buf : "", - sticky ? "sticky " : "", - prefix_mac2str(mac, buf, sizeof(buf)), dst_buf); + dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "", + buf, dst_buf); + } - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - 0); + ret = netlink_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); + if (ret == 0) + return ZEBRA_DPLANE_REQUEST_SUCCESS; + else + return ZEBRA_DPLANE_REQUEST_FAILURE; } /* @@ -2759,17 +2812,12 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, 0); } -int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip, bool sticky) +/* + * Update MAC, using dataplane context object. + */ +enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) { - return netlink_macfdb_update(ifp, vid, mac, vtep_ip, RTM_NEWNEIGH, - sticky); -} - -int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip) -{ - return netlink_macfdb_update(ifp, vid, mac, vtep_ip, RTM_DELNEIGH, 0); + return netlink_macfdb_update_ctx(ctx); } int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 8d8bdd0a6d..7e9a42a617 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -386,16 +386,12 @@ int kernel_del_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) return 0; } -int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip, bool sticky) +/* + * Update MAC, using dataplane context object. No-op here for now. + */ +enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) { - return 0; -} - -int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip) -{ - return 0; + return ZEBRA_DPLANE_REQUEST_SUCCESS; } int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 5d99500397..4ba6b3e981 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -2114,6 +2114,16 @@ mac_update_internal(enum dplane_op_e op, struct zebra_dplane_ctx *ctx = NULL; struct zebra_ns *zns; + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN]; + + zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s", + dplane_op2str(op), + prefix_mac2str(mac, buf1, sizeof(buf1)), + ifp->name, + inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2))); + } + ctx = dplane_ctx_alloc(); ctx->zd_op = op; @@ -2560,7 +2570,6 @@ kernel_dplane_address_update(struct zebra_dplane_ctx *ctx) { enum zebra_dplane_result res; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { char dest_str[PREFIX_STRLEN]; @@ -2581,6 +2590,34 @@ kernel_dplane_address_update(struct zebra_dplane_ctx *ctx) return res; } +/* + * Handler for kernel-facing MAC address updates + */ +static enum zebra_dplane_result +kernel_dplane_mac_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result res; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + char buf[ETHER_ADDR_STRLEN]; + + prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf, + sizeof(buf)); + + zlog_debug("Dplane %s, mac %s, ifindex %u", + dplane_op2str(dplane_ctx_get_op(ctx)), + buf, dplane_ctx_get_ifindex(ctx)); + } + + res = kernel_mac_update_ctx(ctx); + + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors, + 1, memory_order_relaxed); + + return res; +} + /* * Kernel provider callback */ @@ -2635,6 +2672,11 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) res = kernel_dplane_address_update(ctx); break; + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + res = kernel_dplane_mac_update(ctx); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 601970785e..fa8b5d400a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3312,6 +3312,11 @@ static int rib_process_dplane_results(struct thread *thread) dplane_ctx_fini(&ctx); break; + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + zebra_vxlan_handle_result(ctx); + break; + default: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index dff50ceef4..24cd88b91f 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3694,13 +3694,14 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) } /* - * Install remote MAC into the kernel. + * Install remote MAC into the forwarding plane. */ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) { struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; bool sticky; + enum zebra_dplane_result res; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; @@ -3713,12 +3714,16 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) sticky = !!CHECK_FLAG(mac->flags, (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); - return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, - mac->fwd_info.r_vtep_ip, sticky); + res = dplane_mac_add(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, + mac->fwd_info.r_vtep_ip, sticky); + if (res != ZEBRA_DPLANE_REQUEST_FAILURE) + return 0; + else + return -1; } /* - * Uninstall remote MAC from the kernel. + * Uninstall remote MAC from the forwarding plane. */ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) { @@ -3726,6 +3731,7 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) struct zebra_l2info_vxlan *vxl; struct in_addr vtep_ip; struct interface *ifp; + enum zebra_dplane_result res; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; @@ -3744,7 +3750,11 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) ifp = zvni->vxlan_if; vtep_ip = mac->fwd_info.r_vtep_ip; - return kernel_del_mac(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip); + res = dplane_mac_del(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip); + if (res != ZEBRA_DPLANE_REQUEST_FAILURE) + return 0; + else + return -1; } /* @@ -4431,12 +4441,13 @@ static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) } /* - * Install remote RMAC into the kernel. + * Install remote RMAC into the forwarding plane. */ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { struct zebra_if *zif = NULL; struct zebra_l2info_vxlan *vxl = NULL; + enum zebra_dplane_result res; if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) @@ -4448,18 +4459,23 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) vxl = &zif->l2info.vxl; - return kernel_add_mac(zl3vni->vxlan_if, vxl->access_vlan, - &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); + res = dplane_mac_add(zl3vni->vxlan_if, vxl->access_vlan, + &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); + if (res != ZEBRA_DPLANE_REQUEST_FAILURE) + return 0; + else + return -1; } /* - * Uninstall remote RMAC from the kernel. + * Uninstall remote RMAC from the forwarding plane. */ 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; + enum zebra_dplane_result res; if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) @@ -4479,8 +4495,12 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) vxl = &zif->l2info.vxl; - return kernel_del_mac(zl3vni->vxlan_if, vxl->access_vlan, - &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); + res = dplane_mac_del(zl3vni->vxlan_if, vxl->access_vlan, + &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); + if (res != ZEBRA_DPLANE_REQUEST_FAILURE) + return 0; + else + return -1; } /* handle rmac add */ @@ -9872,6 +9892,15 @@ static int zebra_evpn_cfg_clean_up(struct zserv *client) return 0; } +/* + * Handle results for vxlan dataplane operations. + */ +extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx) +{ + /* TODO -- anything other than freeing the context? */ + dplane_ctx_fini(&ctx); +} + /* Cleanup BGP EVPN configuration upon client disconnect */ extern void zebra_evpn_init(void) { diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index c71953d6bb..bb80ae1c9a 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -35,6 +35,7 @@ #include "lib/json.h" #include "zebra/zebra_vrf.h" #include "zebra/zserv.h" +#include "zebra/zebra_dplane.h" #ifdef __cplusplus extern "C" { @@ -213,6 +214,8 @@ extern int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); +extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx); + extern void zebra_evpn_init(void); #ifdef __cplusplus