From nobody Sat Apr 08 19:44:49 2023 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Pv5Kt58qZz44nmP; Sat, 8 Apr 2023 19:44:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Pv5Kt1F2yz43pm; Sat, 8 Apr 2023 19:44:50 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680983090; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=/pZeacW8GpYql+4AsuG5/js/ygOn9EGxxyZfG8A0VvI=; b=DX/5x4WjHWeZxiLBwAyjrrhvG0GOt6BoOQjdadJ17dUjk/TDrt6vmDMQLXFfbmoLkhn3ox N5VBBBz4dh4rVPuXlYiUHF4LPuF3XqelInOUlOhrHz829ZjGU7E3YtF+FEazcTFDxc2WyK 2aOppXBG+AHCEMeCIft79R9uYvpN/NGtz1PbymgAQHNE2XMpsiM8cxrHDf6y0i307LLIZM 2A1XtomK2TdidcbRVaRkzOd4OBnOoTsUkO45y7O3SDfYzUaxCh6/j647jWQL1AimNYuy3m f2Ly/1NbTn/kgpNEkG7CJRZHdPHd2olTxdkqEgw0Y/XG0/+OEAqSLK7iWvlefQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680983090; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=/pZeacW8GpYql+4AsuG5/js/ygOn9EGxxyZfG8A0VvI=; b=exFP7gcV241Mom/kojltcaJQTSkPzrJDYI9nEv75lRzOOoD9fIdNrkhpikzwCQaR5u7c7/ lMP1yncClkb5vVoIL6okEGbYvuacwrAyyY3TSixei/HiPB2NXZYiIv5ELJ9M6eOb3SIUAF upLDfg6JTseq93ki8C+Ah+IRhvkq6P5FxsBXsGTuHGPKbNhQN9BavcHdVIC7XtuvagF62R D7CPjVOzxHTa1jpx7R2rD4hw1uP58cL1r0ETenfx+H8V0G1bkIPvXvVfNOKIoZqUIoogji GDcKSWNRH3frVyD0I8vcIB8eMmG3cgGxlZQo15w10E2AHSV7iUaI2dAJrTVZ8g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1680983090; a=rsa-sha256; cv=none; b=B/R/uRc/LCgOI3II6dKo80irrwROwNEx1XWO1/Olrreop/odAAHHc8KNSIHly3J510b6Tv 6hWoNcbAUWd7UbwNRWsQfW7WS0qUJ+IoOGJsR5Dk7y6667/asIF5ncgnURoF2CkcXc9bV9 V8591kUceZ61ljHFOny5+iAyUGO88Z30dkuJ63QuQ5nH/SzVxS4FpzAZL4a969JeO1fchF C+xhnjTRyLKmxkrEa7ifdBppZUr361OcpXQCAuGsZDG2/1U1cv5NLzgypzfwBMhzMhxI95 12XVLOcYzEvnFhdU2UwSQ74aCxfDrb7BiJC6+iH/xHIUgBiyuysa/t/3HxRdQQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Pv5Kt0KRCzfYZ; Sat, 8 Apr 2023 19:44:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 338Jinho018693; Sat, 8 Apr 2023 19:44:49 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 338JinEw018692; Sat, 8 Apr 2023 19:44:49 GMT (envelope-from git) Date: Sat, 8 Apr 2023 19:44:49 GMT Message-Id: <202304081944.338JinEw018692@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: ec1edf13b151 - stable/13 - netlink: add basic message writing support to snl(3). List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: ec1edf13b15179e2ac5af41e4b73faa3f560347a Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=ec1edf13b15179e2ac5af41e4b73faa3f560347a commit ec1edf13b15179e2ac5af41e4b73faa3f560347a Author: Alexander V. Chernikov AuthorDate: 2023-03-09 14:33:26 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-04-08 19:05:43 +0000 netlink: add basic message writing support to snl(3). Differential Revision: https://reviews.freebsd.org/D38947 MFC after: 2 weeks (cherry picked from commit 76f6d391504b040528882a908147e47ea90b7b90) --- sys/netlink/netlink_snl.h | 324 ++++++++++++++++++++++++++++++++++++++++ sys/netlink/netlink_snl_route.h | 36 +++++ 2 files changed, 360 insertions(+) diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h index 3c63e3f95419..19b3e2f985f3 100644 --- a/sys/netlink/netlink_snl.h +++ b/sys/netlink/netlink_snl.h @@ -124,6 +124,7 @@ struct snl_state { struct linear_buffer *lb; }; #define SCRATCH_BUFFER_SIZE 1024 +#define SNL_WRITER_BUFFER_SIZE 256 typedef void snl_parse_field_f(struct snl_state *ss, void *hdr, void *target); struct snl_field_parser { @@ -294,6 +295,30 @@ snl_read_message(struct snl_state *ss) return (hdr); } +static inline struct nlmsghdr * +snl_read_reply(struct snl_state *ss, uint32_t nlmsg_seq) +{ + while (true) { + struct nlmsghdr *hdr = snl_read_message(ss); + if (hdr == NULL) + break; + if (hdr->nlmsg_seq == nlmsg_seq) + return (hdr); + } + + return (NULL); +} + +static inline struct nlmsghdr * +snl_get_reply(struct snl_state *ss, struct nlmsghdr *hdr) +{ + uint32_t nlmsg_seq = hdr->nlmsg_seq; + + if (snl_send(ss, hdr, hdr->nlmsg_len)) + return (snl_read_reply(ss, nlmsg_seq)); + return (NULL); +} + /* * Checks that attributes are sorted by attribute type. */ @@ -511,4 +536,303 @@ snl_field_get_uint32(struct snl_state *ss __unused, void *src, void *target) *((uint32_t *)target) = *((uint32_t *)src); } +struct snl_errmsg_data { + uint32_t nlmsg_seq; + int error; + char *error_str; + uint32_t error_offs; + struct nlattr *cookie; +}; +#define _IN(_field) offsetof(struct nlmsgerr, _field) +#define _OUT(_field) offsetof(struct snl_errmsg_data, _field) +static const struct snl_attr_parser nla_p_errmsg[] = { + { .type = NLMSGERR_ATTR_MSG, .off = _OUT(error_str), .cb = snl_attr_get_string }, + { .type = NLMSGERR_ATTR_OFFS, .off = _OUT(error_offs), .cb = snl_attr_get_uint32 }, + { .type = NLMSGERR_ATTR_COOKIE, .off = _OUT(cookie), .cb = snl_attr_get_nla }, +}; + +static const struct snl_field_parser nlf_p_errmsg[] = { + { .off_in = _IN(error), .off_out = _OUT(error), .cb = snl_field_get_uint32 }, + { .off_in = _IN(msg.nlmsg_seq), .off_out = _OUT(nlmsg_seq), .cb = snl_field_get_uint32 }, +}; +#undef _IN +#undef _OUT +SNL_DECLARE_PARSER(snl_errmsg_parser, struct nlmsgerr, nlf_p_errmsg, nla_p_errmsg); + +static inline bool +snl_check_return(struct snl_state *ss, struct nlmsghdr *hdr, struct snl_errmsg_data *e) +{ + if (hdr != NULL && hdr->nlmsg_type == NLMSG_ERROR) + return (snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e)); + return (false); +} + +/* writer logic */ +struct snl_writer { + char *base; + uint32_t offset; + uint32_t size; + struct nlmsghdr *hdr; + struct snl_state *ss; + bool error; +}; + +static inline void +snl_init_writer(struct snl_state *ss, struct snl_writer *nw) +{ + nw->size = SNL_WRITER_BUFFER_SIZE; + nw->base = snl_allocz(ss, nw->size); + if (nw->base == NULL) { + nw->error = true; + nw->size = 0; + } + + nw->offset = 0; + nw->hdr = NULL; + nw->error = false; + nw->ss = ss; +} + +static inline bool +snl_realloc_msg_buffer(struct snl_writer *nw, size_t sz) +{ + uint32_t new_size = nw->size * 2; + + while (new_size < nw->size + sz) + new_size *= 2; + + if (nw->error) + return (false); + + void *new_base = snl_allocz(nw->ss, new_size); + if (new_base == NULL) { + nw->error = true; + return (false); + } + + memcpy(new_base, nw->base, nw->offset); + if (nw->hdr != NULL) { + int hdr_off = (char *)(nw->hdr) - nw->base; + nw->hdr = (struct nlmsghdr *)(void *)((char *)new_base + hdr_off); + } + nw->base = new_base; + + return (true); +} + +static inline void * +snl_reserve_msg_data_raw(struct snl_writer *nw, size_t sz) +{ + sz = NETLINK_ALIGN(sz); + + if (__predict_false(nw->offset + sz > nw->size)) { + if (!snl_realloc_msg_buffer(nw, sz)) + return (NULL); + } + + void *data_ptr = &nw->base[nw->offset]; + nw->offset += sz; + + return (data_ptr); +} +#define snl_reserve_msg_object(_ns, _t) ((_t *)snl_reserve_msg_data_raw(_ns, sizeof(_t))) +#define snl_reserve_msg_data(_ns, _sz, _t) ((_t *)snl_reserve_msg_data_raw(_ns, _sz)) + +static inline void * +_snl_reserve_msg_attr(struct snl_writer *nw, uint16_t nla_type, uint16_t sz) +{ + sz += sizeof(struct nlattr); + + struct nlattr *nla = snl_reserve_msg_data(nw, sz, struct nlattr); + if (__predict_false(nla == NULL)) + return (NULL); + nla->nla_type = nla_type; + nla->nla_len = sz; + + return ((void *)(nla + 1)); +} +#define snl_reserve_msg_attr(_ns, _at, _t) ((_t *)_snl_reserve_msg_attr(_ns, _at, sizeof(_t))) + +static inline bool +snl_add_msg_attr(struct snl_writer *nw, int attr_type, int attr_len, const void *data) +{ + int required_len = NLA_ALIGN(attr_len + sizeof(struct nlattr)); + + if (__predict_false(nw->offset + required_len > nw->size)) { + if (!snl_realloc_msg_buffer(nw, required_len)) + return (false); + } + + struct nlattr *nla = (struct nlattr *)(&nw->base[nw->offset]); + + nla->nla_len = attr_len + sizeof(struct nlattr); + nla->nla_type = attr_type; + if (attr_len > 0) { + if ((attr_len % 4) != 0) { + /* clear padding bytes */ + bzero((char *)nla + required_len - 4, 4); + } + memcpy((nla + 1), data, attr_len); + } + nw->offset += required_len; + return (true); +} + +static inline bool +snl_add_msg_attr_raw(struct snl_writer *nw, const struct nlattr *nla_src) +{ + int attr_len = nla_src->nla_len - sizeof(struct nlattr); + + assert(attr_len >= 0); + + return (snl_add_msg_attr(nw, nla_src->nla_type, attr_len, (const void *)(nla_src + 1))); +} + +static inline bool +snl_add_msg_attr_u8(struct snl_writer *nw, int attrtype, uint8_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(uint8_t), &value)); +} + +static inline bool +snl_add_msg_attr_u16(struct snl_writer *nw, int attrtype, uint16_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(uint16_t), &value)); +} + +static inline bool +snl_add_msg_attr_u32(struct snl_writer *nw, int attrtype, uint32_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(uint32_t), &value)); +} + +static inline bool +snl_add_msg_attr_u64(struct snl_writer *nw, int attrtype, uint64_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(uint64_t), &value)); +} + +static inline bool +snl_add_msg_attr_s8(struct snl_writer *nw, int attrtype, int8_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(int8_t), &value)); +} + +static inline bool +snl_add_msg_attr_s16(struct snl_writer *nw, int attrtype, int16_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(int16_t), &value)); +} + +static inline bool +snl_add_msg_attr_s32(struct snl_writer *nw, int attrtype, int32_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(int32_t), &value)); +} + +static inline bool +snl_add_msg_attr_s64(struct snl_writer *nw, int attrtype, int64_t value) +{ + return (snl_add_msg_attr(nw, attrtype, sizeof(int64_t), &value)); +} + +static inline bool +snl_add_msg_attr_flag(struct snl_writer *nw, int attrtype) +{ + return (snl_add_msg_attr(nw, attrtype, 0, NULL)); +} + +static inline bool +snl_add_msg_attr_string(struct snl_writer *nw, int attrtype, const char *str) +{ + return (snl_add_msg_attr(nw, attrtype, strlen(str) + 1, str)); +} + + +static inline int +snl_get_msg_offset(const struct snl_writer *nw) +{ + return (nw->offset - ((char *)nw->hdr - nw->base)); +} + +static inline void * +_snl_restore_msg_offset(const struct snl_writer *nw, int off) +{ + return ((void *)((char *)nw->hdr + off)); +} +#define snl_restore_msg_offset(_ns, _off, _t) ((_t *)_snl_restore_msg_offset(_ns, _off)) + +static inline int +snl_add_msg_attr_nested(struct snl_writer *nw, int attrtype) +{ + int off = snl_get_msg_offset(nw); + struct nlattr *nla = snl_reserve_msg_data(nw, sizeof(struct nlattr), struct nlattr); + if (__predict_false(nla == NULL)) + return (0); + nla->nla_type = attrtype; + return (off); +} + +static inline void +snl_end_attr_nested(const struct snl_writer *nw, int off) +{ + if (!nw->error) { + struct nlattr *nla = snl_restore_msg_offset(nw, off, struct nlattr); + nla->nla_len = NETLINK_ALIGN(snl_get_msg_offset(nw) - off); + } +} + +static inline struct nlmsghdr * +snl_create_msg_request(struct snl_writer *nw, int nlmsg_type) +{ + assert(nw->hdr == NULL); + + struct nlmsghdr *hdr = snl_reserve_msg_object(nw, struct nlmsghdr); + hdr->nlmsg_type = nlmsg_type; + hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nw->hdr = hdr; + + return (hdr); +} + +static void +snl_abort_msg(struct snl_writer *nw) +{ + if (nw->hdr != NULL) { + int offset = (char *)(&nw->base[nw->offset]) - (char *)(nw->hdr); + + nw->offset -= offset; + nw->hdr = NULL; + } +} + +static inline struct nlmsghdr * +snl_finalize_msg(struct snl_writer *nw) +{ + if (nw->error) + snl_abort_msg(nw); + if (nw->hdr != NULL) { + struct nlmsghdr *hdr = nw->hdr; + + int offset = (char *)(&nw->base[nw->offset]) - (char *)(nw->hdr); + hdr->nlmsg_len = offset; + hdr->nlmsg_seq = snl_get_seq(nw->ss); + nw->hdr = NULL; + + return (hdr); + } + return (NULL); +} + +static bool +snl_send_msgs(struct snl_writer *nw) +{ + int offset = nw->offset; + + assert(nw->hdr == NULL); + nw->offset = 0; + + return (snl_send(nw->ss, nw->base, offset)); +} + #endif diff --git a/sys/netlink/netlink_snl_route.h b/sys/netlink/netlink_snl_route.h index 4adb3d697ecd..281794a9d6f7 100644 --- a/sys/netlink/netlink_snl_route.h +++ b/sys/netlink/netlink_snl_route.h @@ -127,4 +127,40 @@ snl_attr_get_ipvia(struct snl_state *ss, struct nlattr *nla, return (false); } +static inline bool +snl_add_msg_attr_ip(struct snl_writer *nw, int attrtype, const struct sockaddr *sa) +{ + const void *addr; + + switch (sa->sa_family) { + case AF_INET: + addr = &((const struct sockaddr_in *)sa)->sin_addr; + return (snl_add_msg_attr(nw, attrtype, 4, addr)); + case AF_INET6: + addr = &((const struct sockaddr_in6 *)sa)->sin6_addr; + return (snl_add_msg_attr(nw, attrtype, 16, addr)); + } + + return (false); +} + +static inline bool +snl_add_msg_attr_ipvia(struct snl_writer *nw, int attrtype, const struct sockaddr *sa) +{ + char buf[17]; + + buf[0] = sa->sa_family; + + switch (sa->sa_family) { + case AF_INET: + memcpy(&buf[1], &((const struct sockaddr_in *)sa)->sin_addr, 4); + return (snl_add_msg_attr(nw, attrtype, 5, buf)); + case AF_INET6: + memcpy(&buf[1], &((const struct sockaddr_in6 *)sa)->sin6_addr, 16); + return (snl_add_msg_attr(nw, attrtype, 17, buf)); + } + + return (false); +} + #endif