diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 568 |
1 files changed, 406 insertions, 162 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 40a7eeba8e..4a6839d3b1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -68,11 +68,27 @@ #include "zebra/zebra_mroute.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_evpn_mh.h" #ifndef AF_MPLS #define AF_MPLS 28 #endif +/* Re-defining as I am unable to include <linux/if_bridge.h> which has the + * UAPI for MAC sync. */ +#ifndef _UAPI_LINUX_IF_BRIDGE_H +/* FDB notification bits for NDA_NOTIFY: + * - BR_FDB_NFY_STATIC - notify on activity/expire even for a static entry + * - BR_FDB_NFY_INACTIVE - mark as inactive to avoid double notification, + * used with BR_FDB_NFY_STATIC (kernel controlled) + */ +enum { + BR_FDB_NFY_STATIC, + BR_FDB_NFY_INACTIVE, + BR_FDB_NFY_MAX +}; +#endif + static vlanid_t filter_vlan = 0; /* We capture whether the current kernel supports nexthop ids; by @@ -131,6 +147,8 @@ static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags) flags |= NTF_EXT_LEARNED; if (dplane_flags & DPLANE_NTF_ROUTER) flags |= NTF_ROUTER; + if (dplane_flags & DPLANE_NTF_USE) + flags |= NTF_USE; return flags; } @@ -150,6 +168,8 @@ static uint16_t neigh_state_to_netlink(uint16_t dplane_state) state |= NUD_NOARP; if (dplane_state & DPLANE_NUD_PROBE) state |= NUD_PROBE; + if (dplane_state & DPLANE_NUD_INCOMPLETE) + state |= NUD_INCOMPLETE; return state; } @@ -163,7 +183,8 @@ static inline bool is_selfroute(int proto) || (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP) || (proto == RTPROT_LDP) || (proto == RTPROT_BABEL) || (proto == RTPROT_RIP) || (proto == RTPROT_SHARP) - || (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)) { + || (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC) + || (proto == RTPROT_SRTE)) { return true; } @@ -213,6 +234,9 @@ static inline int zebra2proto(int proto) case ZEBRA_ROUTE_OPENFABRIC: proto = RTPROT_OPENFABRIC; break; + case ZEBRA_ROUTE_SRTE: + proto = RTPROT_SRTE; + break; case ZEBRA_ROUTE_TABLE: case ZEBRA_ROUTE_NHG: proto = RTPROT_ZEBRA; @@ -278,6 +302,9 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop) case RTPROT_OPENFABRIC: proto = ZEBRA_ROUTE_OPENFABRIC; break; + case RTPROT_SRTE: + proto = ZEBRA_ROUTE_SRTE; + break; case RTPROT_ZEBRA: if (is_nexthop) { proto = ZEBRA_ROUTE_NHG; @@ -1051,14 +1078,17 @@ static bool _netlink_route_add_gateway_info(uint8_t route_family, bytelen + 2)) return false; } else { - if (gw_family == AF_INET) { - if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv4, bytelen)) - return false; - } else { - if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv6, bytelen)) - return false; + if (!(nexthop->rparent + && IS_MAPPED_IPV6(&nexthop->rparent->gate.ipv6))) { + if (gw_family == AF_INET) { + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen)) + return false; + } else { + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen)) + return false; + } } } @@ -2204,19 +2234,11 @@ nexthop_done: return NLMSG_ALIGN(req->n.nlmsg_len); } -/** - * kernel_nexthop_update() - Update/delete a nexthop from the kernel - * - * @ctx: Dataplane context - * - * Return: Dataplane result flag - */ -enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) +static ssize_t netlink_nexthop_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) { enum dplane_op_e op; int cmd = 0; - int ret = 0; - char buf[NL_PKT_BUF_SIZE]; op = dplane_ctx_get_op(ctx); if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) @@ -2227,33 +2249,43 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) flog_err(EC_ZEBRA_NHG_FIB_UPDATE, "Context received for kernel nexthop update with incorrect OP code (%u)", op); - return ZEBRA_DPLANE_REQUEST_FAILURE; + return -1; } + return netlink_nexthop_msg_encode(cmd, ctx, buf, buflen); +} + +enum netlink_msg_status +netlink_put_nexthop_update_msg(struct nl_batch *bth, + struct zebra_dplane_ctx *ctx) +{ /* Nothing to do if the kernel doesn't support nexthop objects */ if (!kernel_nexthops_supported()) - return ZEBRA_DPLANE_REQUEST_SUCCESS; + return FRR_NETLINK_SUCCESS; - if (netlink_nexthop_msg_encode(cmd, ctx, buf, sizeof(buf)) > 0) - ret = netlink_talk_info(netlink_talk_filter, (void *)&buf, - dplane_ctx_get_ns(ctx), 0); - else - ret = 0; + return netlink_batch_add_msg(bth, ctx, netlink_nexthop_msg_encoder, + false); +} - return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS - : ZEBRA_DPLANE_REQUEST_FAILURE); +static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf, + buflen, false, false); } -/* - * Update or delete a prefix from the kernel, - * using info from a dataplane context. - */ -enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) +static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf, + buflen, false, false); +} + +enum netlink_msg_status +netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) { - int cmd, ret; + int cmd; const struct prefix *p = dplane_ctx_get_dest(ctx); - struct nexthop *nexthop; - uint8_t nl_pkt[NL_PKT_BUF_SIZE]; if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { cmd = RTM_DELROUTE; @@ -2263,7 +2295,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) if (p->family == AF_INET || v6_rr_semantics) { /* Single 'replace' operation */ - cmd = RTM_NEWROUTE; /* * With route replace semantics in place @@ -2273,17 +2304,11 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * route should cause us to withdraw from * the kernel the old non-system route */ - if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) && - !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { - if (netlink_route_multipath_msg_encode( - RTM_DELROUTE, ctx, nl_pkt, - sizeof(nl_pkt), false, false) - > 0) - netlink_talk_info( - netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); - } + if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) + && !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) + netlink_batch_add_msg( + bth, ctx, netlink_delroute_msg_encoder, + true); } else { /* * So v6 route replace semantics are not in @@ -2297,51 +2322,24 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * of the route delete. If that happens yeah we're * screwed. */ - if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { - if (netlink_route_multipath_msg_encode( - RTM_DELROUTE, ctx, nl_pkt, - sizeof(nl_pkt), false, false) - > 0) - netlink_talk_info( - netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); - } - cmd = RTM_NEWROUTE; + if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) + netlink_batch_add_msg( + bth, ctx, netlink_delroute_msg_encoder, + true); } - } else { - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) { - if (netlink_route_multipath_msg_encode( - cmd, ctx, nl_pkt, sizeof(nl_pkt), false, false) - > 0) - ret = netlink_talk_info(netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); - else - ret = -1; - + cmd = RTM_NEWROUTE; } else - ret = 0; - if ((cmd == RTM_NEWROUTE) && (ret == 0)) { - /* Update installed nexthops to signal which have been - * installed. - */ - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; + return FRR_NETLINK_ERROR; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - } - } - } + if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) + return FRR_NETLINK_SUCCESS; - return (ret == 0 ? - ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); + return netlink_batch_add_msg(bth, ctx, + cmd == RTM_NEWROUTE + ? netlink_newroute_msg_encoder + : netlink_delroute_msg_encoder, + false); } /** @@ -2518,6 +2516,15 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* We use the ID key'd nhg table for kernel updates */ id = *((uint32_t *)RTA_DATA(tb[NHA_ID])); + if (zebra_evpn_mh_is_fdb_nh(id)) { + /* If this is a L2 NH just ignore it */ + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) { + zlog_debug("Ignore kernel update (%u) for fdb-nh 0x%x", + h->nlmsg_type, id); + } + return 0; + } + family = nhm->nh_family; afi = family2afi(family); @@ -2673,7 +2680,9 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, static ssize_t netlink_neigh_update_msg_encode( const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac, const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type, - uint8_t flags, uint16_t state, void *data, size_t datalen) + uint8_t flags, uint16_t state, uint32_t nhg_id, + bool nfy, uint8_t nfy_flags, + void *data, size_t datalen) { uint8_t protocol = RTPROT_ZEBRA; struct { @@ -2686,7 +2695,7 @@ static ssize_t netlink_neigh_update_msg_encode( if (datalen < sizeof(*req)) return 0; - memset(req, 0, datalen); + memset(req, 0, sizeof(*req)); op = dplane_ctx_get_op(ctx); @@ -2703,7 +2712,7 @@ static ssize_t netlink_neigh_update_msg_encode( req->ndm.ndm_flags = flags; req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); - if (!nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol, + if (!nl_attr_put(&req->n, datalen, NDA_PROTOCOL, &protocol, sizeof(protocol))) return 0; @@ -2712,6 +2721,16 @@ static ssize_t netlink_neigh_update_msg_encode( return 0; } + if (nhg_id) { + if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id)) + return 0; + } + if (nfy) { + if (!nl_attr_put(&req->n, datalen, NDA_NOTIFY, + &nfy_flags, sizeof(nfy_flags))) + return 0; + } + ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len)) return 0; @@ -2736,22 +2755,16 @@ static ssize_t netlink_neigh_update_msg_encode( * Add remote VTEP to the flood list for this VxLAN interface (VNI). This * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00. */ -static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, - int cmd) +static ssize_t +netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd, + void *buf, size_t buflen) { struct ethaddr dst_mac = {.octet = {0}}; - uint8_t nl_pkt[NL_PKT_BUF_SIZE]; - if (netlink_neigh_update_msg_encode( - ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false, - PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt, - sizeof(nl_pkt)) - <= 0) - return -1; - - return netlink_talk_info(netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); + return netlink_neigh_update_msg_encode( + ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false, + PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, + false /*nfy*/, 0 /*nfy_flags*/, buf, buflen); } #ifndef NDA_RTA @@ -2774,6 +2787,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) char vid_buf[20]; char dst_buf[30]; bool sticky; + bool local_inactive = false; + bool dp_static = false; + uint32_t nhg_id = 0; ndm = NLMSG_DATA(h); @@ -2821,13 +2837,29 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) inet_ntoa(vtep_ip)); } + if (tb[NDA_NH_ID]) + nhg_id = *(uint32_t *)RTA_DATA(tb[NDA_NH_ID]); + + if (ndm->ndm_state & NUD_STALE) + local_inactive = true; + + if (tb[NDA_NOTIFY]) { + uint8_t nfy_flags; + + dp_static = true; + nfy_flags = *(uint8_t *)RTA_DATA(tb[NDA_NOTIFY]); + /* local activity has not been detected on the entry */ + if (nfy_flags & (1 << BR_FDB_NFY_INACTIVE)) + local_inactive = true; + } + if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %s%s", + zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %s%s nhg %d", nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex, vid_present ? vid_buf : "", ndm->ndm_state, ndm->ndm_flags, prefix_mac2str(&mac, buf, sizeof(buf)), - dst_present ? dst_buf : ""); + dst_present ? dst_buf : "", nhg_id); /* The interface should exist. */ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), @@ -2850,7 +2882,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) return 0; } - sticky = !!(ndm->ndm_state & NUD_NOARP); + sticky = !!(ndm->ndm_flags & NTF_STICKY); if (filter_vlan && vid != filter_vlan) { if (IS_ZEBRA_DEBUG_KERNEL) @@ -2878,7 +2910,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) vid); return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid, - sticky); + sticky, local_inactive, dp_static); } /* This is a delete notification. @@ -2891,6 +2923,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * Note: We will get notifications from both bridge driver and VxLAN * driver. */ + if (nhg_id) + return 0; + if (dst_present) { u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; @@ -3078,9 +3113,8 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, /* * Netlink-specific handler for MAC updates using dataplane context object. */ -ssize_t -netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, - size_t datalen) +ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, + size_t datalen) { struct ipaddr vtep_ip; vlanid_t vid; @@ -3088,18 +3122,43 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, int cmd; uint8_t flags; uint16_t state; + uint32_t nhg_id; + uint32_t update_flags; + bool nfy = false; + uint8_t nfy_flags = 0; cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL ? RTM_NEWNEIGH : RTM_DELNEIGH; - flags = (NTF_SELF | NTF_MASTER); + flags = NTF_MASTER; state = NUD_REACHABLE; - if (dplane_ctx_mac_is_sticky(ctx)) - state |= NUD_NOARP; - else - flags |= NTF_EXT_LEARNED; + update_flags = dplane_ctx_mac_get_update_flags(ctx); + if (update_flags & DPLANE_MAC_REMOTE) { + flags |= NTF_SELF; + if (dplane_ctx_mac_is_sticky(ctx)) + flags |= NTF_STICKY; + else + flags |= NTF_EXT_LEARNED; + /* if it was static-local previously we need to clear the + * notify flags on replace with remote + */ + if (update_flags & DPLANE_MAC_WAS_STATIC) + nfy = true; + } else { + /* local mac */ + if (update_flags & DPLANE_MAC_SET_STATIC) { + nfy_flags |= (1 << BR_FDB_NFY_STATIC); + state |= NUD_NOARP; + } + if (update_flags & DPLANE_MAC_SET_INACTIVE) + nfy_flags |= (1 << BR_FDB_NFY_INACTIVE); + + nfy = true; + } + + nhg_id = dplane_ctx_mac_get_nhg_id(ctx); vtep_ip.ipaddr_v4 = *(dplane_ctx_mac_get_vtep_ip(ctx)); SET_IPADDR_V4(&vtep_ip); @@ -3107,6 +3166,7 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, char ipbuf[PREFIX_STRLEN]; char buf[ETHER_ADDR_STRLEN]; char vid_buf[20]; + const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx); vid = dplane_ctx_mac_get_vlan(ctx); if (vid > 0) @@ -3114,20 +3174,30 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, else vid_buf[0] = '\0'; - const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx); - - zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s", + zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s nhg %u%s%s%s%s%s", nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE), dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx), vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "", prefix_mac2str(mac, buf, sizeof(buf)), - ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf))); + ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)), + nhg_id, + (update_flags & + DPLANE_MAC_REMOTE) ? " rem" : "", + (update_flags & + DPLANE_MAC_WAS_STATIC) ? " clr_sync" : "", + (update_flags & + DPLANE_MAC_SET_STATIC) ? " static" : "", + (update_flags & + DPLANE_MAC_SET_INACTIVE) ? " inactive" : "", + (nfy & + DPLANE_MAC_SET_INACTIVE) ? " nfy" : ""); } total = netlink_neigh_update_msg_encode( ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true, - AF_BRIDGE, 0, flags, state, data, datalen); + AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags, + data, datalen); return total; } @@ -3161,6 +3231,8 @@ static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif, #define NUD_VALID \ (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE \ | NUD_DELAY) +#define NUD_LOCAL_ACTIVE \ + (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE) static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) { @@ -3177,6 +3249,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) int mac_present = 0; bool is_ext; bool is_router; + bool local_inactive; ndm = NLMSG_DATA(h); @@ -3286,10 +3359,17 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * result * in re-adding the neighbor if it is a valid "remote" neighbor. */ - if (ndm->ndm_state & NUD_VALID) + if (ndm->ndm_state & NUD_VALID) { + local_inactive = !(ndm->ndm_state & NUD_LOCAL_ACTIVE); + + /* XXX - populate dp-static based on the sync flags + * in the kernel + */ return zebra_vxlan_handle_kernel_neigh_update( ifp, link_if, &ip, &mac, ndm->ndm_state, - is_ext, is_router); + is_ext, is_router, local_inactive, + false /* dp_static */); + } return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip); } @@ -3510,15 +3590,14 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) /* * Utility neighbor-update function, using info from dplane context. */ -static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, - int cmd) +static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, + int cmd, void *buf, size_t buflen) { const struct ipaddr *ip; const struct ethaddr *mac; uint8_t flags; uint16_t state; uint8_t family; - uint8_t nl_pkt[NL_PKT_BUF_SIZE]; ip = dplane_ctx_neigh_get_ipaddr(ctx); mac = dplane_ctx_neigh_get_mac(ctx); @@ -3543,59 +3622,56 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, flags, state); } - if (netlink_neigh_update_msg_encode(ctx, cmd, mac, ip, true, family, - RTN_UNICAST, flags, state, nl_pkt, - sizeof(nl_pkt)) - <= 0) - return -1; - - return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); + return netlink_neigh_update_msg_encode( + ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state, + 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, buf, buflen); } -/* - * Update MAC, using dataplane context object. - */ -enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) +static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) { - uint8_t nl_pkt[NL_PKT_BUF_SIZE]; - ssize_t rv; - - rv = netlink_macfdb_update_ctx(ctx, nl_pkt, sizeof(nl_pkt)); - if (rv <= 0) - return ZEBRA_DPLANE_REQUEST_FAILURE; - - rv = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); - - return rv == 0 ? - ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE; -} - -enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx) -{ - int ret = -1; + ssize_t ret; switch (dplane_ctx_get_op(ctx)) { case DPLANE_OP_NEIGH_INSTALL: case DPLANE_OP_NEIGH_UPDATE: - ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH); + case DPLANE_OP_NEIGH_DISCOVER: + ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen); break; case DPLANE_OP_NEIGH_DELETE: - ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH); + ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); break; case DPLANE_OP_VTEP_ADD: - ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH); + ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf, + buflen); break; case DPLANE_OP_VTEP_DELETE: - ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH); + ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf, + buflen); break; default: - break; + ret = -1; } - return (ret == 0 ? - ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); + return ret; +} + +/* + * Update MAC, using dataplane context object. + */ + +enum netlink_msg_status netlink_put_mac_update_msg(struct nl_batch *bth, + struct zebra_dplane_ctx *ctx) +{ + return netlink_batch_add_msg(bth, ctx, netlink_macfdb_update_ctx, + false); +} + +enum netlink_msg_status +netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) +{ + return netlink_batch_add_msg(bth, ctx, netlink_neigh_msg_encoder, + false); } /* @@ -3754,4 +3830,172 @@ ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, return NLMSG_ALIGN(req->n.nlmsg_len); } + +/**************************************************************************** +* This code was developed in a branch that didn't have dplane APIs for +* MAC updates. Hence the use of the legacy style. It will be moved to +* the new dplane style pre-merge to master. XXX +*/ +static int netlink_fdb_nh_update(uint32_t nh_id, struct in_addr vtep_ip) +{ + struct { + struct nlmsghdr n; + struct nhmsg nhm; + char buf[256]; + } req; + int cmd = RTM_NEWNEXTHOP; + struct zebra_vrf *zvrf; + struct zebra_ns *zns; + + zvrf = zebra_vrf_get_evpn(); + if (!zvrf) + return -1; + zns = zvrf->zns; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + req.n.nlmsg_type = cmd; + req.nhm.nh_family = AF_INET; + + if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id)) + return -1; + if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0)) + return -1; + if (!nl_attr_put(&req.n, sizeof(req), NHA_GATEWAY, + &vtep_ip, IPV4_MAX_BYTELEN)) + return -1; + + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) { + zlog_debug("Tx %s fdb-nh 0x%x %s", + nl_msg_type_to_str(cmd), nh_id, inet_ntoa(vtep_ip)); + } + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); +} + +static int netlink_fdb_nh_del(uint32_t nh_id) +{ + struct { + struct nlmsghdr n; + struct nhmsg nhm; + char buf[256]; + } req; + int cmd = RTM_DELNEXTHOP; + struct zebra_vrf *zvrf; + struct zebra_ns *zns; + + zvrf = zebra_vrf_get_evpn(); + if (!zvrf) + return -1; + zns = zvrf->zns; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.nhm.nh_family = AF_UNSPEC; + + if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id)) + return -1; + + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) { + zlog_debug("Tx %s fdb-nh 0x%x", + nl_msg_type_to_str(cmd), nh_id); + } + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); +} + +static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt, + struct nh_grp *nh_ids) +{ + struct { + struct nlmsghdr n; + struct nhmsg nhm; + char buf[256]; + } req; + int cmd = RTM_NEWNEXTHOP; + struct zebra_vrf *zvrf; + struct zebra_ns *zns; + struct nexthop_grp grp[nh_cnt]; + uint32_t i; + + zvrf = zebra_vrf_get_evpn(); + if (!zvrf) + return -1; + zns = zvrf->zns; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + req.n.nlmsg_type = cmd; + req.nhm.nh_family = AF_UNSPEC; + + if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nhg_id)) + return -1; + if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0)) + return -1; + memset(&grp, 0, sizeof(grp)); + for (i = 0; i < nh_cnt; ++i) { + grp[i].id = nh_ids[i].id; + grp[i].weight = nh_ids[i].weight; + } + if (!nl_attr_put(&req.n, sizeof(req), NHA_GROUP, + grp, nh_cnt * sizeof(struct nexthop_grp))) + return -1; + + + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) { + char vtep_str[ES_VTEP_LIST_STR_SZ]; + char nh_buf[16]; + + vtep_str[0] = '\0'; + for (i = 0; i < nh_cnt; ++i) { + snprintf(nh_buf, sizeof(nh_buf), "%u ", + grp[i].id); + strlcat(vtep_str, nh_buf, sizeof(vtep_str)); + } + + zlog_debug("Tx %s fdb-nhg 0x%x %s", + nl_msg_type_to_str(cmd), nhg_id, vtep_str); + } + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); +} + +static int netlink_fdb_nhg_del(uint32_t nhg_id) +{ + return netlink_fdb_nh_del(nhg_id); +} + +int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip) +{ + return netlink_fdb_nh_update(nh_id, vtep_ip); +} + +int kernel_del_mac_nh(uint32_t nh_id) +{ + return netlink_fdb_nh_del(nh_id); +} + +int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt, + struct nh_grp *nh_ids) +{ + return netlink_fdb_nhg_update(nhg_id, nh_cnt, nh_ids); +} + +int kernel_del_mac_nhg(uint32_t nhg_id) +{ + return netlink_fdb_nhg_del(nhg_id); +} + #endif /* HAVE_NETLINK */ |
