From nobody Sat Apr 08 19:44:54 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 4Pv5Ky66pwz44nb6; Sat, 8 Apr 2023 19:44:54 +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 4Pv5Ky4gRPz442g; Sat, 8 Apr 2023 19:44:54 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680983094; 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=KvasdEZgWuvGpIM2UDOesVUy5B1TxG9LqveY/OCE98A=; b=aXDPaptYirlJ+unbkcBLIYuxOyI6/1HNHjn6fb7adUVyUtS9HlDy2MqJt/jffhT2Yso3WS PWEC4pKwVQ/UxogTkpzqdxUWJ3diHtmo3QcduthOMKyRoejNwFzx5YeEZLrSr9QQdDmTf8 7xtYStJ7wUEYlOWTkSJ7vDjZ54s/ld1AMpW+V6Vtre0mSdHUtLJrzrXkRfkQW1ui+/G9UX 1HOQ+PbQSeNyhDOwc/s0resAWaTn19Xnu1cGuXV8YXZ6BEA9spCBmUgY65FirIGDqeH6Ro j7gUeBzRImXYzZx8sKYkQ7n+cIfDxvZbl1LjvLGS+PLncX7prlnrAdOpw9wSbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680983094; 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=KvasdEZgWuvGpIM2UDOesVUy5B1TxG9LqveY/OCE98A=; b=cnnTYjT/9P+MOc+hMuBJ/PLGNXVwknpJOjQTa4J95pXzlQ/BoNpAttyHE1rIUWNPyrUai9 4od0p1+92UbgHYgbCh7PTtimgIbzkwHGlyYWTxE2oOQ9Pl+1DDqLgNSg+lcowrW2pdG7nh AcDx+bd6A1eEZakWft7z0NGBwMi1XFgtoWw1wtT2A8c9UWp8nkh+ZLYJV2p5J41rOzXP2Y 1yIgkK6rjpQ2/kyNif8nuSSDJ9h/24WRc2H+FgQc1e3hWSeiboqGmDFQ3gRDvrt9qBVejj qob1SmXj8zUKMUG5JbgAbZxgunkTkza85zxYWm4mD0CRzHL3fMEIjJTCwYa4QQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1680983094; a=rsa-sha256; cv=none; b=T1PxbYsTpq0DZVNBDl9VgB3IYWu3f5eRznOow7Yn6xoq7Besiblgk6BHAN+hBicVVb22mF bPypSGaXhWvEHe/zZKN2ivMaQKgXnHJI8jOnWGU0Jg/TroImajSYI5G0ZTm1hClPHebj+W C48Xn0votuFdQuiz4UD6Ki3aebrpgSLp0AOzOt+O0tnz9LgFsVPxo0zymXVLXcuyJpvp6n 8fbORAGvoE+MBkD1x4l+lsoiylEl9sWk4G2jWfrQ2hhnmHi8iSeKzht3O2i8BlLEQ0PTk3 dGigwPPT/ZSyVGPDFOPX+nSMT3uLvCDTTkN2xV0ZteLO96rFPPs5VQTzkvLr5g== 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 4Pv5Ky3mRjzfst; Sat, 8 Apr 2023 19:44:54 +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 338JisC5018773; Sat, 8 Apr 2023 19:44:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 338JisWN018772; Sat, 8 Apr 2023 19:44:54 GMT (envelope-from git) Date: Sat, 8 Apr 2023 19:44:54 GMT Message-Id: <202304081944.338JisWN018772@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: a5e5f4105346 - stable/13 - netlink: improve 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: a5e5f410534627f306778ff38ed942f714962f9b Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=a5e5f410534627f306778ff38ed942f714962f9b commit a5e5f410534627f306778ff38ed942f714962f9b Author: Alexander V. Chernikov AuthorDate: 2023-03-15 13:56:26 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-04-08 19:11:41 +0000 netlink: improve snl(3) Summary: * add snl_send_message() as a convenient send wrapper * add signed integer parsers * add snl_read_reply_code() to simplify operation result checks * add snl_read_reply_multi() to simplify reading multipart messages * add snl_create_genl_msg_request() * add snl_get_genl_family() to simplify family name->id resolution * add tests for some of the functionality Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D39092 MFC after: 2 weeks (cherry picked from commit 73ae25c174b515616050496dea764a943796efef) --- sys/netlink/netlink_snl.h | 104 +++++++++++++++++++++++++++++------ sys/netlink/netlink_snl_generic.h | 97 ++++++++++++++++++++++++++++++++ tests/sys/netlink/Makefile | 2 +- tests/sys/netlink/test_snl.c | 58 ++++++++++--------- tests/sys/netlink/test_snl_generic.c | 77 ++++++++++++++++++++++++++ 5 files changed, 294 insertions(+), 44 deletions(-) diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h index 31b90003b519..be512b67c7ec 100644 --- a/sys/netlink/netlink_snl.h +++ b/sys/netlink/netlink_snl.h @@ -258,6 +258,14 @@ snl_send(struct snl_state *ss, void *data, int sz) 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 @@ snl_read_message(struct snl_state *ss) 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 @@ snl_read_reply(struct snl_state *ss, uint32_t nlmsg_seq) 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 @@ snl_attr_get_uint64(struct snl_state *ss __unused, struct nlattr *nla, 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 @@ static const struct snl_field_parser nlf_p_errmsg[] = { #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 @@ snl_send_msgs(struct snl_writer *nw) 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 index 000000000000..a725e6948b43 --- /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 + * + * 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 +#include +#include + +/* 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 index 45095ac95309..656582be33b6 100644 --- a/tests/sys/netlink/Makefile +++ b/tests/sys/netlink/Makefile @@ -5,7 +5,7 @@ WARNS?= 1 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 index daacc1aaacec..85bdff7fb163 100644 --- a/tests/sys/netlink/test_snl.c +++ b/tests/sys/netlink/test_snl.c @@ -20,13 +20,25 @@ require_netlink(void) 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 @@ SNL_DECLARE_PARSER(link_parser, struct ifinfomsg, fp_link, ap_link); 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 index 000000000000..c65d134f080d --- /dev/null +++ b/tests/sys/netlink/test_snl_generic.c @@ -0,0 +1,77 @@ +#include +#include +#include + +#include +#include + +#include +#include "netlink/netlink_snl.h" +#include "netlink/netlink_snl_generic.h" + +#include + +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()); +} +