diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 887 |
1 files changed, 494 insertions, 393 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 095c5570a2..9883e73876 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1029,11 +1029,15 @@ int netlink_route_read(struct zebra_ns *zns) return 0; } -static void _netlink_route_nl_add_gateway_info(uint8_t route_family, - uint8_t gw_family, - struct nlmsghdr *nlmsg, - size_t req_size, int bytelen, - const struct nexthop *nexthop) +/* + * 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, + const struct nexthop *nexthop) { if (route_family == AF_MPLS) { struct gw_family_t gw_fam; @@ -1043,45 +1047,22 @@ static void _netlink_route_nl_add_gateway_info(uint8_t route_family, memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); else memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); - addattr_l(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) - addattr_l(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv4, bytelen); - else - addattr_l(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; + } } -} - -static void _netlink_route_rta_add_gateway_info(uint8_t route_family, - uint8_t gw_family, - struct rtattr *rta, - struct rtnexthop *rtnh, - size_t req_size, int bytelen, - const struct nexthop *nexthop) -{ - if (route_family == AF_MPLS) { - struct gw_family_t gw_fam; - gw_fam.family = gw_family; - if (gw_family == AF_INET) - memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); - else - memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); - rta_addattr_l(rta, req_size, RTA_VIA, &gw_fam.family, - bytelen + 2); - rtnh->rtnh_len += RTA_LENGTH(bytelen + 2); - } else { - if (gw_family == AF_INET) - rta_addattr_l(rta, req_size, RTA_GATEWAY, - &nexthop->gate.ipv4, bytelen); - else - rta_addattr_l(rta, req_size, RTA_GATEWAY, - &nexthop->gate.ipv6, bytelen); - rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; - } + return true; } static int build_label_stack(struct mpls_label_stack *nh_label, @@ -1114,6 +1095,86 @@ static int build_label_stack(struct mpls_label_stack *nh_label, return num_labels; } +static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label, + struct nlmsghdr *nlmsg, + size_t buflen, struct rtmsg *rtmsg, + char *label_buf, + size_t label_buf_size) +{ + mpls_lse_t out_lse[MPLS_MAX_LABELS]; + int num_labels; + + /* + * label_buf is *only* currently used within debugging. + * As such when we assign it we are guarding it inside + * a debug test. If you want to change this make sure + * you fix this assumption + */ + label_buf[0] = '\0'; + + num_labels = + build_label_stack(nh_label, out_lse, label_buf, label_buf_size); + + if (num_labels) { + /* Set the BoS bit */ + out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT); + + if (rtmsg->rtm_family == AF_MPLS) { + if (!nl_attr_put(nlmsg, buflen, RTA_NEWDST, &out_lse, + num_labels * sizeof(mpls_lse_t))) + return false; + } else { + struct rtattr *nest; + + if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_MPLS)) + return false; + + nest = nl_attr_nest(nlmsg, buflen, RTA_ENCAP); + if (!nest) + return false; + + if (!nl_attr_put(nlmsg, buflen, MPLS_IPTUNNEL_DST, + &out_lse, + num_labels * sizeof(mpls_lse_t))) + return false; + nl_attr_nest_end(nlmsg, nest); + } + } + + return true; +} + +static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, + int family, + struct nlmsghdr *nlmsg, + size_t buflen, int bytelen) +{ + if (family == AF_INET) { + if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen)) + return false; + } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen)) + return false; + } + } else if (family == AF_INET6) { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->rmap_src.ipv6, bytelen)) + return false; + } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->src.ipv6, bytelen)) + return false; + } + } + + return true; +} + /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. @@ -1124,8 +1185,11 @@ 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, @@ -1133,9 +1197,7 @@ static void _netlink_route_build_singlepath(const struct prefix *p, size_t req_size, int cmd) { - mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; - int num_labels = 0; struct vrf *vrf; char addrstr[INET6_ADDRSTRLEN]; @@ -1143,77 +1205,49 @@ static void _netlink_route_build_singlepath(const struct prefix *p, 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 - * a debug test. If you want to change this make sure - * you fix this assumption - */ - label_buf[0] = '\0'; - - num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf, - sizeof(label_buf)); - - if (num_labels) { - /* Set the BoS bit */ - out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT); - - if (rtmsg->rtm_family == AF_MPLS) - addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse, - num_labels * sizeof(mpls_lse_t)); - else { - struct rtattr *nest; - uint16_t encap = LWTUNNEL_ENCAP_MPLS; - - addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, &encap, - sizeof(uint16_t)); - nest = addattr_nest(nlmsg, req_size, RTA_ENCAP); - addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, &out_lse, - num_labels * sizeof(mpls_lse_t)); - addattr_nest_end(nlmsg, nest); - } - } + if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg, + req_size, rtmsg, label_buf, + sizeof(label_buf))) + return false; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) { rtmsg->rtm_flags |= RTNH_F_ONLINK; - addattr_l(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4); - addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); - - if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY - && (cmd == RTM_NEWROUTE)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr != INADDR_ANY - && (cmd == RTM_NEWROUTE)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + 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 (cmd == RTM_NEWROUTE) { + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET, nlmsg, req_size, 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_nl_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) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr != INADDR_ANY) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET, nlmsg, req_size, bytelen)) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) { @@ -1228,17 +1262,16 @@ static void _netlink_route_build_singlepath(const struct prefix *p, if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - _netlink_route_nl_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)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv6, bytelen); - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv6, bytelen); + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET6, nlmsg, req_size, + bytelen)) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) { @@ -1256,17 +1289,16 @@ static void _netlink_route_build_singlepath(const struct prefix *p, * This is especially useful if we are doing route * leaking. */ - if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) - addattr32(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) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr != INADDR_ANY) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET, nlmsg, req_size, bytelen)) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) @@ -1274,11 +1306,12 @@ static void _netlink_route_build_singlepath(const struct prefix *p, __func__, routedesc, p, nexthop->ifindex, VRF_LOGNAME(vrf), nexthop->vrf_id); } + + return true; } /* This function takes a nexthop as argument and - * appends to the given rtattr/rtnexthop pair the - * representation of the nexthop. If the nexthop + * appends to the given netlink msg. If the nexthop * defines a preferred source, the src parameter * will be modified to point to that src, otherwise * it will be kept unmodified. @@ -1287,77 +1320,45 @@ static void _netlink_route_build_singlepath(const struct prefix *p, * (direct/recursive, single-/multipath) * @param bytelen: Length of addresses in bytes. * @param nexthop: Nexthop information - * @param rta: rtnetlink attribute structure - * @param rtnh: pointer to an rtnetlink nexthop structure + * @param nlmsg: nlmsghdr structure to fill in. + * @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, const char *routedesc, - int bytelen, const struct nexthop *nexthop, - struct rtattr *rta, struct rtnexthop *rtnh, - struct rtmsg *rtmsg, const union g_addr **src) +static bool _netlink_route_build_multipath(const struct prefix *p, + const char *routedesc, int bytelen, + const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, + size_t req_size, struct rtmsg *rtmsg, + const union g_addr **src) { - mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; - int num_labels = 0; struct vrf *vrf; + struct rtnexthop *rtnh; - rtnh->rtnh_len = sizeof(*rtnh); - rtnh->rtnh_flags = 0; - rtnh->rtnh_hops = 0; - rta->rta_len += rtnh->rtnh_len; + rtnh = nl_attr_rtnh(nlmsg, req_size); + if (rtnh == NULL) + return false; 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 - * a debug test. If you want to change this make sure - * you fix this assumption - */ - label_buf[0] = '\0'; - - num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf, - sizeof(label_buf)); - - if (num_labels) { - /* Set the BoS bit */ - out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT); - - if (rtmsg->rtm_family == AF_MPLS) { - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST, - &out_lse, - num_labels * sizeof(mpls_lse_t)); - rtnh->rtnh_len += - RTA_LENGTH(num_labels * sizeof(mpls_lse_t)); - } else { - struct rtattr *nest; - uint16_t encap = LWTUNNEL_ENCAP_MPLS; - int len = rta->rta_len; - - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE, - &encap, sizeof(uint16_t)); - nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP); - rta_addattr_l(rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST, - &out_lse, - num_labels * sizeof(mpls_lse_t)); - rta_nest_end(rta, nest); - rtnh->rtnh_len += rta->rta_len - len; - } - } + if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg, + req_size, rtmsg, label_buf, + sizeof(label_buf))) + return false; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtnh->rtnh_flags |= RTNH_F_ONLINK; if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) { - bytelen = 4; rtnh->rtnh_flags |= RTNH_F_ONLINK; - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &ipv4_ll, - bytelen); - rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4)) + return false; rtnh->rtnh_ifindex = nexthop->ifindex; if (nexthop->weight) rtnh->rtnh_hops = nexthop->weight - 1; @@ -1373,14 +1374,17 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, __func__, routedesc, p, ipv4_ll_buf, label_buf, nexthop->ifindex, VRF_LOGNAME(vrf), nexthop->vrf_id); - return; + nl_attr_rtnh_end(nlmsg, rtnh); + return true; } if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { - _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET, - rta, rtnh, NL_PKT_BUF_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) @@ -1394,9 +1398,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, } if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET6, - rta, rtnh, NL_PKT_BUF_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; @@ -1433,9 +1438,12 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, 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, @@ -1447,31 +1455,33 @@ static inline void _netlink_mpls_build_singlepath(const struct prefix *p, 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 rtattr *rta, - struct rtnexthop *rtnh, struct rtmsg *rtmsg, - const union g_addr **src) + const zebra_nhlfe_t *nhlfe, + struct nlmsghdr *nlmsg, size_t req_size, + struct rtmsg *rtmsg, const union g_addr **src) { int bytelen; uint8_t family; family = NHLFE_FAMILY(nhlfe); bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop, - rta, rtnh, 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, @@ -1498,10 +1508,10 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; - addattr_l(&req.n, sizeof(req), - NDA_PROTOCOL, &protocol, sizeof(protocol)); - addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); - addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol, + sizeof(protocol)); + nl_attr_put32(&req.n, sizeof(req), NDA_DST, addr); + nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -1531,29 +1541,44 @@ 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) +/* + * 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: - addattr_l(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type, - sizeof(uint16_t)); + if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) + return false; + + nest = nl_attr_nest(n, nlen, RTA_ENCAP); + if (!nest) + return false; - nest = addattr_nest(n, nlen, RTA_ENCAP); - addattr32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni); - addattr_nest_end(n, nest); + 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; @@ -1573,6 +1598,9 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, 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); @@ -1609,9 +1637,13 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, if (cmd != RTM_DELROUTE) req->r.rtm_type = RTN_UNICAST; - addattr_l(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen); - if (src_p) - addattr_l(&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 @@ -1620,7 +1652,9 @@ ssize_t 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, 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) { @@ -1631,8 +1665,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, else tag = dplane_ctx_get_tag(ctx); - if (tag > 0 && tag <= 255) - addattr32(&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. */ @@ -1641,7 +1677,8 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, req->r.rtm_table = table_id; else { req->r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&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) @@ -1657,33 +1694,34 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, * 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)) { - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; + struct rtattr *nest; uint32_t mtu = dplane_ctx_get_mtu(ctx); uint32_t nexthop_mtu = dplane_ctx_get_nh_mtu(ctx); if (!mtu || (nexthop_mtu && nexthop_mtu < mtu)) mtu = nexthop_mtu; - rta->rta_type = RTA_METRICS; - rta->rta_len = RTA_LENGTH(0); - rta_addattr_l(rta, NL_PKT_BUF_SIZE, - RTAX_MTU, &mtu, sizeof(mtu)); - addattr_l(&req->n, datalen, RTA_METRICS, RTA_DATA(rta), - RTA_PAYLOAD(rta)); + + nest = nl_attr_nest(&req->n, datalen, RTA_METRICS); + 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)); - addattr32(&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)) { @@ -1694,15 +1732,18 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, } if (setsrc) { - if (p->family == AF_INET) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv4, bytelen); - else if (p->family == AF_INET6) - addattr_l(&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 @@ -1741,7 +1782,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, 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)) { @@ -1759,9 +1800,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, ? "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; } @@ -1770,28 +1812,31 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, * 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) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv4, bytelen); - else if (p->family == AF_INET6) - addattr_l(&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 */ - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; - struct rtnexthop *rtnh; + struct rtattr *nest; const union g_addr *src1 = NULL; - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH(0); - rtnh = RTA_DATA(rta); + 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)) { @@ -1812,10 +1857,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, : "multipath"; nexthop_num++; - _netlink_route_build_multipath( - p, routedesc, bytelen, nexthop, rta, - rtnh, &req->r, &src1); - rtnh = RTNH_NEXT(rtnh); + 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) @@ -1826,30 +1871,40 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, setsrc = 1; } } + } - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) - netlink_route_nexthop_encap(&req->n, datalen, - nexthop); + nl_attr_nest_end(&req->n, nest); + + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) { + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), + nexthop)) { + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; + if (!netlink_route_nexthop_encap( + &req->n, datalen, nexthop)) + return 0; + } } + if (setsrc) { - if (p->family == AF_INET) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv4, bytelen); - else if (p->family == AF_INET6) - addattr_l(&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"); } - - if (rta->rta_len > RTA_LENGTH(0)) - addattr_l(&req->n, datalen, RTA_MULTIPATH, - RTA_DATA(rta), RTA_PAYLOAD(rta)); } /* If there is no useful nexthop then return. */ @@ -1858,7 +1913,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, zlog_debug("%s: No useful nexthop.", __func__); } - return req->n.nlmsg_len; + return NLMSG_ALIGN(req->n.nlmsg_len); } int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) @@ -1885,10 +1940,10 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) req.ndm.ndm_family = RTNL_FAMILY_IPMR; req.n.nlmsg_type = RTM_GETROUTE; - addattr_l(&req.n, sizeof(req), RTA_IIF, &mroute->ifindex, 4); - addattr_l(&req.n, sizeof(req), RTA_OIF, &mroute->ifindex, 4); - addattr_l(&req.n, sizeof(req), RTA_SRC, &mroute->sg.src.s_addr, 4); - addattr_l(&req.n, sizeof(req), RTA_DST, &mroute->sg.grp.s_addr, 4); + nl_attr_put32(&req.n, sizeof(req), RTA_IIF, mroute->ifindex); + nl_attr_put32(&req.n, sizeof(req), RTA_OIF, mroute->ifindex); + nl_attr_put32(&req.n, sizeof(req), RTA_SRC, mroute->sg.src.s_addr); + nl_attr_put32(&req.n, sizeof(req), RTA_DST, mroute->sg.grp.s_addr); /* * What? * @@ -1905,7 +1960,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) */ actual_table = (zvrf->table_id == RT_TABLE_MAIN) ? RT_TABLE_DEFAULT : zvrf->table_id; - addattr_l(&req.n, sizeof(req), RTA_TABLE, &actual_table, 4); + nl_attr_put32(&req.n, sizeof(req), RTA_TABLE, actual_table); suc = netlink_talk(netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0); @@ -1917,7 +1972,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) /* 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) @@ -1947,11 +2002,15 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, } } } - addattr_l(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; } /** @@ -1962,10 +2021,12 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, * \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; @@ -1979,7 +2040,10 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, 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; @@ -2002,7 +2066,8 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, return -1; } - addattr32(&req->n, buflen, NHA_ID, id); + if (!nl_attr_put32(&req->n, buflen, NHA_ID, id)) + return 0; if (cmd == RTM_NEWNEXTHOP) { /* @@ -2011,12 +2076,13 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, * 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); @@ -2029,17 +2095,22 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, switch (nh->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - addattr_l(&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: - addattr_l(&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: - addattr_l(&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; @@ -2055,7 +2126,9 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, return -1; } - addattr32(&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; @@ -2075,25 +2148,32 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, if (req->nhm.nh_family == AF_MPLS) goto nexthop_done; #if 0 - addattr_l(&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; - addattr_l(&req->n, buflen, - NHA_ENCAP_TYPE, &encap, - sizeof(uint16_t)); - nest = addattr_nest(&req->n, buflen, + if (!nl_attr_put16(&req->n, buflen, + NHA_ENCAP_TYPE, + encap)) + return 0; + nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP); - addattr_l(&req->n, buflen, - MPLS_IPTUNNEL_DST, &out_lse, - num_labels - * sizeof(mpls_lse_t)); - addattr_nest_end(&req->n, nest); + 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); } } @@ -2104,7 +2184,7 @@ nexthop_done: __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)); @@ -2154,7 +2234,7 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *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 @@ -2195,12 +2275,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) */ 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 { /* @@ -2216,12 +2298,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * 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; } @@ -2231,11 +2315,15 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) } 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)) { @@ -2559,8 +2647,8 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, } /** - * 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. @@ -2579,14 +2667,13 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, * @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 { @@ -2597,6 +2684,8 @@ netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx, int ipa_len; enum dplane_op_e op; + if (datalen < sizeof(*req)) + return 0; memset(req, 0, datalen); op = dplane_ctx_get_op(ctx); @@ -2614,22 +2703,30 @@ netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx, 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); + 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; - addattr_l(&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) - addattr16(&req->n, datalen, NDA_VLAN, vid); + if (vid > 0) { + if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid)) + return 0; + } - addattr32(&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); @@ -2645,10 +2742,12 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, 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, @@ -2845,7 +2944,7 @@ static int netlink_request_macs(struct nlsock *netlink_cmd, int family, req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.ifm.ifi_family = family; if (master_ifindex) - addattr32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex); + nl_attr_put32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex); return netlink_request(netlink_cmd, &req); } @@ -2934,13 +3033,13 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, req.ndm.ndm_family = family; /* AF_BRIDGE */ /* req.ndm.ndm_state = NUD_REACHABLE; */ - addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6); br_zif = (struct zebra_if *)br_if->info; if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) - addattr16(&req.n, sizeof(req), NDA_VLAN, vid); + nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid); - addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -3026,9 +3125,9 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, 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; } @@ -3246,7 +3345,7 @@ static int netlink_request_neigh(struct nlsock *netlink_cmd, int family, req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.ndm.ndm_family = family; if (ifindex) - addattr32(&req.n, sizeof(req), NDA_IFINDEX, ifindex); + nl_attr_put32(&req.n, sizeof(req), NDA_IFINDEX, ifindex); return netlink_request(netlink_cmd, &req); } @@ -3325,7 +3424,7 @@ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, req.ndm.ndm_family = AF_INET6; } - addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); + nl_attr_put(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); if (IS_ZEBRA_DEBUG_KERNEL) { char buf[INET6_ADDRSTRLEN]; @@ -3444,9 +3543,11 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, 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); @@ -3501,7 +3602,8 @@ enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx) * 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; @@ -3515,10 +3617,13 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) struct { struct nlmsghdr n; struct rtmsg r; - char buf[NL_PKT_BUF_SIZE]; - } req; + char buf[0]; + } *req = buf; - memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE); + if (buflen < sizeof(*req)) + return 0; + + memset(req, 0, sizeof(*req)); /* * Count # nexthops so we can decide whether to use singlepath @@ -3547,30 +3652,31 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) (!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); - addattr_l(&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. @@ -3596,23 +3702,22 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) && 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; } } } else { /* Multipath case */ - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; - struct rtnexthop *rtnh; + struct rtattr *nest; const union g_addr *src1 = NULL; - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH(0); - rtnh = RTA_DATA(rta); + 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), @@ -3636,21 +3741,17 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) nexthop_num++; /* Build the multipath */ - _netlink_mpls_build_multipath(&p, routedesc, - nhlfe, rta, rtnh, - &req.r, &src1); - rtnh = RTNH_NEXT(rtnh); + if (!_netlink_mpls_build_multipath( + &p, routedesc, nhlfe, &req->n, + buflen, &req->r, &src1)) + return 0; } } /* Add the multipath */ - if (rta->rta_len > RTA_LENGTH(0)) - addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, - RTA_DATA(rta), RTA_PAYLOAD(rta)); + 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 */ |
