diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 708 |
1 files changed, 368 insertions, 340 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5a1ae2c217..5c9d2f69a6 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -718,14 +718,15 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (IS_ZEBRA_DEBUG_KERNEL) { char buf[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; - zlog_debug("%s %s%s%s vrf %u(%u) metric: %d Admin Distance: %d", - nl_msg_type_to_str(h->nlmsg_type), - prefix2str(&p, buf, sizeof(buf)), - src_p.prefixlen ? " from " : "", - src_p.prefixlen - ? prefix2str(&src_p, buf2, sizeof(buf2)) - : "", - vrf_id, table, metric, distance); + zlog_debug( + "%s %s%s%s vrf %s(%u) table_id: %u metric: %d Admin Distance: %d", + nl_msg_type_to_str(h->nlmsg_type), + prefix2str(&p, buf, sizeof(buf)), + src_p.prefixlen ? " from " : "", + src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) + : "", + vrf_id_to_name(vrf_id), vrf_id, table, metric, + distance); } afi_t afi = AFI_IP; @@ -911,9 +912,8 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h, ifp = if_lookup_by_index(iif, vrf); zlog_debug( "MCAST VRF: %s(%d) %s (%s,%s) IIF: %s(%d) OIF: %s jiffies: %lld", - (zvrf ? zvrf->vrf->name : "Unknown"), vrf, - nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, - ifp ? ifp->name : "Unknown", iif, oif_list, + zvrf_name(zvrf), vrf, nl_msg_type_to_str(h->nlmsg_type), + sbuf, gbuf, ifp ? ifp->name : "Unknown", iif, oif_list, m->lastused); } return 0; @@ -983,7 +983,7 @@ static int netlink_request_route(struct zebra_ns *zns, int family, int type) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.rtm.rtm_family = family; - return netlink_request(&zns->netlink_cmd, &req.n); + return netlink_request(&zns->netlink_cmd, &req); } /* Routing table read function using netlink interface. Only called @@ -1122,9 +1122,13 @@ static void _netlink_route_build_singlepath(const struct prefix *p, mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; int num_labels = 0; + struct vrf *vrf; + char addrstr[INET6_ADDRSTRLEN]; assert(nexthop); + vrf = vrf_lookup_by_id(nexthop->vrf_id); + /* * label_buf is *only* currently used within debugging. * As such when we assign it we are guarding it inside @@ -1176,10 +1180,10 @@ static void _netlink_route_build_singlepath(const struct prefix *p, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - " 5549: _netlink_route_build_singlepath() (%s): %pFX nexthop via %s %s if %u(%u)", - routedesc, p, ipv4_ll_buf, label_buf, - nexthop->ifindex, nexthop->vrf_id); + zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)", + __func__, routedesc, p, ipv4_ll_buf, + label_buf, nexthop->ifindex, + VRF_LOGNAME(vrf), nexthop->vrf_id); return; } @@ -1200,11 +1204,14 @@ static void _netlink_route_build_singlepath(const struct prefix *p, &nexthop->src.ipv4, bytelen); } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)", - routedesc, p, inet_ntoa(nexthop->gate.ipv4), - label_buf, nexthop->ifindex, nexthop->vrf_id); + if (IS_ZEBRA_DEBUG_KERNEL) { + inet_ntop(AF_INET, &nexthop->gate.ipv4, addrstr, + sizeof(addrstr)); + zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)", + __func__, routedesc, p, addrstr, label_buf, + nexthop->ifindex, VRF_LOGNAME(vrf), + nexthop->vrf_id); + } } if (nexthop->type == NEXTHOP_TYPE_IPV6 @@ -1222,11 +1229,14 @@ static void _netlink_route_build_singlepath(const struct prefix *p, &nexthop->src.ipv6, bytelen); } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)", - routedesc, p, inet6_ntoa(nexthop->gate.ipv6), - label_buf, nexthop->ifindex, nexthop->vrf_id); + if (IS_ZEBRA_DEBUG_KERNEL) { + inet_ntop(AF_INET6, &nexthop->gate.ipv6, addrstr, + sizeof(addrstr)); + zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)", + __func__, routedesc, p, addrstr, label_buf, + nexthop->ifindex, VRF_LOGNAME(vrf), + nexthop->vrf_id); + } } /* @@ -1248,10 +1258,9 @@ static void _netlink_route_build_singlepath(const struct prefix *p, } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): %pFX nexthop via if %u(%u)", - routedesc, p, nexthop->ifindex, - nexthop->vrf_id); + zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)", + __func__, routedesc, p, nexthop->ifindex, + VRF_LOGNAME(vrf), nexthop->vrf_id); } } @@ -1280,6 +1289,7 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; int num_labels = 0; + struct vrf *vrf; rtnh->rtnh_len = sizeof(*rtnh); rtnh->rtnh_flags = 0; @@ -1288,6 +1298,8 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, assert(nexthop); + vrf = vrf_lookup_by_id(nexthop->vrf_id); + /* * label_buf is *only* currently used within debugging. * As such when we assign it we are guarding it inside @@ -1347,9 +1359,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - " 5549: netlink_route_build_multipath() (%s): %pFX nexthop via %s %s if %u", - routedesc, p, ipv4_ll_buf, label_buf, - nexthop->ifindex); + "%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)", + __func__, routedesc, p, ipv4_ll_buf, label_buf, + nexthop->ifindex, VRF_LOGNAME(vrf), + nexthop->vrf_id); return; } @@ -1364,10 +1377,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u", - routedesc, p, inet_ntoa(nexthop->gate.ipv4), - label_buf, nexthop->ifindex); + zlog_debug("%s: (%s): %pFX nexthop via %pI4 %s if %u vrf %s(%u)", + __func__, routedesc, p, &nexthop->gate.ipv4, + label_buf, nexthop->ifindex, + VRF_LOGNAME(vrf), nexthop->vrf_id); } if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { @@ -1381,10 +1394,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u", - routedesc, p, inet6_ntoa(nexthop->gate.ipv6), - label_buf, nexthop->ifindex); + zlog_debug("%s: (%s): %pFX nexthop via %pI6 %s if %u vrf %s(%u)", + __func__, routedesc, p, &nexthop->gate.ipv6, + label_buf, nexthop->ifindex, + VRF_LOGNAME(vrf), nexthop->vrf_id); } /* @@ -1403,9 +1416,9 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): %pFX nexthop via if %u", - routedesc, p, nexthop->ifindex); + zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)", + __func__, routedesc, p, nexthop->ifindex, + VRF_LOGNAME(vrf), nexthop->vrf_id); } if (nexthop->weight) @@ -1444,37 +1457,6 @@ _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc, rta, rtnh, rtmsg, src); } - -/* Log debug information for netlink_route_multipath - * if debug logging is enabled. - * - * @param cmd: Netlink command which is to be processed - * @param p: Prefix for which the change is due - * @param family: Address family which the change concerns - * @param zvrf: The vrf we are in - * @param tableid: The table we are working on - */ -static void _netlink_route_debug(int cmd, const struct prefix *p, - int family, vrf_id_t vrfid, - uint32_t tableid) -{ - if (IS_ZEBRA_DEBUG_KERNEL) { - char buf[PREFIX_STRLEN]; - zlog_debug( - "netlink_route_multipath(): %s %s vrf %u(%u)", - nl_msg_type_to_str(cmd), - prefix2str(p, buf, sizeof(buf)), - vrfid, tableid); - } -} - -static void _netlink_nexthop_debug(int cmd, uint32_t id) -{ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_nexthop(): %s, id=%u", - nl_msg_type_to_str(cmd), id); -} - static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) { if (IS_ZEBRA_DEBUG_KERNEL) @@ -1539,15 +1521,32 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family, return false; } +static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, + struct nexthop *nh) +{ + struct rtattr *nest; + + switch (nh->nh_encap_type) { + case NET_VXLAN: + addattr_l(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type, + sizeof(uint16_t)); + + nest = addattr_nest(n, nlen, RTA_ENCAP); + addattr32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni); + addattr_nest_end(n, nest); + break; + } +} + /* * Routing table change via netlink interface, using a dataplane context object */ -static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) +ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, + uint8_t *data, size_t datalen, bool fpm) { int bytelen; struct nexthop *nexthop = NULL; unsigned int nexthop_num; - int family; const char *routedesc; bool setsrc = false; union g_addr src; @@ -1557,38 +1556,36 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) struct { struct nlmsghdr n; struct rtmsg r; - char buf[NL_PKT_BUF_SIZE]; - } req; + char buf[]; + } *req = (void *)data; p = dplane_ctx_get_dest(ctx); src_p = dplane_ctx_get_src(ctx); - family = PREFIX_FAMILY(p); + memset(req, 0, sizeof(*req)); - memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE); - - bytelen = (family == AF_INET ? 4 : 16); + bytelen = (p->family == AF_INET ? 4 : 16); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; if ((cmd == RTM_NEWROUTE) && ((p->family == AF_INET) || v6_rr_semantics)) - req.n.nlmsg_flags |= NLM_F_REPLACE; + req->n.nlmsg_flags |= NLM_F_REPLACE; - req.n.nlmsg_type = cmd; + req->n.nlmsg_type = cmd; - req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; - req.r.rtm_family = family; - req.r.rtm_dst_len = p->prefixlen; - req.r.rtm_src_len = src_p ? src_p->prefixlen : 0; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req->r.rtm_family = p->family; + req->r.rtm_dst_len = p->prefixlen; + req->r.rtm_src_len = src_p ? src_p->prefixlen : 0; + req->r.rtm_scope = RT_SCOPE_UNIVERSE; if (cmd == RTM_DELROUTE) - req.r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx)); + req->r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx)); else - req.r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx)); + req->r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx)); /* * blackhole routes are not RTN_UNICAST, they are @@ -1599,12 +1596,11 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) * the RTM_DELROUTE case */ if (cmd != RTM_DELROUTE) - req.r.rtm_type = RTN_UNICAST; + req->r.rtm_type = RTN_UNICAST; - addattr_l(&req.n, sizeof(req), RTA_DST, &p->u.prefix, bytelen); + addattr_l(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen); if (src_p) - addattr_l(&req.n, sizeof(req), RTA_SRC, &src_p->u.prefix, - bytelen); + addattr_l(&req->n, datalen, RTA_SRC, &src_p->u.prefix, bytelen); /* Metric. */ /* Hardcode the metric for all routes coming from zebra. Metric isn't @@ -1613,7 +1609,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) * path(s) * by the routing protocol and for communicating with protocol peers. */ - addattr32(&req.n, sizeof(req), RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); + addattr32(&req->n, datalen, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); #if defined(SUPPORT_REALMS) { @@ -1625,19 +1621,23 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) tag = dplane_ctx_get_tag(ctx); if (tag > 0 && tag <= 255) - addattr32(&req.n, sizeof(req), RTA_FLOW, tag); + addattr32(&req->n, datalen, RTA_FLOW, tag); } #endif /* Table corresponding to this route. */ table_id = dplane_ctx_get_table(ctx); if (table_id < 256) - req.r.rtm_table = table_id; + req->r.rtm_table = table_id; else { - req.r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&req.n, sizeof(req), RTA_TABLE, table_id); + req->r.rtm_table = RT_TABLE_UNSPEC; + addattr32(&req->n, datalen, RTA_TABLE, table_id); } - _netlink_route_debug(cmd, p, family, dplane_ctx_get_vrf(ctx), table_id); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s: %s %pFX vrf %u(%u)", __func__, + nl_msg_type_to_str(cmd), p, dplane_ctx_get_vrf(ctx), + table_id); /* * If we are not updating the route and we have received @@ -1646,7 +1646,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) * it. */ if (cmd == RTM_DELROUTE) - goto skip; + return req->n.nlmsg_len; if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) { char buf[NL_PKT_BUF_SIZE]; @@ -1660,7 +1660,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) rta->rta_len = RTA_LENGTH(0); rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof(mtu)); - addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA(rta), + addattr_l(&req->n, datalen, RTA_METRICS, RTA_DATA(rta), RTA_PAYLOAD(rta)); } @@ -1670,7 +1670,8 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) zlog_debug( "netlink_route_multipath(): %pFX nhg_id is %u", p, dplane_ctx_get_nhe_id(ctx)); - addattr32(&req.n, sizeof(req), RTA_NH_ID, + + addattr32(&req->n, datalen, RTA_NH_ID, dplane_ctx_get_nhe_id(ctx)); /* Have to determine src still */ @@ -1678,18 +1679,19 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (setsrc) break; - setsrc = nexthop_set_src(nexthop, family, &src); + setsrc = nexthop_set_src(nexthop, p->family, &src); } if (setsrc) { - if (family == AF_INET) - addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + if (p->family == AF_INET) + addattr_l(&req->n, datalen, RTA_PREFSRC, &src.ipv4, bytelen); - else if (family == AF_INET6) - addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + else if (p->family == AF_INET6) + addattr_l(&req->n, datalen, RTA_PREFSRC, &src.ipv6, bytelen); } - goto skip; + + return req->n.nlmsg_len; } /* Count overall nexthops so we can decide whether to use singlepath @@ -1699,7 +1701,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; - if (cmd == RTM_NEWROUTE && !NEXTHOP_IS_ACTIVE(nexthop->flags)) + if (!NEXTHOP_IS_ACTIVE(nexthop->flags)) continue; nexthop_num++; @@ -1719,16 +1721,16 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { switch (nexthop->bh_type) { case BLACKHOLE_ADMINPROHIB: - req.r.rtm_type = RTN_PROHIBIT; + req->r.rtm_type = RTN_PROHIBIT; break; case BLACKHOLE_REJECT: - req.r.rtm_type = RTN_UNREACHABLE; + req->r.rtm_type = RTN_UNREACHABLE; break; default: - req.r.rtm_type = RTN_BLACKHOLE; + req->r.rtm_type = RTN_BLACKHOLE; break; } - goto skip; + return req->n.nlmsg_len; } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { @@ -1736,30 +1738,38 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (setsrc) continue; - setsrc = nexthop_set_src(nexthop, family, &src); - + setsrc = nexthop_set_src(nexthop, p->family, + &src); continue; } - if ((cmd == RTM_NEWROUTE - && NEXTHOP_IS_ACTIVE(nexthop->flags))) { + if (NEXTHOP_IS_ACTIVE(nexthop->flags)) { routedesc = nexthop->rparent ? "recursive, single-path" : "single-path"; _netlink_route_build_singlepath( - p, routedesc, bytelen, nexthop, &req.n, - &req.r, sizeof(req), cmd); + p, routedesc, bytelen, nexthop, &req->n, + &req->r, datalen, cmd); nexthop_num++; break; } + + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) + netlink_route_nexthop_encap(&req->n, datalen, + nexthop); } + if (setsrc) { - if (family == AF_INET) - addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + if (p->family == AF_INET) + addattr_l(&req->n, datalen, RTA_PREFSRC, &src.ipv4, bytelen); - else if (family == AF_INET6) - addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + else if (p->family == AF_INET6) + addattr_l(&req->n, datalen, RTA_PREFSRC, &src.ipv6, bytelen); } } else { /* Multipath case */ @@ -1780,13 +1790,12 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (setsrc) continue; - setsrc = nexthop_set_src(nexthop, family, &src); - + setsrc = nexthop_set_src(nexthop, p->family, + &src); continue; } - if ((cmd == RTM_NEWROUTE - && NEXTHOP_IS_ACTIVE(nexthop->flags))) { + if (NEXTHOP_IS_ACTIVE(nexthop->flags)) { routedesc = nexthop->rparent ? "recursive, multipath" : "multipath"; @@ -1794,47 +1803,51 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) _netlink_route_build_multipath( p, routedesc, bytelen, nexthop, rta, - rtnh, &req.r, &src1); + rtnh, &req->r, &src1); rtnh = RTNH_NEXT(rtnh); if (!setsrc && src1) { - if (family == AF_INET) + if (p->family == AF_INET) src.ipv4 = src1->ipv4; - else if (family == AF_INET6) + else if (p->family == AF_INET6) src.ipv6 = src1->ipv6; setsrc = 1; } } + + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) + netlink_route_nexthop_encap(&req->n, datalen, + nexthop); } + if (setsrc) { - if (family == AF_INET) - addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + if (p->family == AF_INET) + addattr_l(&req->n, datalen, RTA_PREFSRC, &src.ipv4, bytelen); - else if (family == AF_INET6) - addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + else if (p->family == AF_INET6) + addattr_l(&req->n, datalen, RTA_PREFSRC, &src.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Setting source"); } if (rta->rta_len > RTA_LENGTH(0)) - addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, + addattr_l(&req->n, datalen, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta)); } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath(): No useful nexthop."); - return 0; + zlog_debug("%s: No useful nexthop.", __func__); } -skip: - /* Talk to netlink socket. */ - return netlink_talk_info(netlink_talk_filter, &req.n, - dplane_ctx_get_ns(ctx), 0); + return req->n.nlmsg_len; } int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) @@ -1982,6 +1995,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) addattr32(&req.n, req_size, NHA_ID, id); if (cmd == RTM_NEWNEXTHOP) { + /* + * We distinguish between a "group", which is a collection + * of ids, and a singleton nexthop with an id. The + * group is installed as an id that just refers to a list of + * other ids. + */ if (dplane_ctx_get_nhe_nh_grp_count(ctx)) _netlink_nexthop_build_group( &req.n, req_size, id, @@ -2068,14 +2087,13 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) } } - nexthop_done: - if (IS_ZEBRA_DEBUG_KERNEL) { - char buf[NEXTHOP_STRLEN]; +nexthop_done: - snprintfrr(buf, sizeof(buf), "%pNHv", nh); - zlog_debug("%s: ID (%u): %s (%u) %s ", __func__, - id, buf, nh->vrf_id, label_buf); - } + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: ID (%u): %pNHv vrf %s(%u) %s ", + __func__, id, nh, + vrf_id_to_name(nh->vrf_id), + nh->vrf_id, label_buf); } req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx)); @@ -2088,7 +2106,9 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) return -1; } - _netlink_nexthop_debug(cmd, id); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s, id=%u", __func__, nl_msg_type_to_str(cmd), + id); return netlink_talk_info(netlink_talk_filter, &req.n, dplane_ctx_get_ns(ctx), 0); @@ -2103,43 +2123,19 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) */ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) { + enum dplane_op_e op; int cmd = 0; int ret = 0; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_NH_DELETE: - cmd = RTM_DELNEXTHOP; - break; - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: + op = dplane_ctx_get_op(ctx); + if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) cmd = RTM_NEWNEXTHOP; - break; - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_NONE: - flog_err( - EC_ZEBRA_NHG_FIB_UPDATE, - "Context received for kernel nexthop update with incorrect OP code (%u)", - dplane_ctx_get_op(ctx)); + else if (op == DPLANE_OP_NH_DELETE) + cmd = RTM_DELNEXTHOP; + else { + flog_err(EC_ZEBRA_NHG_FIB_UPDATE, + "Context received for kernel nexthop update with incorrect OP code (%u)", + op); return ZEBRA_DPLANE_REQUEST_FAILURE; } @@ -2158,6 +2154,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) int cmd, ret; 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; @@ -2178,9 +2175,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * the kernel the old non-system route */ if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) && - !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) - (void)netlink_route_multipath(RTM_DELROUTE, - ctx); + !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { + netlink_route_multipath(RTM_DELROUTE, ctx, + nl_pkt, sizeof(nl_pkt), + false); + netlink_talk_info(netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); + } } else { /* * So v6 route replace semantics are not in @@ -2194,9 +2196,14 @@ 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))) - (void)netlink_route_multipath(RTM_DELROUTE, - ctx); + if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { + netlink_route_multipath(RTM_DELROUTE, ctx, + nl_pkt, sizeof(nl_pkt), + false); + netlink_talk_info(netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); + } cmd = RTM_NEWROUTE; } @@ -2204,9 +2211,13 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_FAILURE; } - if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) - ret = netlink_route_multipath(cmd, ctx); - else + if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) { + netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), + false); + ret = netlink_talk_info(netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); + } else ret = 0; if ((cmd == RTM_NEWROUTE) && (ret == 0)) { /* Update installed nexthops to signal which have been @@ -2481,7 +2492,7 @@ static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); req.nhm.nh_family = family; - return netlink_request(&zns->netlink_cmd, &req.n); + return netlink_request(&zns->netlink_cmd, &req); } @@ -2528,44 +2539,95 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, addr, lla, llalen, ns_id); } -/* - * 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. +/** + * netlink_update_neigh_ctx_internal() - Common helper api for evpn + * neighbor updates using dataplane context object. + * @ctx: Dataplane context + * @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH) + * @mac: A neighbor cache link layer address + * @ip: A neighbor cache n/w layer destination address + * @replace_obj: Whether NEW request should replace existing object or + * add to the end of the list + * @family: AF_* netlink family + * @type: RTN_* route type + * @flags: NTF_* flags + * @state: NUD_* states + * @data: data buffer pointer + * @datalen: total amount of data buffer space + * + * Return: Result status */ -static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, - int cmd) +static ssize_t +netlink_update_neigh_ctx_internal(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 protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; - char buf[256]; - } req; - uint8_t dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - const struct ipaddr *addr; + char buf[]; + } *req = data; + int ipa_len; + enum dplane_op_e op; - memset(&req, 0, sizeof(req)); + memset(req, 0, datalen); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; + op = dplane_ctx_get_op(ctx); + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req->n.nlmsg_flags = NLM_F_REQUEST; if (cmd == RTM_NEWNEIGH) - req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND); - req.n.nlmsg_type = cmd; - req.ndm.ndm_family = PF_BRIDGE; - req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT; - req.ndm.ndm_flags |= NTF_SELF; /* Handle by "self", not "master" */ + req->n.nlmsg_flags |= + NLM_F_CREATE + | (replace_obj ? NLM_F_REPLACE : NLM_F_APPEND); + req->n.nlmsg_type = cmd; + req->ndm.ndm_family = family; + req->ndm.ndm_type = type; + req->ndm.ndm_state = state; + req->ndm.ndm_flags = flags; + req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); + + addattr_l(&req->n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); + if (mac) + addattr_l(&req->n, datalen, NDA_LLADDR, mac, 6); + ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; + addattr_l(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len); - addattr_l(&req.n, sizeof(req), - NDA_PROTOCOL, &protocol, sizeof(protocol)); - addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6); - req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); + if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) { + vlanid_t vid = dplane_ctx_mac_get_vlan(ctx); - addr = dplane_ctx_neigh_get_ipaddr(ctx); + if (vid > 0) + addattr16(&req->n, datalen, NDA_VLAN, vid); - addattr_l(&req.n, sizeof(req), NDA_DST, &(addr->ipaddr_v4), 4); + addattr32(&req->n, datalen, NDA_MASTER, + dplane_ctx_mac_get_br_ifindex(ctx)); + } - return netlink_talk_info(netlink_talk_filter, &req.n, + return NLMSG_ALIGN(req->n.nlmsg_len); +} + +/* + * 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) +{ + struct ethaddr dst_mac = {.octet = {0}}; + uint8_t nl_pkt[NL_PKT_BUF_SIZE]; + + netlink_update_neigh_ctx_internal( + 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)); + + return netlink_talk_info(netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, dplane_ctx_get_ns(ctx), 0); } @@ -2760,7 +2822,7 @@ static int netlink_request_macs(struct nlsock *netlink_cmd, int family, if (master_ifindex) addattr32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex); - return netlink_request(netlink_cmd, &req.n); + return netlink_request(netlink_cmd, &req); } /* @@ -2856,12 +2918,14 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: Tx family %s IF %s(%u) MAC %s vid %u", __func__, - nl_family_to_str(req.ndm.ndm_family), br_if->name, - br_if->ifindex, - prefix_mac2str(mac, buf, sizeof(buf)), vid); + zlog_debug( + "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %s vid %u", + __func__, nl_family_to_str(req.ndm.ndm_family), + br_if->name, br_if->ifindex, + vrf_id_to_name(br_if->vrf_id), br_if->vrf_id, + prefix_mac2str(mac, buf, sizeof(buf)), vid); - return netlink_request(&zns->netlink_cmd, &req.n); + return netlink_request(&zns->netlink_cmd, &req); } int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, @@ -2890,92 +2954,60 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, /* * Netlink-specific handler for MAC updates using dataplane context object. */ -static enum zebra_dplane_result -netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) +ssize_t +netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, + size_t datalen) { - uint8_t protocol = RTPROT_ZEBRA; - struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - int ret; - int dst_alen; - int vid_present = 0; - int cmd; - struct in_addr vtep_ip; + struct ipaddr vtep_ip; vlanid_t vid; + ssize_t total; + int cmd; + uint8_t flags; + uint16_t state; + uint8_t nl_pkt[NL_PKT_BUF_SIZE]; - if (dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL) - cmd = RTM_NEWNEIGH; - else - cmd = RTM_DELNEIGH; - - memset(&req, 0, sizeof(req)); + cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL + ? RTM_NEWNEIGH : RTM_DELNEIGH; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - if (cmd == RTM_NEWNEIGH) - req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); - req.n.nlmsg_type = cmd; - req.ndm.ndm_family = AF_BRIDGE; - req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; - req.ndm.ndm_state = NUD_REACHABLE; + flags = (NTF_SELF | NTF_MASTER); + state = NUD_REACHABLE; if (dplane_ctx_mac_is_sticky(ctx)) - req.ndm.ndm_state |= NUD_NOARP; + state |= NUD_NOARP; else - req.ndm.ndm_flags |= NTF_EXT_LEARNED; - - addattr_l(&req.n, sizeof(req), - NDA_PROTOCOL, &protocol, sizeof(protocol)); - addattr_l(&req.n, sizeof(req), NDA_LLADDR, - dplane_ctx_mac_get_addr(ctx), 6); - req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); - - 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); + flags |= NTF_EXT_LEARNED; - vid = dplane_ctx_mac_get_vlan(ctx); - - if (vid > 0) { - addattr16(&req.n, sizeof(req), NDA_VLAN, vid); - vid_present = 1; - } - addattr32(&req.n, sizeof(req), NDA_MASTER, - dplane_ctx_mac_get_br_ifindex(ctx)); + vtep_ip.ipaddr_v4 = *(dplane_ctx_mac_get_vtep_ip(ctx)); + SET_IPADDR_V4(&vtep_ip); if (IS_ZEBRA_DEBUG_KERNEL) { char ipbuf[PREFIX_STRLEN]; char buf[ETHER_ADDR_STRLEN]; - char dst_buf[PREFIX_STRLEN + 10]; char vid_buf[20]; - if (vid_present) + vid = dplane_ctx_mac_get_vlan(ctx); + if (vid > 0) snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid); else vid_buf[0] = '\0'; - 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)); + const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx); - 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), + zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %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 " : "", - buf, dst_buf); + prefix_mac2str(mac, buf, sizeof(buf)), + ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf))); } - 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; + total = netlink_update_neigh_ctx_internal( + ctx, cmd, dplane_ctx_mac_get_addr(ctx), + dplane_ctx_neigh_get_ipaddr(ctx), true, AF_BRIDGE, 0, + flags, state, nl_pkt, sizeof(nl_pkt)); + + return total; } /* @@ -3017,6 +3049,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) struct interface *link_if; struct ethaddr mac; struct ipaddr ip; + struct vrf *vrf; char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; int mac_present = 0; @@ -3031,6 +3064,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (!ifp || !ifp->info) return 0; + vrf = vrf_lookup_by_id(ifp->vrf_id); zif = (struct zebra_if *)ifp->info; /* Parse attributes and extract fields of interest. */ @@ -3038,10 +3072,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); if (!tb[NDA_DST]) { - zlog_debug("%s family %s IF %s(%u) - no DST", + zlog_debug("%s family %s IF %s(%u) vrf %s(%u) - no DST", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex); + ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id); return 0; } @@ -3093,12 +3127,13 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu", + "%s family %s IF %s(%u) vrf %s(%u) - LLADDR is not MAC, len %lu", nl_msg_type_to_str( h->nlmsg_type), nl_family_to_str( ndm->ndm_family), ifp->name, ndm->ndm_ifindex, + VRF_LOGNAME(vrf), ifp->vrf_id, (unsigned long)RTA_PAYLOAD( tb[NDA_LLADDR])); return 0; @@ -3113,10 +3148,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x", + "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, + ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id, ipaddr2str(&ip, buf2, sizeof(buf2)), mac_present ? prefix_mac2str(&mac, buf, sizeof(buf)) @@ -3138,10 +3173,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Rx %s family %s IF %s(%u) IP %s", + zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %s", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, + ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id, ipaddr2str(&ip, buf2, sizeof(buf2))); /* Process the delete - it may result in re-adding the neighbor if it is @@ -3190,7 +3225,7 @@ static int netlink_request_neigh(struct nlsock *netlink_cmd, int family, if (ifindex) addattr32(&req.n, sizeof(req), NDA_IFINDEX, ifindex); - return netlink_request(netlink_cmd, &req.n); + return netlink_request(netlink_cmd, &req); } /* @@ -3278,7 +3313,7 @@ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, ipaddr2str(ip, buf, sizeof(buf)), req.n.nlmsg_flags); } - return netlink_request(&zns->netlink_cmd, &req.n); + return netlink_request(&zns->netlink_cmd, &req); } int netlink_neigh_read_specific_ip(struct ipaddr *ip, @@ -3295,9 +3330,10 @@ int netlink_neigh_read_specific_ip(struct ipaddr *ip, zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: neigh request IF %s(%u) IP %s vrf_id %u", + zlog_debug("%s: neigh request IF %s(%u) IP %s vrf %s(%u)", __func__, vlan_if->name, vlan_if->ifindex, - ipaddr2str(ip, buf, sizeof(buf)), vlan_if->vrf_id); + ipaddr2str(ip, buf, sizeof(buf)), + vrf_id_to_name(vlan_if->vrf_id), vlan_if->vrf_id); ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip, vlan_if->ifindex); @@ -3355,21 +3391,12 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { - uint8_t protocol = RTPROT_ZEBRA; - struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - int ipa_len; - char buf[INET6_ADDRSTRLEN]; - char buf2[ETHER_ADDR_STRLEN]; const struct ipaddr *ip; const struct ethaddr *mac; uint8_t flags; uint16_t state; - - memset(&req, 0, sizeof(req)); + 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); @@ -3379,36 +3406,26 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx)); state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - if (cmd == RTM_NEWNEIGH) - req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); - req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH - req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; - req.ndm.ndm_state = state; - req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); - req.ndm.ndm_type = RTN_UNICAST; - req.ndm.ndm_flags = flags; + family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; - addattr_l(&req.n, sizeof(req), - NDA_PROTOCOL, &protocol, sizeof(protocol)); - ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; - addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); - if (mac) - addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + if (IS_ZEBRA_DEBUG_KERNEL) { + char buf[INET6_ADDRSTRLEN]; + char buf2[ETHER_ADDR_STRLEN]; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x", - nl_msg_type_to_str(cmd), - nl_family_to_str(req.ndm.ndm_family), - dplane_ctx_get_ifname(ctx), - dplane_ctx_get_ifindex(ctx), - ipaddr2str(ip, buf, sizeof(buf)), - mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) - : "null", - flags, state); + zlog_debug( + "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x", + nl_msg_type_to_str(cmd), nl_family_to_str(family), + dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx), + ipaddr2str(ip, buf, sizeof(buf)), + mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) : "null", + flags, state); + } - return netlink_talk_info(netlink_talk_filter, &req.n, + netlink_update_neigh_ctx_internal( + ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, + state, nl_pkt, sizeof(nl_pkt)); + + return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, dplane_ctx_get_ns(ctx), 0); } @@ -3417,7 +3434,18 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, */ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) { - return netlink_macfdb_update_ctx(ctx); + 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) |
