From nobody Fri Jul 24 15:04:08 2026 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 4h6B8t3Tc4z6mH1H for ; Fri, 24 Jul 2026 15:04:14 +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 "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h6B8t1CX5z3ScR for ; Fri, 24 Jul 2026 15:04:14 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784905454; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=+P4asZS+pvNwJgN/KinI/6PCKikvJZdAfDW3A6UWLro=; b=I5iSPFk8SLdHCFaeJSL8C8ptedfr0XdUvNSnaauigIcHjmVfwsYk3xKYnDfzB0cLpZxjEM /fDUvT3idc9CAvlQEVlKXP5qxMfmnjVMgSXec4BKo8E6GHR03SR7VUB7QyQ9Lh6tUQMDZR EnvDoK22eHhFXtlLbbStV0ubVgvRC/7PC48a0ZFTrtF/IKGQeFJKCoA2NCvJlMIcRXUp1G AnueWz1wPAHMzcT4tBFwczXDT6UBkJQzZ3XhYpCR3ZDHcqKVFgKM6imgNmmIeRLCZDoiKf DiPW5FRPE+yfC6uo6ETjsgMWZlcOEiADF0jbWLGjkFzk7IZsmjtVIOFkgjStXA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784905454; a=rsa-sha256; cv=none; b=dMJscFnX2tM2ebORZ867IDi6Th+GqjW/TgXKKCOlomLbS5z4idDho3P8Xvtym6WT6ddC1C N/3zxuJHsf8wjjpLTKfAGfwbEvcv3DakqrjGzUAvXF3Vfn0EaqLaIS8mQ4WjIWkuEYP406 mjZNtmnliP3/e2WQA0WqLObeojR2PfFJ3gTkoW4rbiyP+tD1lMnljg8CqiHNgTdlZWxMYb /JkgwHfegSquSMqCfNcRIn0IfFC8iw7rKdXdBIB8fr5t5scDyiQvFcOEfTDcG2m8mcjaR3 b8K15NeQLl29d3IKG0vrfgNUf35hcha41yvzSIHIrssJ1HAuvZb0qtwzUzzseA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784905454; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=+P4asZS+pvNwJgN/KinI/6PCKikvJZdAfDW3A6UWLro=; b=rRIn8DdkYoy/EqUz9DQKWK8YUOgc7/+YSfGi11KZys/Uyp4XGjhVhE884deFtHb8JnxBOj WAmwvhsWIYY5hfyU+faxnHGI6zqEqkfZePM1gDC/+c8qKU+C3i7NdYuyZpQU63pbRFh/4W xbl5gtsBwqeYd2jsSeLPNGquUjbjxnkIT01HN6Y5NOK266plr+5wvdHhzhlFipsmj0nO6t HZ4vufybM7ZrsHwIJt8nJe0qGeMhYS4mq+4UihhkExb/OIl6eBBwpRR+Zoqwaws0KlowgV vdb/EWNPh5ncQq83321EYBgFo+bsC76soPbebAMyfTOc8s95iiZCpyl9ow8trA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h6B8t0BGPzwg4 for ; Fri, 24 Jul 2026 15:04:14 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3620a by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 24 Jul 2026 15:04:08 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Ishan Agrawal From: Kristof Provost Subject: git: 26bb78b77231 - main - libsysdecode: add Netlink attribute decoding infrastructure 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: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 26bb78b77231c4b2d80f7d89f39e9e06294151d2 Auto-Submitted: auto-generated Date: Fri, 24 Jul 2026 15:04:08 +0000 Message-Id: <6a637ee8.3620a.6a13d1a8@gitrepo.freebsd.org> The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=26bb78b77231c4b2d80f7d89f39e9e06294151d2 commit 26bb78b77231c4b2d80f7d89f39e9e06294151d2 Author: Ishan Agrawal AuthorDate: 2026-07-22 15:31:23 +0000 Commit: Kristof Provost CommitDate: 2026-07-24 15:02:37 +0000 libsysdecode: add Netlink attribute decoding infrastructure Introduce a generic Netlink attribute decoding framework based on attribute decoder tables. The framework supports decoding primitive attribute types as well as nested attributes and can be reused by different Generic Netlink families. Signed-off-by: Ishan Agrawal Sponsored-by: Google LLC (GSoC 2026) Reviewed-by: kp Pull-Request: https://github.com/freebsd/freebsd-src/pull/2337 --- lib/libsysdecode/netlink.c | 215 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 213 insertions(+), 2 deletions(-) diff --git a/lib/libsysdecode/netlink.c b/lib/libsysdecode/netlink.c index ce8ac0485009..bb07ad2e4bf7 100644 --- a/lib/libsysdecode/netlink.c +++ b/lib/libsysdecode/netlink.c @@ -5,9 +5,14 @@ */ #include +#include +#include +#include +#include #include #include #include +#include #include #include @@ -29,8 +34,195 @@ static struct name_table *family_table = NULL; static size_t num_family = 0; +typedef void decode_attr_f(FILE *fp, const struct nlattr *attr, + const char *attr_name, const void *args); +struct nlattr_decoder { + uint16_t type; /* Attribute type */ + const char *attr_name; /* Attribute name*/ + decode_attr_f *cb; /* decoder function to call */ + const void *args; /* nested decoder */ +}; + +struct nlattr_decoder_set { + const struct nlattr_decoder *decoders; /* PFNL CMD Decoders */ + size_t count; /*Attribute Count*/ +}; + +#define NL_DECLARE_ATTR_DECODER(_name, _np) \ +static const struct nlattr_decoder_set _name = { \ + .decoders = &((_np)[0]), \ + .count = nitems(_np), \ +} + +static void nl_decode_attrs_raw(FILE *fp, const struct nlattr *nla_head, + size_t len, const struct nlattr_decoder *ps, size_t pslen); + +static void +nlattr_decode_in6_addr(FILE *fp, const struct nlattr *attr, + const char *attr_name, const void *args) +{ + (void)args; + + struct in6_addr target; + + if (NLA_DATA_LEN(attr) < (int)sizeof(target)) + return; + + memcpy(&target, NLA_DATA_CONST(attr), sizeof(struct in6_addr)); + + fprintf(fp, "%s=", attr_name); + + char buf[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET6, &target, buf, sizeof(buf)) != NULL) + fprintf(fp, "%s", buf); +} + +static void +nlattr_decode_uint32(FILE *fp, const struct nlattr *attr, const char *attr_name, + const void *args) +{ + (void)args; + + uint32_t target; + + if (NLA_DATA_LEN(attr) < (int)sizeof(target)) + return; + + memcpy(&target, NLA_DATA_CONST(attr), sizeof(uint32_t)); + + fprintf(fp, "%s=%u", attr_name, target); +} + +static void +nlattr_decode_uint8(FILE *fp, const struct nlattr *attr, const char *attr_name, + const void *args) +{ + (void)args; + + uint8_t target; + + if (NLA_DATA_LEN(attr) < (int)sizeof(target)) + return; + + memcpy(&target, NLA_DATA_CONST(attr), sizeof(uint8_t)); + + fprintf(fp, "%s=%u", attr_name, target); +} + +static void +nlattr_decode_string(FILE *fp, const struct nlattr *attr, const char *attr_name, + const void *args) +{ + (void)args; + + if (NLA_DATA_LEN(attr) == 0) + return; + + const char *target = (const char *)NLA_DATA_CONST(attr); + + fprintf(fp, "%s=%s", attr_name, target); +} + +static void +nlattr_decode_nested(FILE *fp, const struct nlattr *attr, const char *attr_name, + const void *args) +{ + const struct nlattr_decoder_set *set = args; + + if (set == NULL) + return; + + fprintf(fp, "%s=", attr_name); + + nl_decode_attrs_raw(fp, NLA_DATA_CONST(attr), NLA_DATA_LEN(attr), + set->decoders, set->count); +} + +static const struct nlattr_decoder * +search_decoders(const struct nlattr_decoder *ps, size_t pslen, int key) +{ + size_t left_i = 0, right_i = pslen - 1; + + if (pslen == 0) + return (NULL); + + if (key < ps[0].type || key > ps[pslen - 1].type) + return (NULL); + + while (left_i + 1 < right_i) { + size_t mid_i = (left_i + right_i) / 2; + if (key < ps[mid_i].type) + right_i = mid_i; + else if (key > ps[mid_i].type) + left_i = mid_i + 1; + else + return (&ps[mid_i]); + } + if (ps[left_i].type == key) + return (&ps[left_i]); + else if (ps[right_i].type == key) + return (&ps[right_i]); + return (NULL); +} + static void -sysdecode_netlink_pf(FILE *fp, const struct genlmsghdr *genl) +nl_decode_attrs_raw(FILE *fp, const struct nlattr *nla_head, size_t len, + const struct nlattr_decoder *ps, size_t pslen) +{ + const struct nlattr_decoder *s; + const struct nlattr *nla; + bool first = true; + + fprintf(fp, "{"); + + NLA_FOREACH_CONST(nla, nla_head, len) { + if (!first) + fprintf(fp, ","); + + s = search_decoders(ps, pslen, nla->nla_type & NLA_TYPE_MASK); + if (s != NULL && s->cb != NULL) + s->cb(fp, nla, s->attr_name, s->args); + + first = false; + } + + fprintf(fp, "}"); +} + +static const struct nlattr_decoder nla_d_addr_wrap[] = { + { .type = PF_AT_ADDR, .attr_name = "addr", .cb = nlattr_decode_in6_addr }, + { .type = PF_AT_MASK, .attr_name = "mask", .cb = nlattr_decode_in6_addr }, + { .type = PF_AT_IFNAME, .attr_name = "ifname", .cb = nlattr_decode_string }, + { .type = PF_AT_TABLENAME, .attr_name = "tablename", .cb = nlattr_decode_string }, + { .type = PF_AT_TYPE, .attr_name = "type", .cb = nlattr_decode_uint8 }, + { .type = PF_AT_IFLAGS, .attr_name = "iflags", .cb = nlattr_decode_uint8 }, +}; +NL_DECLARE_ATTR_DECODER(addr_wrap_decoder, nla_d_addr_wrap); + +static const struct nlattr_decoder nla_d_pool_addr[] = { + { .type = PF_PA_ADDR, .attr_name = "addr", .cb = nlattr_decode_nested, .args = &addr_wrap_decoder}, + { .type = PF_PA_IFNAME, .attr_name = "ifname", .cb = nlattr_decode_string }, +}; +NL_DECLARE_ATTR_DECODER(pool_addr_decoder, nla_d_pool_addr); + +static const struct nlattr_decoder nla_d_add_addr[] = { + { .type = PF_AA_ACTION, .attr_name = "action", .cb = nlattr_decode_uint32 }, + { .type = PF_AA_TICKET, .attr_name = "ticket", .cb = nlattr_decode_uint32 }, + { .type = PF_AA_NR, .attr_name = "nr", .cb = nlattr_decode_uint32 }, + { .type = PF_AA_R_NUM, .attr_name = "r_num", .cb = nlattr_decode_uint32 }, + { .type = PF_AA_R_ACTION, .attr_name = "r_action", .cb = nlattr_decode_uint8 }, + { .type = PF_AA_R_LAST, .attr_name = "r_last", .cb = nlattr_decode_uint8 }, + { .type = PF_AA_AF, .attr_name = "af", .cb = nlattr_decode_uint8 }, + { .type = PF_AA_ANCHOR, .attr_name = "anchor", .cb = nlattr_decode_string }, + { .type = PF_AA_ADDR, .attr_name = "addr", .cb = nlattr_decode_nested , .args = &pool_addr_decoder}, + { .type = PF_AA_WHICH, .attr_name = "which", .cb = nlattr_decode_uint32 }, +}; +NL_DECLARE_ATTR_DECODER(addr_parser, nla_d_add_addr); + + +static void +sysdecode_netlink_pf(FILE *fp, const struct genlmsghdr *genl, size_t nlm_len) { uint8_t cmd = genl->cmd; const char *cmd_name = sysdecode_pfnl_cmd(cmd); @@ -39,6 +231,22 @@ sysdecode_netlink_pf(FILE *fp, const struct genlmsghdr *genl) fprintf(fp, "cmd=%s", cmd_name); else fprintf(fp, "cmd=%u", cmd); + + const struct nlattr *nla = (const struct nlattr *)(const void *) + ((const char *)genl + sizeof(struct genlmsghdr)); + + switch (cmd) { + case PFNL_CMD_GET_ADDR: + nl_decode_attrs_raw(fp, nla, nlm_len, + addr_parser.decoders, addr_parser.count); + break; + case PFNL_CMD_GET_ADDRS: + nl_decode_attrs_raw(fp, nla, nlm_len, + addr_parser.decoders, addr_parser.count); + break; + default: + break; + } } bool @@ -181,8 +389,11 @@ sysdecode_netlink(FILE *fp, const void *buf, size_t len, int protocol) (const struct genlmsghdr *)(const void *) ((const char *)nl + sizeof(struct nlmsghdr)); + const size_t nlm_len = nl->nlmsg_len - + (sizeof(struct nlmsghdr) + + sizeof(struct genlmsghdr)); - sysdecode_netlink_pf(fp, genl); + sysdecode_netlink_pf(fp, genl, nlm_len); } fprintf(fp, "}");