((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(
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,
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);
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));
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);
}
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;
}
/*
0);
}
-int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac,
- struct in_addr vtep_ip, bool sticky)
-{
- 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)
+/*
+ * 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_DELNEIGH, 0);
+ return netlink_macfdb_update_ctx(ctx);
}
int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip,
return 0;
}
-int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac,
- struct in_addr vtep_ip, bool sticky)
-{
- return 0;
-}
-
-int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac,
- struct in_addr vtep_ip)
+/*
+ * 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;
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip,
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;
{
enum zebra_dplane_result res;
-
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
char dest_str[PREFIX_STRLEN];
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
*/
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:
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);
}
/*
- * 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;
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)
{
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;
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;
}
/*
}
/*
- * 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)))
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)))
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 */
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)
{
#include "lib/json.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zserv.h"
+#include "zebra/zebra_dplane.h"
#ifdef __cplusplus
extern "C" {
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