Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102753000
D39092.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D39092.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 17, 5:19 PM (6 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14682525
Default Alt Text
D39092.diff (12 KB)
Attached To
Mode
D39092: netlink: improve snl(3)
Attached
Detach File
Event Timeline
Log In to Comment