xref: /freebsd/tests/sys/netlink/test_rtnl_gif.c (revision 9bfb78bf6357f8fc165f85a65f8a8e4048282401)
1 /*
2  * Copyright (c) 2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <sys/param.h>
8 #include <sys/module.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13 #include <net/if_gif.h>
14 
15 #include <netlink/netlink.h>
16 #include <netlink/netlink_route.h>
17 #include <netlink/netlink_snl.h>
18 #include <netlink/netlink_snl_route.h>
19 #include <netlink/netlink_snl_route_compat.h>
20 #include <netlink/netlink_snl_route_parsers.h>
21 
22 #include <atf-c.h>
23 
24 struct nl_parsed_gif {
25 	struct sockaddr		*ifla_local;
26 	struct sockaddr		*ifla_remote;
27 	uint32_t		ifla_flags;
28 };
29 
30 struct nla_gif_info {
31 	const char		*kind;
32 	struct nl_parsed_gif	data;
33 };
34 
35 struct nla_gif_link {
36 	uint32_t		ifi_index;
37 	struct nla_gif_info	linkinfo;
38 };
39 
40 #define _OUT(_field)	offsetof(struct nl_parsed_gif, _field)
41 static const struct snl_attr_parser nla_p_gif[] = {
42 	{ .type = IFLA_IPTUN_LOCAL, .off = _OUT(ifla_local), .cb = snl_attr_get_ip },
43 	{ .type = IFLA_IPTUN_REMOTE, .off = _OUT(ifla_remote), .cb = snl_attr_get_ip },
44 	{ .type = IFLA_IPTUN_FLAGS, .off = _OUT(ifla_flags), .cb = snl_attr_get_uint32 },
45 };
46 #undef _OUT
47 SNL_DECLARE_ATTR_PARSER(gif_linkinfo_data_parser, nla_p_gif);
48 
49 #define _OUT(_field)	offsetof(struct nla_gif_info, _field)
50 static const struct snl_attr_parser ap_gif_linkinfo[] = {
51 	{ .type = IFLA_INFO_KIND, .off = _OUT(kind), .cb = snl_attr_get_string },
52 	{ .type = IFLA_INFO_DATA, .off = _OUT(data),
53 		.arg = &gif_linkinfo_data_parser, .cb = snl_attr_get_nested },
54 };
55 #undef _OUT
56 SNL_DECLARE_ATTR_PARSER(gif_linkinfo_parser, ap_gif_linkinfo);
57 
58 #define _IN(_field)	offsetof(struct ifinfomsg, _field)
59 #define _OUT(_field)	offsetof(struct nla_gif_link, _field)
60 static const struct snl_attr_parser ap_gif_link[] = {
61 	{ .type = IFLA_LINKINFO, .off = _OUT(linkinfo),
62 		.arg = &gif_linkinfo_parser, .cb = snl_attr_get_nested },
63 };
64 
65 static const struct snl_field_parser fp_gif_link[] = {
66 	{ .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 },
67 };
68 #undef _IN
69 #undef _OUT
70 SNL_DECLARE_PARSER(gif_parser, struct ifinfomsg, fp_gif_link, ap_gif_link);
71 
72 ATF_TC(test_rtnl_gif);
ATF_TC_HEAD(test_rtnl_gif,tc)73 ATF_TC_HEAD(test_rtnl_gif, tc)
74 {
75 	atf_tc_set_md_var(tc, "descr", "test gif interface using netlink");
76 	atf_tc_set_md_var(tc, "require.user", "root");
77 	atf_tc_set_md_var(tc, "require.kmods", "netlink if_gif");
78 }
79 
ATF_TC_BODY(test_rtnl_gif,tc)80 ATF_TC_BODY(test_rtnl_gif, tc)
81 {
82 	struct snl_state ss;
83 	struct snl_writer nw;
84 	struct nlmsghdr *hdr, *rx_hdr;
85 	struct in_addr src, dst;
86 	struct nla_gif_link lattrs = {};
87 	struct nl_parsed_gif attrs = {};
88 	struct snl_errmsg_data e = {};
89 	struct ifinfomsg *ifmsg;
90 	int off, off2;
91 
92 	ATF_REQUIRE_MSG(snl_init(&ss, NETLINK_ROUTE), "snl_init() failed");
93 
94 	/* Create gif interface */
95 	snl_init_writer(&ss, &nw);
96 	ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_NEWLINK)) != NULL);
97 	hdr->nlmsg_flags |= (NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST | NLM_F_ACK);
98 	snl_reserve_msg_object(&nw, struct ifinfomsg);
99 
100 	/* Create parameters */
101 	snl_add_msg_attr_string(&nw, IFLA_IFNAME, "gif10");
102 	off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
103         snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gif");
104 	off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
105 
106 	inet_pton(AF_INET, "127.0.0.1", &src);
107 	inet_pton(AF_INET, "127.0.0.2", &dst);
108 	snl_add_msg_attr_ip4(&nw, IFLA_IPTUN_LOCAL, &src);
109 	snl_add_msg_attr_ip4(&nw, IFLA_IPTUN_REMOTE, &dst);
110 	snl_add_msg_attr_u32(&nw, IFLA_IPTUN_FLAGS, (GIF_NOCLAMP | GIF_IGNORE_SOURCE));
111 
112 	snl_end_attr_nested(&nw, off2);
113 	snl_end_attr_nested(&nw, off);
114 
115 	ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
116 	ATF_REQUIRE(snl_send_message(&ss, hdr));
117 	ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
118 	ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e));
119 	ATF_REQUIRE_INTEQ(e.error, 0);
120 
121 	/* Dump gif interface */
122 	snl_init_writer(&ss, &nw);
123 	ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_GETLINK)) != NULL);
124 	hdr->nlmsg_flags |= NLM_F_DUMP;
125 	snl_reserve_msg_object(&nw, struct ifinfomsg);
126 	snl_add_msg_attr_string(&nw, IFLA_IFNAME, "gif10");
127 	off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
128         snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gif");
129 	snl_end_attr_nested(&nw, off);
130 
131 	ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
132 	ATF_REQUIRE(snl_send_message(&ss, hdr));
133 
134 	/* Check parameters */
135 	ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
136 	ATF_CHECK(snl_parse_nlmsg(&ss, rx_hdr, &gif_parser, &lattrs));
137 	attrs = lattrs.linkinfo.data;
138 	ATF_CHECK_STREQ(lattrs.linkinfo.kind, "gif");
139 	ATF_CHECK_INTEQ(attrs.ifla_flags, (GIF_NOCLAMP | GIF_IGNORE_SOURCE));
140 
141 	/* Delete gif interface */
142 	snl_init_writer(&ss, &nw);
143 	ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_DELLINK)) != NULL);
144 	hdr->nlmsg_flags |= (NLM_F_ACK | NLM_F_REQUEST);
145 	ATF_REQUIRE((ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg)) != NULL);
146 	ifmsg->ifi_index = lattrs.ifi_index;
147 	ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
148 	ATF_REQUIRE(snl_send_message(&ss, hdr));
149 	ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
150 	ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e));
151 	ATF_REQUIRE_INTEQ(e.error, 0);
152 }
153 
ATF_TP_ADD_TCS(tp)154 ATF_TP_ADD_TCS(tp)
155 {
156 	ATF_TP_ADD_TC(tp, test_rtnl_gif);
157 
158 	return (atf_no_error());
159 }
160 
161