Page MenuHomeFreeBSD

D39092.id118873.diff
No OneTemporary

D39092.id118873.diff

diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h
--- a/sys/netlink/netlink_snl.h
+++ b/sys/netlink/netlink_snl.h
@@ -258,6 +258,14 @@
return (send(ss->fd, data, sz, 0) == sz);
}
+static inline bool
+snl_send_message(struct snl_state *ss, struct nlmsghdr *hdr)
+{
+ ssize_t sz = NLMSG_ALIGN(hdr->nlmsg_len);
+
+ return (send(ss->fd, hdr, sz, 0) == sz);
+}
+
static inline uint32_t
snl_get_seq(struct snl_state *ss)
{
@@ -298,10 +306,9 @@
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;
+ struct nlmsghdr *hdr;
+
+ while ((hdr = snl_read_message(ss)) != NULL) {
if (hdr->nlmsg_seq == nlmsg_seq)
return (hdr);
}
@@ -309,16 +316,6 @@
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.
*/
@@ -472,6 +469,34 @@
return (false);
}
+static inline bool
+snl_attr_get_int8(struct snl_state *ss, struct nlattr *nla, const void *arg,
+ void *target)
+{
+ return (snl_attr_get_uint8(ss, nla, arg, target));
+}
+
+static inline bool
+snl_attr_get_int16(struct snl_state *ss, struct nlattr *nla, const void *arg,
+ void *target)
+{
+ return (snl_attr_get_uint16(ss, nla, arg, target));
+}
+
+static inline bool
+snl_attr_get_int32(struct snl_state *ss, struct nlattr *nla, const void *arg,
+ void *target)
+{
+ return (snl_attr_get_uint32(ss, nla, arg, target));
+}
+
+static inline bool
+snl_attr_get_int64(struct snl_state *ss, struct nlattr *nla, const void *arg,
+ void *target)
+{
+ return (snl_attr_get_uint64(ss, nla, arg, target));
+}
+
static inline bool
snl_attr_get_string(struct snl_state *ss __unused, struct nlattr *nla,
const void *arg __unused, void *target)
@@ -573,14 +598,55 @@
#undef _OUT
SNL_DECLARE_PARSER(snl_errmsg_parser, struct nlmsgerr, nlf_p_errmsg, nla_p_errmsg);
+#define _IN(_field) offsetof(struct nlmsgerr, _field)
+#define _OUT(_field) offsetof(struct snl_errmsg_data, _field)
+static const struct snl_attr_parser nla_p_donemsg[] = {};
+
+static const struct snl_field_parser nlf_p_donemsg[] = {
+ { .off_in = _IN(error), .off_out = _OUT(error), .cb = snl_field_get_uint32 },
+};
+#undef _IN
+#undef _OUT
+SNL_DECLARE_PARSER(snl_donemsg_parser, struct nlmsgerr, nlf_p_donemsg, nla_p_donemsg);
+
static inline bool
-snl_check_return(struct snl_state *ss, struct nlmsghdr *hdr, struct snl_errmsg_data *e)
+snl_read_reply_code(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg_data *e)
{
- if (hdr != NULL && hdr->nlmsg_type == NLMSG_ERROR)
- return (snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e));
+ struct nlmsghdr *hdr = snl_read_reply(ss, nlmsg_seq);
+
+ if (hdr == NULL) {
+ e->error = EINVAL;
+ } else if (hdr->nlmsg_type == NLMSG_ERROR) {
+ if (!snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e))
+ e->error = EINVAL;
+ return (e->error == 0);
+ }
+
return (false);
}
+/*
+ * Assumes e is zeroed
+ */
+static inline struct nlmsghdr *
+snl_read_reply_multi(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg_data *e)
+{
+ struct nlmsghdr *hdr = snl_read_reply(ss, nlmsg_seq);
+
+ if (hdr == NULL) {
+ e->error = EINVAL;
+ } else if (hdr->nlmsg_type == NLMSG_ERROR) {
+ if (!snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e))
+ e->error = EINVAL;
+ } if (hdr->nlmsg_type == NLMSG_DONE) {
+ snl_parse_nlmsg(ss, hdr, &snl_donemsg_parser, e);
+ } else
+ return (hdr);
+
+ return (NULL);
+}
+
+
/* writer logic */
struct snl_writer {
char *base;
@@ -849,4 +915,8 @@
return (snl_send(nw->ss, nw->base, offset));
}
+static const struct snl_hdr_parser *snl_all_core_parsers[] = {
+ &snl_errmsg_parser, &snl_donemsg_parser,
+};
+
#endif
diff --git a/sys/netlink/netlink_snl_generic.h b/sys/netlink/netlink_snl_generic.h
new file mode 100644
--- /dev/null
+++ b/sys/netlink/netlink_snl_generic.h
@@ -0,0 +1,97 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _NETLINK_NETLINK_SNL_GENERIC_H_
+#define _NETLINK_NETLINK_SNL_GENERIC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_generic.h>
+#include <netlink/netlink_snl.h>
+
+/* Genetlink helpers */
+static inline struct nlmsghdr *
+snl_create_genl_msg_request(struct snl_writer *nw, int genl_family, uint8_t genl_cmd)
+{
+ assert(nw->hdr == NULL);
+
+ struct nlmsghdr *hdr = snl_reserve_msg_object(nw, struct nlmsghdr);
+ hdr->nlmsg_type = genl_family;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nw->hdr = hdr;
+ struct genlmsghdr *ghdr = snl_reserve_msg_object(nw, struct genlmsghdr);
+ ghdr->cmd = genl_cmd;
+
+ return (hdr);
+}
+
+static struct snl_field_parser snl_fp_genl[] = {};
+
+#define SNL_DECLARE_GENL_PARSER(_name, _np) SNL_DECLARE_PARSER(_name,\
+ struct genlmsghdr, snl_fp_genl, _np)
+
+struct _getfamily_attrs {
+ uint16_t family_id;
+ char *family_name;
+};
+
+#define _IN(_field) offsetof(struct genlmsghdr, _field)
+#define _OUT(_field) offsetof(struct _getfamily_attrs, _field)
+static struct snl_attr_parser _nla_p_getfam[] = {
+ { .type = CTRL_ATTR_FAMILY_ID , .off = _OUT(family_id), .cb = snl_attr_get_uint16 },
+ { .type = CTRL_ATTR_FAMILY_NAME, .off = _OUT(family_name), .cb = snl_attr_get_string },
+};
+#undef _IN
+#undef _OUT
+SNL_DECLARE_GENL_PARSER(_genl_ctrl_getfam_parser, _nla_p_getfam);
+
+static inline uint16_t
+snl_get_genl_family(struct snl_state *ss, const char *family_name)
+{
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
+
+ snl_init_writer(ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, GENL_ID_CTRL, CTRL_CMD_GETFAMILY);
+ snl_add_msg_attr_string(&nw, CTRL_ATTR_FAMILY_NAME, family_name);
+ if (snl_finalize_msg(&nw) == NULL || !snl_send_message(ss, hdr))
+ return (0);
+
+ hdr = snl_read_reply(ss, hdr->nlmsg_seq);
+ if (hdr != NULL && hdr->nlmsg_type != NLMSG_ERROR) {
+ struct _getfamily_attrs attrs = {};
+
+ if (snl_parse_nlmsg(ss, hdr, &_genl_ctrl_getfam_parser, &attrs))
+ return (attrs.family_id);
+ }
+
+ return (0);
+}
+
+static const struct snl_hdr_parser *snl_all_genl_parsers[] = {
+ &_genl_ctrl_getfam_parser,
+};
+
+#endif
diff --git a/tests/sys/netlink/Makefile b/tests/sys/netlink/Makefile
--- a/tests/sys/netlink/Makefile
+++ b/tests/sys/netlink/Makefile
@@ -5,7 +5,7 @@
TESTSDIR= ${TESTSBASE}/sys/netlink
-ATF_TESTS_C += test_snl
+ATF_TESTS_C += test_snl test_snl_generic
ATF_TESTS_PYTEST += test_nl_core.py
ATF_TESTS_PYTEST += test_rtnl_iface.py
ATF_TESTS_PYTEST += test_rtnl_ifaddr.py
diff --git a/tests/sys/netlink/test_snl.c b/tests/sys/netlink/test_snl.c
--- a/tests/sys/netlink/test_snl.c
+++ b/tests/sys/netlink/test_snl.c
@@ -20,13 +20,25 @@
atf_tc_skip("netlink module not loaded");
}
-ATF_TC(snl_verify_parsers);
-ATF_TC_HEAD(snl_verify_parsers, tc)
+ATF_TC(snl_verify_core_parsers);
+ATF_TC_HEAD(snl_verify_core_parsers, tc)
{
- atf_tc_set_md_var(tc, "descr", "Tests snl(3) parsers are correct");
+ atf_tc_set_md_var(tc, "descr", "Tests snl(3) core nlmsg parsers are correct");
}
-ATF_TC_BODY(snl_verify_parsers, tc)
+ATF_TC_BODY(snl_verify_core_parsers, tc)
+{
+ SNL_VERIFY_PARSERS(snl_all_core_parsers);
+
+}
+
+ATF_TC(snl_verify_route_parsers);
+ATF_TC_HEAD(snl_verify_route_parsers, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests snl(3) route parsers are correct");
+}
+
+ATF_TC_BODY(snl_verify_route_parsers, tc)
{
SNL_VERIFY_PARSERS(snl_all_route_parsers);
@@ -61,45 +73,39 @@
ATF_TC_BODY(snl_list_ifaces, tc)
{
struct snl_state ss;
+ struct snl_writer nw;
require_netlink();
if (!snl_init(&ss, NETLINK_ROUTE))
atf_tc_fail("snl_init() failed");
- struct {
- struct nlmsghdr hdr;
- struct ifinfomsg ifmsg;
- } msg = {
- .hdr.nlmsg_type = RTM_GETLINK,
- .hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
- .hdr.nlmsg_seq = snl_get_seq(&ss),
- };
- msg.hdr.nlmsg_len = sizeof(msg);
-
- if (!snl_send(&ss, &msg, sizeof(msg))) {
- snl_free(&ss);
- atf_tc_fail("snl_send() failed");
- }
+ snl_init_writer(&ss, &nw);
+
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK);
+ ATF_CHECK(hdr != NULL);
+ ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL);
+ ATF_CHECK(snl_finalize_msg(&nw) != NULL);
+ uint32_t seq_id = hdr->nlmsg_seq;
- struct nlmsghdr *hdr;
+ ATF_CHECK(snl_send_message(&ss, hdr));
+
+ struct snl_errmsg_data e = {};
int count = 0;
- while ((hdr = snl_read_message(&ss)) != NULL && hdr->nlmsg_type != NLMSG_DONE) {
- if (hdr->nlmsg_seq != msg.hdr.nlmsg_seq)
- continue;
- struct nl_parsed_link link = {};
- if (!snl_parse_nlmsg(&ss, hdr, &link_parser, &link))
- continue;
+ while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) {
count++;
}
+ ATF_REQUIRE(e.error == 0);
+
ATF_REQUIRE_MSG(count > 0, "Empty interface list");
}
ATF_TP_ADD_TCS(tp)
{
+ ATF_TP_ADD_TC(tp, snl_verify_core_parsers);
+ ATF_TP_ADD_TC(tp, snl_verify_route_parsers);
ATF_TP_ADD_TC(tp, snl_list_ifaces);
- ATF_TP_ADD_TC(tp, snl_verify_parsers);
return (atf_no_error());
}
diff --git a/tests/sys/netlink/test_snl_generic.c b/tests/sys/netlink/test_snl_generic.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/netlink/test_snl_generic.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/param.h>
+#include <sys/module.h>
+
+#include <netlink/netlink.h>
+#include "netlink/netlink_snl.h"
+#include "netlink/netlink_snl_generic.h"
+
+#include <atf-c.h>
+
+static void
+require_netlink(void)
+{
+ if (modfind("netlink") == -1)
+ atf_tc_skip("netlink module not loaded");
+}
+
+ATF_TC(snl_verify_genl_parsers);
+ATF_TC_HEAD(snl_verify_genl_parsers, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests snl(3) generic parsers are correct");
+}
+
+ATF_TC_BODY(snl_verify_genl_parsers, tc)
+{
+ SNL_VERIFY_PARSERS(snl_all_genl_parsers);
+
+}
+
+ATF_TC(test_snl_get_genl_family_success);
+ATF_TC_HEAD(test_snl_get_genl_family_success, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests successfull resolution of the 'nlctrl' family");
+}
+
+ATF_TC_BODY(test_snl_get_genl_family_success, tc)
+{
+ struct snl_state ss;
+
+ require_netlink();
+
+ if (!snl_init(&ss, NETLINK_GENERIC))
+ atf_tc_fail("snl_init() failed");
+
+ ATF_CHECK_EQ(snl_get_genl_family(&ss, "nlctrl"), GENL_ID_CTRL);
+}
+
+ATF_TC(test_snl_get_genl_family_failure);
+ATF_TC_HEAD(test_snl_get_genl_family_failure, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests unsuccessfull resolution of 'no-such-family' family");
+}
+
+ATF_TC_BODY(test_snl_get_genl_family_failure, tc)
+{
+ struct snl_state ss;
+
+ require_netlink();
+
+ if (!snl_init(&ss, NETLINK_GENERIC))
+ atf_tc_fail("snl_init() failed");
+
+ ATF_CHECK_EQ(snl_get_genl_family(&ss, "no-such-family"), 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, snl_verify_genl_parsers);
+ ATF_TP_ADD_TC(tp, test_snl_get_genl_family_success);
+ ATF_TP_ADD_TC(tp, test_snl_get_genl_family_failure);
+
+ return (atf_no_error());
+}
+

File Metadata

Mime Type
text/plain
Expires
Mon, Sep 30, 12:50 PM (21 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13153380
Default Alt Text
D39092.id118873.diff (12 KB)

Event Timeline