From nobody Thu Mar 09 14:35:32 2023 X-Original-To: dev-commits-src-all@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 4PXWtr6PZLz3x0wX; Thu, 9 Mar 2023 14:35:32 +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 4PXWtr5tN7z3rQR; Thu, 9 Mar 2023 14:35:32 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1678372532; 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=sE9nwTleSM+5on4noLtdAmpg3djegqPSXoAxDvhh8hQ=; b=bQZ3shHAAijFiHSzDV2B4avrrANbOFi+MfJUQqLM59GNE4CdtKv22RdcRm8137kTWWhoGB TmmHfqQi57SqyoQCLhchH97vBkBI3gjRexHHVks2hmC+nGlzK/xvhSwF0caX/+XCjbHc/T YMocme6xfG42V4M/RVbCMGJgVTD4Wl/646rzAHvH47/jm+rfWzM1MQvg0gq92nLFGPpkMI xcfChISd8A90zUx6YU7ElTeI/3Qf9WB1C+AQX3psW7ptARdvr3r7wLRarRPXfbvIjkhn7p eaLb0h6E8sZGzIdD7AE4UEQSJWIW7Jrg89lJkm3snslaWhgOE8odh4BECbO/Dw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1678372532; 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=sE9nwTleSM+5on4noLtdAmpg3djegqPSXoAxDvhh8hQ=; b=Bl3dJ23Clt8h2grV+OI9DjryaJOMzHtLEUBpSpE8NVxq3BKBTc84TlULwGJdVtfJ6kL/lN +cRMolDz0z0NwBDm0vgKdozj3zjqzAwnzwtd/8dS/Mmhkb3u119ZuYSbyM+2r/HIrMWVEJ 6Z1VomtdRtW9wGz8Sh7JGgbVhrSC15QdOK8DPONFz5A8mAniWZQBEBya43en+dosLsG2gr 8khGEAEVpIOxehtWN+VpkRllhAeazZpN1gZFSfZfXtWXxdoP5TKekY/5nWnXY2qO4J/6z8 TK8pufZEYyw4YLLNRKQWc/CyfKp+Oe/nXznj7EdTyIjScwWr7D/CgOBh2retEA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1678372532; a=rsa-sha256; cv=none; b=IdDI6tNCrmbqRvGkruVogdf5IXuiMwrp1MLZQD2U3qWl9P9DODvRAcD2TVFY1+YsZMvUdI Zjx4ncjrx8ryWc1mwG20i4gX83m598h7kvIq/jdLNHDQFc3mBguumKB0VJV7g7o/CzZlxb h8+vs5BlAaY0xsUCbwDobTQZGYNmQGkjQl26a/BlBUugi/Sa7IQOzUONTwUGxMo5GHnYc6 c7DqWge7pf1WGdbOFFq5joBH1du425PFHWBCigRCCEUNZUNYpc1ZoI7JaWRd1nnhOEdkfW JTPJjdCUPJAz+P6ork/nx0bPrsqIvXHEb4izvC1Tp12uN3XkD//FUG1CMwgnAA== 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 4PXWtr4b6Kz19rb; Thu, 9 Mar 2023 14:35:32 +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 329EZWaw032973; Thu, 9 Mar 2023 14:35:32 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 329EZWbG032972; Thu, 9 Mar 2023 14:35:32 GMT (envelope-from git) Date: Thu, 9 Mar 2023 14:35:32 GMT Message-Id: <202303091435.329EZWbG032972@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: 76f6d391504b - main - netlink: add basic message writing support to snl(3). List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@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/main X-Git-Reftype: branch X-Git-Commit: 76f6d391504b040528882a908147e47ea90b7b90 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=76f6d391504b040528882a908147e47ea90b7b90 commit 76f6d391504b040528882a908147e47ea90b7b90 Author: Alexander V. Chernikov AuthorDate: 2023-03-09 14:33:26 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-03-09 14:33:26 +0000 netlink: add basic message writing support to snl(3). Differential Revision: https://reviews.freebsd.org/D38947 MFC after: 2 weeks --- 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