return 0;
}
-static void _netlink_route_add_gateway_info(uint8_t route_family,
+/*
+ * The function returns true if the gateway info could be added
+ * to the message, otherwise false is returned.
+ */
+static bool _netlink_route_add_gateway_info(uint8_t route_family,
uint8_t gw_family,
struct nlmsghdr *nlmsg,
size_t req_size, int bytelen,
memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen);
else
memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen);
- nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family,
- bytelen + 2);
+ if (!nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family,
+ bytelen + 2))
+ return false;
} else {
- if (gw_family == AF_INET)
- nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
- &nexthop->gate.ipv4, bytelen);
- else
- nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
- &nexthop->gate.ipv6, bytelen);
+ 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;
+ }
}
+
+ return true;
}
static int build_label_stack(struct mpls_label_stack *nh_label,
* @param nexthop: Nexthop information
* @param nlmsg: nlmsghdr structure to fill in.
* @param req_size: The size allocated for the message.
+ *
+ * The function returns true if the nexthop could be added
+ * to the message, otherwise false is returned.
*/
-static void _netlink_route_build_singlepath(const struct prefix *p,
+static bool _netlink_route_build_singlepath(const struct prefix *p,
const char *routedesc, int bytelen,
const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
/* Set the BoS bit */
out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
- if (rtmsg->rtm_family == AF_MPLS)
- nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
- num_labels * sizeof(mpls_lse_t));
- else {
+ if (rtmsg->rtm_family == AF_MPLS) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
+ num_labels * sizeof(mpls_lse_t)))
+ return false;
+ } else {
struct rtattr *nest;
uint16_t encap = LWTUNNEL_ENCAP_MPLS;
- nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
- sizeof(uint16_t));
+ if (!nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE,
+ &encap, sizeof(uint16_t)))
+ return false;
+
nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
- nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
- &out_lse, num_labels * sizeof(mpls_lse_t));
+ if (!nest)
+ return false;
+
+ if (!nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
+ &out_lse,
+ num_labels * sizeof(mpls_lse_t)))
+ return false;
nl_attr_nest_end(nlmsg, nest);
}
}
if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
rtmsg->rtm_flags |= RTNH_F_ONLINK;
- nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4);
- nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
+ if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4))
+ return false;
+ if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
+ return false;
if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY
- && (cmd == RTM_NEWROUTE))
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->rmap_src.ipv4, bytelen);
- else if (nexthop->src.ipv4.s_addr != INADDR_ANY
- && (cmd == RTM_NEWROUTE))
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->src.ipv4, bytelen);
+ && (cmd == RTM_NEWROUTE)) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->rmap_src.ipv4, bytelen))
+ return false;
+ } else if (nexthop->src.ipv4.s_addr != INADDR_ANY
+ && (cmd == RTM_NEWROUTE)) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen))
+ return false;
+ }
if (IS_ZEBRA_DEBUG_KERNEL)
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;
+ return true;
}
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
/* Send deletes to the kernel without specifying the next-hop */
- if (cmd != RTM_DELROUTE)
- _netlink_route_add_gateway_info(
- rtmsg->rtm_family, AF_INET, nlmsg, req_size,
- bytelen, nexthop);
+ if (cmd != RTM_DELROUTE) {
+ if (!_netlink_route_add_gateway_info(
+ rtmsg->rtm_family, AF_INET, nlmsg, req_size,
+ bytelen, nexthop))
+ return false;
+ }
if (cmd == RTM_NEWROUTE) {
- if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->rmap_src.ipv4, bytelen);
- else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->src.ipv4, bytelen);
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->rmap_src.ipv4,
+ bytelen))
+ return false;
+ } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen))
+ return false;
+ }
}
if (IS_ZEBRA_DEBUG_KERNEL) {
if (nexthop->type == NEXTHOP_TYPE_IPV6
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
- _netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET6,
- nlmsg, req_size, bytelen,
- nexthop);
+ if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
+ AF_INET6, nlmsg, req_size,
+ bytelen, nexthop))
+ return false;
if (cmd == RTM_NEWROUTE) {
- if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->rmap_src.ipv6, bytelen);
- else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->src.ipv6, bytelen);
+ if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->rmap_src.ipv6,
+ bytelen))
+ return false;
+ } else if (!IN6_IS_ADDR_UNSPECIFIED(
+ &nexthop->src.ipv6)) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->src.ipv6, bytelen))
+ return false;
+ }
}
if (IS_ZEBRA_DEBUG_KERNEL) {
* This is especially useful if we are doing route
* leaking.
*/
- if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
- nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
+ if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
+ if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
+ return false;
+ }
if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
if (cmd == RTM_NEWROUTE) {
- if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->rmap_src.ipv4, bytelen);
- else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
- nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->src.ipv4, bytelen);
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->rmap_src.ipv4,
+ bytelen))
+ return false;
+ } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen))
+ return false;
+ }
}
if (IS_ZEBRA_DEBUG_KERNEL)
__func__, routedesc, p, nexthop->ifindex,
VRF_LOGNAME(vrf), nexthop->vrf_id);
}
+
+ return true;
}
/* This function takes a nexthop as argument and
* @param req_size: The size allocated for the message.
* @param src: pointer pointing to a location where
* the prefsrc should be stored.
+ *
+ * The function returns true if the nexthop could be added
+ * to the message, otherwise false is returned.
*/
-static void _netlink_route_build_multipath(const struct prefix *p,
+static bool _netlink_route_build_multipath(const struct prefix *p,
const char *routedesc, int bytelen,
const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
struct rtnexthop *rtnh;
rtnh = nl_attr_rtnh(nlmsg, req_size);
+ if (rtnh == NULL)
+ return false;
assert(nexthop);
out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
if (rtmsg->rtm_family == AF_MPLS) {
- nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
- num_labels * sizeof(mpls_lse_t));
+ if (!nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
+ num_labels * sizeof(mpls_lse_t)))
+ return false;
} else {
struct rtattr *nest;
uint16_t encap = LWTUNNEL_ENCAP_MPLS;
- nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
- sizeof(uint16_t));
+ if (!nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE,
+ &encap, sizeof(uint16_t)))
+ return false;
+
nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
- nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
- &out_lse, num_labels * sizeof(mpls_lse_t));
+ if (nest == NULL)
+ return false;
+
+ if (!nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
+ &out_lse,
+ num_labels * sizeof(mpls_lse_t)))
+ return false;
nl_attr_nest_end(nlmsg, nest);
}
}
if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
bytelen = 4;
rtnh->rtnh_flags |= RTNH_F_ONLINK;
- nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, bytelen);
+ if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll,
+ bytelen))
+ return false;
rtnh->rtnh_ifindex = nexthop->ifindex;
if (nexthop->weight)
rtnh->rtnh_hops = nexthop->weight - 1;
nexthop->ifindex, VRF_LOGNAME(vrf),
nexthop->vrf_id);
nl_attr_rtnh_end(nlmsg, rtnh);
- return;
+ return true;
}
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
- _netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET,
- nlmsg, req_size, bytelen,
- nexthop);
+ if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET,
+ nlmsg, req_size, bytelen,
+ nexthop))
+ return false;
+
if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->rmap_src;
else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
}
if (nexthop->type == NEXTHOP_TYPE_IPV6
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
- _netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET6,
- nlmsg, req_size, bytelen,
- nexthop);
+ if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
+ AF_INET6, nlmsg, req_size,
+ bytelen, nexthop))
+ return false;
if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
*src = &nexthop->rmap_src;
if (nexthop->weight)
rtnh->rtnh_hops = nexthop->weight - 1;
+
nl_attr_rtnh_end(nlmsg, rtnh);
+ return true;
}
-static inline void _netlink_mpls_build_singlepath(const struct prefix *p,
+static inline bool _netlink_mpls_build_singlepath(const struct prefix *p,
const char *routedesc,
const zebra_nhlfe_t *nhlfe,
struct nlmsghdr *nlmsg,
family = NHLFE_FAMILY(nhlfe);
bytelen = (family == AF_INET ? 4 : 16);
- _netlink_route_build_singlepath(p, routedesc, bytelen, nhlfe->nexthop,
- nlmsg, rtmsg, req_size, cmd);
+ return _netlink_route_build_singlepath(p, routedesc, bytelen,
+ nhlfe->nexthop, nlmsg, rtmsg,
+ req_size, cmd);
}
-static inline void
+static inline bool
_netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
const zebra_nhlfe_t *nhlfe,
struct nlmsghdr *nlmsg, size_t req_size,
family = NHLFE_FAMILY(nhlfe);
bytelen = (family == AF_INET ? 4 : 16);
- _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop,
- nlmsg, req_size, rtmsg, src);
+ return _netlink_route_build_multipath(p, routedesc, bytelen,
+ nhlfe->nexthop, nlmsg, req_size,
+ rtmsg, src);
}
static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
{
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("netlink_mpls_multipath() (%s): %s %u/20", routedesc,
- nl_msg_type_to_str(cmd), label);
+ zlog_debug("netlink_mpls_multipath_msg_encode() (%s): %s %u/20",
+ routedesc, nl_msg_type_to_str(cmd), label);
}
static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
return false;
}
-static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
- struct nexthop *nh)
+/*
+ * The function returns true if the attribute could be added
+ * to the message, otherwise false is returned.
+ */
+static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
+ struct nexthop *nh)
{
struct rtattr *nest;
switch (nh->nh_encap_type) {
case NET_VXLAN:
- nl_attr_put(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type,
- sizeof(uint16_t));
+ if (!nl_attr_put(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type,
+ sizeof(uint16_t)))
+ return false;
nest = nl_attr_nest(n, nlen, RTA_ENCAP);
- nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni);
+ if (!nest)
+ return false;
+
+ if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */,
+ nh->nh_encap.vni))
+ return false;
nl_attr_nest_end(n, nest);
break;
}
+
+ return true;
}
/*
* Routing table change via netlink interface, using a dataplane context object
+ *
+ * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
+ * otherwise the number of bytes written to buf.
*/
-ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
- uint8_t *data, size_t datalen, bool fpm,
- bool force_nhg)
+ssize_t netlink_route_multipath_msg_encode(int cmd,
+ struct zebra_dplane_ctx *ctx,
+ uint8_t *data, size_t datalen,
+ bool fpm, bool force_nhg)
{
int bytelen;
struct nexthop *nexthop = NULL;
p = dplane_ctx_get_dest(ctx);
src_p = dplane_ctx_get_src(ctx);
+ if (datalen < sizeof(*req))
+ return 0;
+
memset(req, 0, sizeof(*req));
bytelen = (p->family == AF_INET ? 4 : 16);
if (cmd != RTM_DELROUTE)
req->r.rtm_type = RTN_UNICAST;
- nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen);
- if (src_p)
- nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix,
- bytelen);
+ if (!nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen))
+ return 0;
+ if (src_p) {
+ if (!nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix,
+ bytelen))
+ return 0;
+ }
/* Metric. */
/* Hardcode the metric for all routes coming from zebra. Metric isn't
* path(s)
* by the routing protocol and for communicating with protocol peers.
*/
- nl_attr_put32(&req->n, datalen, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
+ if (!nl_attr_put32(&req->n, datalen, RTA_PRIORITY,
+ NL_DEFAULT_ROUTE_METRIC))
+ return 0;
#if defined(SUPPORT_REALMS)
{
else
tag = dplane_ctx_get_tag(ctx);
- if (tag > 0 && tag <= 255)
- nl_attr_put32(&req->n, datalen, RTA_FLOW, tag);
+ if (tag > 0 && tag <= 255) {
+ if (!nl_attr_put32(&req->n, datalen, RTA_FLOW, tag))
+ return 0;
+ }
}
#endif
/* Table corresponding to this route. */
req->r.rtm_table = table_id;
else {
req->r.rtm_table = RT_TABLE_UNSPEC;
- nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id);
+ if (!nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id))
+ return 0;
}
if (IS_ZEBRA_DEBUG_KERNEL)
* it.
*/
if (cmd == RTM_DELROUTE)
- return req->n.nlmsg_len;
+ return NLMSG_ALIGN(req->n.nlmsg_len);
if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) {
struct rtattr *nest;
mtu = nexthop_mtu;
nest = nl_attr_nest(&req->n, datalen, RTA_METRICS);
- nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu));
+ if (nest == NULL)
+ return 0;
+
+ if (!nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu)))
+ return 0;
nl_attr_nest_end(&req->n, nest);
}
if (kernel_nexthops_supported() || force_nhg) {
/* Kernel supports nexthop objects */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath(): %pFX nhg_id is %u",
- p, dplane_ctx_get_nhe_id(ctx));
+ zlog_debug("%s: %pFX nhg_id is %u", __func__, p,
+ dplane_ctx_get_nhe_id(ctx));
- nl_attr_put32(&req->n, datalen, RTA_NH_ID,
- dplane_ctx_get_nhe_id(ctx));
+ if (!nl_attr_put32(&req->n, datalen, RTA_NH_ID,
+ dplane_ctx_get_nhe_id(ctx)))
+ return 0;
/* Have to determine src still */
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
}
if (setsrc) {
- if (p->family == AF_INET)
- nl_attr_put(&req->n, datalen, RTA_PREFSRC,
- &src.ipv4, bytelen);
- else if (p->family == AF_INET6)
- nl_attr_put(&req->n, datalen, RTA_PREFSRC,
- &src.ipv6, bytelen);
+ if (p->family == AF_INET) {
+ if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+ &src.ipv4, bytelen))
+ return 0;
+ } else if (p->family == AF_INET6) {
+ if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+ &src.ipv6, bytelen))
+ return 0;
+ }
}
- return req->n.nlmsg_len;
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
/* Count overall nexthops so we can decide whether to use singlepath
req->r.rtm_type = RTN_BLACKHOLE;
break;
}
- return req->n.nlmsg_len;
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE)) {
? "recursive, single-path"
: "single-path";
- _netlink_route_build_singlepath(
- p, routedesc, bytelen, nexthop, &req->n,
- &req->r, datalen, cmd);
+ if (!_netlink_route_build_singlepath(
+ p, routedesc, bytelen, nexthop,
+ &req->n, &req->r, datalen, cmd))
+ return 0;
nexthop_num++;
break;
}
* Add encapsulation information when installing via
* FPM.
*/
- if (fpm)
- netlink_route_nexthop_encap(&req->n, datalen,
- nexthop);
+ if (fpm) {
+ if (!netlink_route_nexthop_encap(
+ &req->n, datalen, nexthop))
+ return 0;
+ }
}
if (setsrc) {
- if (p->family == AF_INET)
- nl_attr_put(&req->n, datalen, RTA_PREFSRC,
- &src.ipv4, bytelen);
- else if (p->family == AF_INET6)
- nl_attr_put(&req->n, datalen, RTA_PREFSRC,
- &src.ipv6, bytelen);
+ if (p->family == AF_INET) {
+ if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+ &src.ipv4, bytelen))
+ return 0;
+ } else if (p->family == AF_INET6) {
+ if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+ &src.ipv6, bytelen))
+ return 0;
+ }
}
} else { /* Multipath case */
struct rtattr *nest;
const union g_addr *src1 = NULL;
nest = nl_attr_nest(&req->n, datalen, RTA_MULTIPATH);
+ if (nest == NULL)
+ return 0;
nexthop_num = 0;
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
: "multipath";
nexthop_num++;
- _netlink_route_build_multipath(
- p, routedesc, bytelen, nexthop, &req->n,
- datalen, &req->r, &src1);
+ if (!_netlink_route_build_multipath(
+ p, routedesc, bytelen, nexthop,
+ &req->n, datalen, &req->r, &src1))
+ return 0;
if (!setsrc && src1) {
if (p->family == AF_INET)
}
}
}
+
nl_attr_nest_end(&req->n, nest);
/*
if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE))
continue;
-
- netlink_route_nexthop_encap(&req->n, datalen,
- nexthop);
+ if (!netlink_route_nexthop_encap(
+ &req->n, datalen, nexthop))
+ return 0;
}
}
if (setsrc) {
- if (p->family == AF_INET)
- nl_attr_put(&req->n, datalen, RTA_PREFSRC,
- &src.ipv4, bytelen);
- else if (p->family == AF_INET6)
- nl_attr_put(&req->n, datalen, RTA_PREFSRC,
- &src.ipv6, bytelen);
+ if (p->family == AF_INET) {
+ if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+ &src.ipv4, bytelen))
+ return 0;
+ } else if (p->family == AF_INET6) {
+ if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+ &src.ipv6, bytelen))
+ return 0;
+ }
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Setting source");
}
/* Char length to debug ID with */
#define ID_LENGTH 10
-static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
+static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
uint32_t id,
const struct nh_grp *z_grp,
const uint8_t count)
}
}
}
- nl_attr_put(n, req_size, NHA_GROUP, grp, count * sizeof(*grp));
+ if (!nl_attr_put(n, req_size, NHA_GROUP, grp,
+ count * sizeof(*grp)))
+ return false;
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: ID (%u): %s", __func__, id, buf);
+
+ return true;
}
/**
* \param[out] buf buffer to hold the packet.
* \param[in] buflen amount of buffer bytes.
*
- * \returns -1 on failure or the number of bytes written to buf.
+ * \returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
+ * otherwise the number of bytes written to buf.
*/
-ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
- void *buf, size_t buflen)
+ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
+ const struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
{
struct {
struct nlmsghdr n;
label_buf[0] = '\0';
- memset(req, 0, buflen);
+ if (buflen < sizeof(*req))
+ return 0;
+
+ memset(req, 0, sizeof(*req));
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
return -1;
}
- nl_attr_put32(&req->n, buflen, NHA_ID, id);
+ if (!nl_attr_put32(&req->n, buflen, NHA_ID, id))
+ return 0;
if (cmd == RTM_NEWNEXTHOP) {
/*
* 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, buflen, id,
- dplane_ctx_get_nhe_nh_grp(ctx),
- dplane_ctx_get_nhe_nh_grp_count(ctx));
- else {
+ if (dplane_ctx_get_nhe_nh_grp_count(ctx)) {
+ if (_netlink_nexthop_build_group(
+ &req->n, buflen, id,
+ dplane_ctx_get_nhe_nh_grp(ctx),
+ dplane_ctx_get_nhe_nh_grp_count(ctx)))
+ return 0;
+ } else {
const struct nexthop *nh =
dplane_ctx_get_nhe_ng(ctx)->nexthop;
afi_t afi = dplane_ctx_get_nhe_afi(ctx);
switch (nh->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- nl_attr_put(&req->n, buflen, NHA_GATEWAY,
- &nh->gate.ipv4, IPV4_MAX_BYTELEN);
+ if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
+ &nh->gate.ipv4,
+ IPV4_MAX_BYTELEN))
+ return 0;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- nl_attr_put(&req->n, buflen, NHA_GATEWAY,
- &nh->gate.ipv6, IPV6_MAX_BYTELEN);
+ if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
+ &nh->gate.ipv6,
+ IPV6_MAX_BYTELEN))
+ return 0;
break;
case NEXTHOP_TYPE_BLACKHOLE:
- nl_attr_put(&req->n, buflen, NHA_BLACKHOLE,
- NULL, 0);
+ if (!nl_attr_put(&req->n, buflen, NHA_BLACKHOLE,
+ NULL, 0))
+ return 0;
/* Blackhole shouldn't have anymore attributes
*/
goto nexthop_done;
return -1;
}
- nl_attr_put32(&req->n, buflen, NHA_OIF, nh->ifindex);
+ if (!nl_attr_put32(&req->n, buflen, NHA_OIF,
+ nh->ifindex))
+ return 0;
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
req->nhm.nh_flags |= RTNH_F_ONLINK;
if (req->nhm.nh_family == AF_MPLS)
goto nexthop_done;
#if 0
- nl_attr_put(&req->n, buflen, NHA_NEWDST,
+ if (!nl_attr_put(&req->n, buflen, NHA_NEWDST,
&out_lse,
num_labels
- * sizeof(mpls_lse_t));
+ * sizeof(mpls_lse_t)))
+ return 0;
#endif
else {
struct rtattr *nest;
uint16_t encap = LWTUNNEL_ENCAP_MPLS;
- nl_attr_put(&req->n, buflen,
- NHA_ENCAP_TYPE, &encap,
- sizeof(uint16_t));
+ if (!nl_attr_put(&req->n, buflen,
+ NHA_ENCAP_TYPE, &encap,
+ sizeof(uint16_t)))
+ return 0;
nest = nl_attr_nest(&req->n, buflen,
NHA_ENCAP);
- nl_attr_put(
- &req->n, buflen,
- MPLS_IPTUNNEL_DST, &out_lse,
- num_labels
- * sizeof(mpls_lse_t));
+ if (!nest)
+ return 0;
+ if (!nl_attr_put(
+ &req->n, buflen,
+ MPLS_IPTUNNEL_DST, &out_lse,
+ num_labels
+ * sizeof(
+ mpls_lse_t)))
+ return 0;
nl_attr_nest_end(&req->n, nest);
}
}
__func__, id, nh, nh->ifindex,
vrf_id_to_name(nh->vrf_id),
nh->vrf_id, label_buf);
- }
+}
req->nhm.nh_protocol =
zebra2proto(dplane_ctx_get_nhe_type(ctx));
if (!kernel_nexthops_supported())
return ZEBRA_DPLANE_REQUEST_SUCCESS;
- if (netlink_nexthop_encode(cmd, ctx, buf, sizeof(buf)) > 0)
+ 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
*/
if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) &&
!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
- netlink_route_multipath(RTM_DELROUTE, ctx,
- nl_pkt, sizeof(nl_pkt),
- false, false);
- netlink_talk_info(netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
+ 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);
}
} else {
/*
* screwed.
*/
if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
- netlink_route_multipath(RTM_DELROUTE, ctx,
- nl_pkt, sizeof(nl_pkt),
- false, false);
- netlink_talk_info(netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
+ 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_type(ctx))) {
- netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), false,
- false);
- ret = netlink_talk_info(netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
+ 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;
+
} else
ret = 0;
if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
}
/**
- * netlink_update_neigh_ctx_internal() - Common helper api for evpn
- * neighbor updates using dataplane context object.
+ * netlink_neigh_update_msg_encode() - Common helper api for encoding
+ * evpn neighbor update as netlink messages using dataplane context object.
* Here, a neighbor refers to a bridge forwarding database entry for
* either unicast forwarding or head-end replication or an IP neighbor
* entry.
* @data: data buffer pointer
* @datalen: total amount of data buffer space
*
- * Return: Result status
+ * Return: 0 when the msg doesn't fit entirely in the buffer
+ * otherwise the number of bytes written to buf.
*/
-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)
+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 protocol = RTPROT_ZEBRA;
struct {
int ipa_len;
enum dplane_op_e op;
+ if (datalen < sizeof(*req))
+ return 0;
memset(req, 0, datalen);
op = dplane_ctx_get_op(ctx);
req->ndm.ndm_flags = flags;
req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
- nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol,
- sizeof(protocol));
- if (mac)
- nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6);
+ if (!nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol,
+ sizeof(protocol)))
+ return 0;
+
+ if (mac) {
+ if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6))
+ return 0;
+ }
ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
- nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len);
+ if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len))
+ return 0;
if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
- if (vid > 0)
- nl_attr_put16(&req->n, datalen, NDA_VLAN, vid);
+ if (vid > 0) {
+ if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid))
+ return 0;
+ }
- nl_attr_put32(&req->n, datalen, NDA_MASTER,
- dplane_ctx_mac_get_br_ifindex(ctx));
+ if (!nl_attr_put32(&req->n, datalen, NDA_MASTER,
+ dplane_ctx_mac_get_br_ifindex(ctx)))
+ return 0;
}
return NLMSG_ALIGN(req->n.nlmsg_len);
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));
+ 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,
ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)));
}
- total = netlink_update_neigh_ctx_internal(
- ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip,
- true, AF_BRIDGE, 0, flags, state, data, datalen);
+ total = netlink_neigh_update_msg_encode(
+ ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true,
+ AF_BRIDGE, 0, flags, state, data, datalen);
return total;
}
flags, state);
}
- netlink_update_neigh_ctx_internal(
- ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags,
- state, nl_pkt, sizeof(nl_pkt));
+ 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);
* MPLS label forwarding table change via netlink interface, using dataplane
* context information.
*/
-int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
+ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
{
mpls_lse_t lse;
const struct nhlfe_list_head *head;
struct {
struct nlmsghdr n;
struct rtmsg r;
- char buf[NL_PKT_BUF_SIZE];
- } req;
+ char buf[0];
+ } *req = buf;
+
+ if (buflen < sizeof(*req))
+ return 0;
- memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
+ memset(req, 0, sizeof(*req));
/*
* Count # nexthops so we can decide whether to use singlepath
(!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE)))
return 0;
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
- req.n.nlmsg_type = cmd;
- req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req->n.nlmsg_type = cmd;
+ req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
- req.r.rtm_family = AF_MPLS;
- req.r.rtm_table = RT_TABLE_MAIN;
- req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
- req.r.rtm_type = RTN_UNICAST;
+ req->r.rtm_family = AF_MPLS;
+ req->r.rtm_table = RT_TABLE_MAIN;
+ req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
+ req->r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req->r.rtm_type = RTN_UNICAST;
if (cmd == RTM_NEWROUTE) {
/* We do a replace to handle update. */
- req.n.nlmsg_flags |= NLM_F_REPLACE;
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
/* set the protocol value if installing */
route_type = re_type_from_lsp_type(
dplane_ctx_get_best_nhlfe(ctx)->type);
- req.r.rtm_protocol = zebra2proto(route_type);
+ req->r.rtm_protocol = zebra2proto(route_type);
}
/* Fill destination */
lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1);
- nl_attr_put(&req.n, sizeof(req), RTA_DST, &lse, sizeof(mpls_lse_t));
+ if (!nl_attr_put(&req->n, buflen, RTA_DST, &lse, sizeof(mpls_lse_t)))
+ return 0;
/* Fill nexthops (paths) based on single-path or multipath. The paths
* chosen depend on the operation.
&& CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_FIB)))) {
/* Add the gateway */
- _netlink_mpls_build_singlepath(
- &p, routedesc, nhlfe, &req.n, &req.r,
- sizeof(req), cmd);
+ if (!_netlink_mpls_build_singlepath(
+ &p, routedesc, nhlfe, &req->n,
+ &req->r, buflen, cmd))
+ return false;
nexthop_num++;
break;
struct rtattr *nest;
const union g_addr *src1 = NULL;
- nest = nl_attr_nest(&req.n, sizeof(req), RTA_MULTIPATH);
+ nest = nl_attr_nest(&req->n, buflen, RTA_MULTIPATH);
+ if (!nest)
+ return 0;
routedesc = "multipath";
_netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
nexthop_num++;
/* Build the multipath */
- _netlink_mpls_build_multipath(
- &p, routedesc, nhlfe, &req.n,
- sizeof(req), &req.r, &src1);
+ if (!_netlink_mpls_build_multipath(
+ &p, routedesc, nhlfe, &req->n,
+ buflen, &req->r, &src1))
+ return 0;
}
}
/* Add the multipath */
- nl_attr_nest_end(&req.n, nest);
+ nl_attr_nest_end(&req->n, nest);
}
- /* Talk to netlink socket. */
- return netlink_talk_info(netlink_talk_filter, &req.n,
- dplane_ctx_get_ns(ctx), 0);
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
#endif /* HAVE_NETLINK */