xref: /freebsd/tests/sys/net/routing/test_rtsock_l3.c (revision 272bd6985f72a2c7dad0d904449d6b6ec0982d9c)
1775dc861SAlexander V. Chernikov /*-
2775dc861SAlexander V. Chernikov  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3775dc861SAlexander V. Chernikov  *
4775dc861SAlexander V. Chernikov  * Copyright (c) 2019 Alexander V. Chernikov
5775dc861SAlexander V. Chernikov  *
6775dc861SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
7775dc861SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
8775dc861SAlexander V. Chernikov  * are met:
9775dc861SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
10775dc861SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
11775dc861SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
12775dc861SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
13775dc861SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
14775dc861SAlexander V. Chernikov  *
15775dc861SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16775dc861SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17775dc861SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18775dc861SAlexander V. Chernikov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19775dc861SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20775dc861SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21775dc861SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22775dc861SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23775dc861SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24775dc861SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25775dc861SAlexander V. Chernikov  * SUCH DAMAGE.
26775dc861SAlexander V. Chernikov  *
27775dc861SAlexander V. Chernikov  * $FreeBSD$
28775dc861SAlexander V. Chernikov  */
29775dc861SAlexander V. Chernikov 
30775dc861SAlexander V. Chernikov #include "rtsock_common.h"
31775dc861SAlexander V. Chernikov #include "rtsock_config.h"
32e02d3fe7SAlexander V. Chernikov #include "sys/types.h"
33e02d3fe7SAlexander V. Chernikov #include <sys/time.h>
34e02d3fe7SAlexander V. Chernikov #include <sys/ioctl.h>
35e02d3fe7SAlexander V. Chernikov 
36e02d3fe7SAlexander V. Chernikov #include "net/bpf.h"
37775dc861SAlexander V. Chernikov 
38ddc75076SAlexander V. Chernikov static void
39ddc75076SAlexander V. Chernikov jump_vnet(struct rtsock_test_config *c, const atf_tc_t *tc)
40ddc75076SAlexander V. Chernikov {
41ddc75076SAlexander V. Chernikov 	char vnet_name[512];
42ddc75076SAlexander V. Chernikov 
43ddc75076SAlexander V. Chernikov 	snprintf(vnet_name, sizeof(vnet_name), "vt-%s", atf_tc_get_ident(tc));
44ddc75076SAlexander V. Chernikov 	RLOG("jumping to %s", vnet_name);
45ddc75076SAlexander V. Chernikov 
46*272bd698SAlexander V. Chernikov 	vnet_switch(vnet_name, c->ifnames, c->num_interfaces);
47ddc75076SAlexander V. Chernikov 
48ddc75076SAlexander V. Chernikov 	/* Update ifindex cache */
49ddc75076SAlexander V. Chernikov 	c->ifindex = if_nametoindex(c->ifname);
50ddc75076SAlexander V. Chernikov }
51ddc75076SAlexander V. Chernikov 
52775dc861SAlexander V. Chernikov static inline struct rtsock_test_config *
53e02d3fe7SAlexander V. Chernikov presetup_ipv6_iface(const atf_tc_t *tc)
54775dc861SAlexander V. Chernikov {
55775dc861SAlexander V. Chernikov 	struct rtsock_test_config *c;
56775dc861SAlexander V. Chernikov 	int ret;
57775dc861SAlexander V. Chernikov 
58*272bd698SAlexander V. Chernikov 	c = config_setup(tc, NULL);
59775dc861SAlexander V. Chernikov 
60ddc75076SAlexander V. Chernikov 	jump_vnet(c, tc);
61ddc75076SAlexander V. Chernikov 
62775dc861SAlexander V. Chernikov 	ret = iface_turn_up(c->ifname);
63775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
64775dc861SAlexander V. Chernikov 
65775dc861SAlexander V. Chernikov 	ret = iface_enable_ipv6(c->ifname);
66775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifname);
67775dc861SAlexander V. Chernikov 
68e02d3fe7SAlexander V. Chernikov 	return (c);
69e02d3fe7SAlexander V. Chernikov }
70e02d3fe7SAlexander V. Chernikov 
71e02d3fe7SAlexander V. Chernikov static inline struct rtsock_test_config *
72e02d3fe7SAlexander V. Chernikov presetup_ipv6(const atf_tc_t *tc)
73e02d3fe7SAlexander V. Chernikov {
74e02d3fe7SAlexander V. Chernikov 	struct rtsock_test_config *c;
75e02d3fe7SAlexander V. Chernikov 	int ret;
76e02d3fe7SAlexander V. Chernikov 
77e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
78e02d3fe7SAlexander V. Chernikov 
79775dc861SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
80775dc861SAlexander V. Chernikov 
81775dc861SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
82775dc861SAlexander V. Chernikov 
83775dc861SAlexander V. Chernikov 	return (c);
84775dc861SAlexander V. Chernikov }
85775dc861SAlexander V. Chernikov 
86775dc861SAlexander V. Chernikov static inline struct rtsock_test_config *
87e02d3fe7SAlexander V. Chernikov presetup_ipv4_iface(const atf_tc_t *tc)
88e02d3fe7SAlexander V. Chernikov {
89e02d3fe7SAlexander V. Chernikov 	struct rtsock_test_config *c;
90e02d3fe7SAlexander V. Chernikov 	int ret;
91e02d3fe7SAlexander V. Chernikov 
92*272bd698SAlexander V. Chernikov 	c = config_setup(tc, NULL);
93e02d3fe7SAlexander V. Chernikov 
94ddc75076SAlexander V. Chernikov 	jump_vnet(c, tc);
95ddc75076SAlexander V. Chernikov 
96e02d3fe7SAlexander V. Chernikov 	ret = iface_turn_up(c->ifname);
97e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
98e02d3fe7SAlexander V. Chernikov 
99e02d3fe7SAlexander V. Chernikov 	return (c);
100e02d3fe7SAlexander V. Chernikov }
101e02d3fe7SAlexander V. Chernikov 
102e02d3fe7SAlexander V. Chernikov static inline struct rtsock_test_config *
103775dc861SAlexander V. Chernikov presetup_ipv4(const atf_tc_t *tc)
104775dc861SAlexander V. Chernikov {
105775dc861SAlexander V. Chernikov 	struct rtsock_test_config *c;
106775dc861SAlexander V. Chernikov 	int ret;
107775dc861SAlexander V. Chernikov 
108e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
109775dc861SAlexander V. Chernikov 
110775dc861SAlexander V. Chernikov 	/* assumes ifconfig doing IFF_UP */
111775dc861SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
112775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
113775dc861SAlexander V. Chernikov 
114775dc861SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
115775dc861SAlexander V. Chernikov 
116775dc861SAlexander V. Chernikov 	return (c);
117775dc861SAlexander V. Chernikov }
118775dc861SAlexander V. Chernikov 
119775dc861SAlexander V. Chernikov 
120775dc861SAlexander V. Chernikov static void
121775dc861SAlexander V. Chernikov prepare_v4_network(struct rtsock_test_config *c, struct sockaddr_in *dst,
122775dc861SAlexander V. Chernikov   struct sockaddr_in *mask, struct sockaddr_in *gw)
123775dc861SAlexander V. Chernikov {
124775dc861SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
125775dc861SAlexander V. Chernikov 	sa_fill_mask4(mask, c->plen4 + 1);
126775dc861SAlexander V. Chernikov 	*dst = c->net4;
127775dc861SAlexander V. Chernikov 	/* Calculate GW as last-net-address - 1 */
128775dc861SAlexander V. Chernikov 	*gw = c->net4;
129775dc861SAlexander V. Chernikov 	gw->sin_addr.s_addr = htonl((ntohl(c->net4.sin_addr.s_addr) | ~ntohl(c->mask4.sin_addr.s_addr)) - 1);
130775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)dst, 0);
131775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)mask, 0);
132775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)gw, 0);
133775dc861SAlexander V. Chernikov }
134775dc861SAlexander V. Chernikov 
135775dc861SAlexander V. Chernikov static void
136775dc861SAlexander V. Chernikov prepare_v6_network(struct rtsock_test_config *c, struct sockaddr_in6 *dst,
137775dc861SAlexander V. Chernikov   struct sockaddr_in6 *mask, struct sockaddr_in6 *gw)
138775dc861SAlexander V. Chernikov {
139775dc861SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
140775dc861SAlexander V. Chernikov 	sa_fill_mask6(mask, c->plen6 + 1);
141775dc861SAlexander V. Chernikov 	*dst = c->net6;
142775dc861SAlexander V. Chernikov 	/* Calculate GW as last-net-address - 1 */
143775dc861SAlexander V. Chernikov 	*gw = c->net6;
144775dc861SAlexander V. Chernikov #define _s6_addr32 __u6_addr.__u6_addr32
145775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[0] = htonl((ntohl(gw->sin6_addr._s6_addr32[0]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[0])));
146775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[1] = htonl((ntohl(gw->sin6_addr._s6_addr32[1]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[1])));
147775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[2] = htonl((ntohl(gw->sin6_addr._s6_addr32[2]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[2])));
148775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[3] = htonl((ntohl(gw->sin6_addr._s6_addr32[3]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[3])) - 1);
149775dc861SAlexander V. Chernikov #undef _s6_addr32
150775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)dst, 0);
151775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)mask, 0);
152775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)gw, 0);
153775dc861SAlexander V. Chernikov }
154775dc861SAlexander V. Chernikov 
155775dc861SAlexander V. Chernikov static void
156775dc861SAlexander V. Chernikov prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
157775dc861SAlexander V. Chernikov   struct sockaddr *mask, struct sockaddr *gw)
158775dc861SAlexander V. Chernikov {
159775dc861SAlexander V. Chernikov 
160775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message(rtm, cmd, dst, mask, gw);
161775dc861SAlexander V. Chernikov 
162775dc861SAlexander V. Chernikov 	if (cmd == RTM_ADD || cmd == RTM_CHANGE)
163775dc861SAlexander V. Chernikov 		rtm->rtm_flags |= RTF_STATIC;
164775dc861SAlexander V. Chernikov }
165775dc861SAlexander V. Chernikov 
166775dc861SAlexander V. Chernikov static void
167775dc861SAlexander V. Chernikov verify_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
168775dc861SAlexander V. Chernikov   struct sockaddr *mask, struct sockaddr *gw)
169775dc861SAlexander V. Chernikov {
170775dc861SAlexander V. Chernikov 	char msg[512];
171775dc861SAlexander V. Chernikov 	struct sockaddr *sa;
172775dc861SAlexander V. Chernikov 	int ret;
173775dc861SAlexander V. Chernikov 
174775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_type == cmd,
175775dc861SAlexander V. Chernikov 	    "expected %s message, got %d (%s)", rtsock_print_cmdtype(cmd),
176775dc861SAlexander V. Chernikov 	    rtm->rtm_type, rtsock_print_cmdtype(rtm->rtm_type));
177775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_errno == 0,
178775dc861SAlexander V. Chernikov 	    "got got errno %d as message reply", rtm->rtm_errno);
179775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->_rtm_spare1 == 0,
180775dc861SAlexander V. Chernikov 	    "expected rtm_spare==0, got %d", rtm->_rtm_spare1);
181775dc861SAlexander V. Chernikov 
182775dc861SAlexander V. Chernikov 	/* kernel MAY return more sockaddrs, including RTA_IFP / RTA_IFA, so verify the needed ones */
183775dc861SAlexander V. Chernikov 	if (dst != NULL) {
184775dc861SAlexander V. Chernikov 		sa = rtsock_find_rtm_sa(rtm, RTA_DST);
185775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "DST is not set");
186775dc861SAlexander V. Chernikov 		ret = sa_equal_msg(sa, dst, msg, sizeof(msg));
187775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
188775dc861SAlexander V. Chernikov 	}
189775dc861SAlexander V. Chernikov 
190775dc861SAlexander V. Chernikov 	if (mask != NULL) {
191775dc861SAlexander V. Chernikov 		sa = rtsock_find_rtm_sa(rtm, RTA_NETMASK);
192775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "NETMASK is not set");
193775dc861SAlexander V. Chernikov 		ret = sa_equal_msg(sa, mask, msg, sizeof(msg));
19434a5582cSAlexander V. Chernikov 		ret = 1;
195775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "NETMASK sa diff: %s", msg);
196775dc861SAlexander V. Chernikov 	}
197775dc861SAlexander V. Chernikov 
198775dc861SAlexander V. Chernikov 	if (gw != NULL) {
199775dc861SAlexander V. Chernikov 		sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
200775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
201775dc861SAlexander V. Chernikov 		ret = sa_equal_msg(sa, gw, msg, sizeof(msg));
202775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
203775dc861SAlexander V. Chernikov 	}
204775dc861SAlexander V. Chernikov }
205775dc861SAlexander V. Chernikov 
206775dc861SAlexander V. Chernikov static void
207775dc861SAlexander V. Chernikov verify_route_message_extra(struct rt_msghdr *rtm, int ifindex, int rtm_flags)
208775dc861SAlexander V. Chernikov {
209775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_index == ifindex,
210775dc861SAlexander V. Chernikov 	    "expected ifindex %d, got %d", ifindex, rtm->rtm_index);
211775dc861SAlexander V. Chernikov 
212ac0bea76SAlexander V. Chernikov 	if (rtm->rtm_flags != rtm_flags) {
213ac0bea76SAlexander V. Chernikov 		char got_flags[64], expected_flags[64];
214ac0bea76SAlexander V. Chernikov 		rtsock_print_rtm_flags(got_flags, sizeof(got_flags),
215ac0bea76SAlexander V. Chernikov 		    rtm->rtm_flags);
216ac0bea76SAlexander V. Chernikov 		rtsock_print_rtm_flags(expected_flags, sizeof(expected_flags),
217ac0bea76SAlexander V. Chernikov 		    rtm_flags);
218ac0bea76SAlexander V. Chernikov 
219775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == rtm_flags,
220ac0bea76SAlexander V. Chernikov 		    "expected flags: 0x%X %s, got 0x%X %s",
221ac0bea76SAlexander V. Chernikov 		    rtm_flags, expected_flags,
222ac0bea76SAlexander V. Chernikov 		    rtm->rtm_flags, got_flags);
223ac0bea76SAlexander V. Chernikov 	}
224e02d3fe7SAlexander V. Chernikov }
225e02d3fe7SAlexander V. Chernikov 
226e02d3fe7SAlexander V. Chernikov static void
227e02d3fe7SAlexander V. Chernikov verify_link_gateway(struct rt_msghdr *rtm, int ifindex)
228e02d3fe7SAlexander V. Chernikov {
229e02d3fe7SAlexander V. Chernikov 	struct sockaddr *sa;
230e02d3fe7SAlexander V. Chernikov 	struct sockaddr_dl *sdl;
231e02d3fe7SAlexander V. Chernikov 
232e02d3fe7SAlexander V. Chernikov 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
233e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
234e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa->sa_family == AF_LINK, "GW sa family is %d", sa->sa_family);
235e02d3fe7SAlexander V. Chernikov 	sdl = (struct sockaddr_dl *)sa;
236e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_index == ifindex, "GW ifindex is %d", sdl->sdl_index);
237775dc861SAlexander V. Chernikov }
238775dc861SAlexander V. Chernikov 
239775dc861SAlexander V. Chernikov /* TESTS */
240775dc861SAlexander V. Chernikov 
241775dc861SAlexander V. Chernikov #define	DECLARE_TEST_VARS					\
242775dc861SAlexander V. Chernikov 	char buffer[2048];					\
243775dc861SAlexander V. Chernikov 	struct rtsock_test_config *c;				\
244775dc861SAlexander V. Chernikov 	struct rt_msghdr *rtm = (struct rt_msghdr *)buffer;	\
245775dc861SAlexander V. Chernikov 	struct sockaddr *sa;					\
246775dc861SAlexander V. Chernikov 	int ret;						\
247775dc861SAlexander V. Chernikov 								\
248775dc861SAlexander V. Chernikov 
249775dc861SAlexander V. Chernikov #define	DESCRIBE_ROOT_TEST(_msg)	config_describe_root_test(tc, _msg)
250ddc75076SAlexander V. Chernikov #define	CLEANUP_AFTER_TEST	config_generic_cleanup(tc)
251775dc861SAlexander V. Chernikov 
252e02d3fe7SAlexander V. Chernikov #define	RTM_DECLARE_ROOT_TEST(_name, _descr)			\
253e02d3fe7SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(_name);					\
254e02d3fe7SAlexander V. Chernikov ATF_TC_HEAD(_name, tc)						\
255e02d3fe7SAlexander V. Chernikov {								\
256e02d3fe7SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST(_descr);				\
257e02d3fe7SAlexander V. Chernikov }								\
258e02d3fe7SAlexander V. Chernikov ATF_TC_CLEANUP(_name, tc)					\
259e02d3fe7SAlexander V. Chernikov {								\
260e02d3fe7SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;					\
261e02d3fe7SAlexander V. Chernikov }
262775dc861SAlexander V. Chernikov 
263775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_exact_success);
264775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_exact_success, tc)
265775dc861SAlexander V. Chernikov {
266775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with exact prefix lookup on an interface prefix");
267775dc861SAlexander V. Chernikov }
268775dc861SAlexander V. Chernikov 
269775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_exact_success, tc)
270775dc861SAlexander V. Chernikov {
271775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
272775dc861SAlexander V. Chernikov 
273775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
274775dc861SAlexander V. Chernikov 
275775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
276775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
277775dc861SAlexander V. Chernikov 
278775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
279775dc861SAlexander V. Chernikov 
280775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
281775dc861SAlexander V. Chernikov 
282775dc861SAlexander V. Chernikov 	/*
283775dc861SAlexander V. Chernikov 	 * RTM_GET: Report Metrics: len 240, pid: 45072, seq 42, errno 0, flags: <UP,DONE,PINNED>
284775dc861SAlexander V. Chernikov 	 * sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
285775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
286775dc861SAlexander V. Chernikov 	 *  af=link len=54 sdl_index=3 if_name=tap4242 hd={36, 12, 03, 00, 06, 00{49}}
287775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.0 hd={10, 02, FF{5}, 00{9}}
288775dc861SAlexander V. Chernikov 	 */
289775dc861SAlexander V. Chernikov 
290775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
291775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
292775dc861SAlexander V. Chernikov 
293775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_UP | RTF_DONE | RTF_PINNED);
294775dc861SAlexander V. Chernikov 
295775dc861SAlexander V. Chernikov 	/* Explicitly verify gateway for the interface route */
296e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
297775dc861SAlexander V. Chernikov 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
298775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
299775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa->sa_family == AF_LINK, "GW sa family is %d", sa->sa_family);
300775dc861SAlexander V. Chernikov 	struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
301775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_index == c->ifindex, "GW ifindex is %d", sdl->sdl_index);
302775dc861SAlexander V. Chernikov }
303775dc861SAlexander V. Chernikov 
304775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_exact_success, tc)
305775dc861SAlexander V. Chernikov {
306775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
307775dc861SAlexander V. Chernikov }
308775dc861SAlexander V. Chernikov 
309775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_lpm_success);
310775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_lpm_success, tc)
311775dc861SAlexander V. Chernikov {
312775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with address lookup on an existing prefix");
313775dc861SAlexander V. Chernikov }
314775dc861SAlexander V. Chernikov 
315775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_lpm_success, tc)
316775dc861SAlexander V. Chernikov {
317775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
318775dc861SAlexander V. Chernikov 
319775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
320775dc861SAlexander V. Chernikov 
321775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4, NULL, NULL);
322775dc861SAlexander V. Chernikov 
323775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
324775dc861SAlexander V. Chernikov 
325e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
326775dc861SAlexander V. Chernikov 
327775dc861SAlexander V. Chernikov 	/*
328775dc861SAlexander V. Chernikov 	 * RTM_GET: Report Metrics: len 312, pid: 67074, seq 1, errno 0, flags:<UP,DONE,PINNED>
329775dc861SAlexander V. Chernikov 	 * locks:  inits:
330775dc861SAlexander V. Chernikov 	 * sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
331775dc861SAlexander V. Chernikov 	 * 10.0.0.0 link#1 255.255.255.0 vtnet0:52.54.0.42.f.ef 10.0.0.157
332775dc861SAlexander V. Chernikov 	 */
333775dc861SAlexander V. Chernikov 
334775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
335775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
336775dc861SAlexander V. Chernikov 
337775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_UP | RTF_DONE | RTF_PINNED);
338775dc861SAlexander V. Chernikov }
339775dc861SAlexander V. Chernikov 
340775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_lpm_success, tc)
341775dc861SAlexander V. Chernikov {
342775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
343775dc861SAlexander V. Chernikov }
344775dc861SAlexander V. Chernikov 
345775dc861SAlexander V. Chernikov 
346775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_empty_dst_failure);
347775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_empty_dst_failure, tc)
348775dc861SAlexander V. Chernikov {
349775dc861SAlexander V. Chernikov 
350775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with empty DST addr");
351775dc861SAlexander V. Chernikov }
352775dc861SAlexander V. Chernikov 
353775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_empty_dst_failure, tc)
354775dc861SAlexander V. Chernikov {
355775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
356*272bd698SAlexander V. Chernikov 	struct rtsock_config_options co;
357775dc861SAlexander V. Chernikov 
358*272bd698SAlexander V. Chernikov 	bzero(&co, sizeof(co));
359*272bd698SAlexander V. Chernikov 	co.num_interfaces = 0;
360*272bd698SAlexander V. Chernikov 
361*272bd698SAlexander V. Chernikov 	c = config_setup(tc,&co);
362775dc861SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
363775dc861SAlexander V. Chernikov 
364775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message(rtm, RTM_GET, NULL,
365775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
366775dc861SAlexander V. Chernikov 	rtsock_update_rtm_len(rtm);
367775dc861SAlexander V. Chernikov 
368775dc861SAlexander V. Chernikov 	write(c->rtsock_fd, rtm, rtm->rtm_msglen);
369775dc861SAlexander V. Chernikov 	ATF_CHECK_ERRNO(EINVAL, write(c->rtsock_fd, rtm, rtm->rtm_msglen));
370775dc861SAlexander V. Chernikov }
371775dc861SAlexander V. Chernikov 
372775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_empty_dst_failure, tc)
373775dc861SAlexander V. Chernikov {
374775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
375775dc861SAlexander V. Chernikov }
376775dc861SAlexander V. Chernikov 
377775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_hostbits_failure);
378775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_hostbits_failure, tc)
379775dc861SAlexander V. Chernikov {
380775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with prefix with some hosts-bits set");
381775dc861SAlexander V. Chernikov }
382775dc861SAlexander V. Chernikov 
383775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_hostbits_failure, tc)
384775dc861SAlexander V. Chernikov {
385775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
386775dc861SAlexander V. Chernikov 
387775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
388775dc861SAlexander V. Chernikov 
389775dc861SAlexander V. Chernikov 	/* Q the same prefix */
390775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->addr4,
391775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
392775dc861SAlexander V. Chernikov 	rtsock_update_rtm_len(rtm);
393775dc861SAlexander V. Chernikov 
394775dc861SAlexander V. Chernikov 	ATF_CHECK_ERRNO(ESRCH, write(c->rtsock_fd, rtm, rtm->rtm_msglen));
395775dc861SAlexander V. Chernikov }
396775dc861SAlexander V. Chernikov 
397775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_hostbits_failure, tc)
398775dc861SAlexander V. Chernikov {
399775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
400775dc861SAlexander V. Chernikov }
401775dc861SAlexander V. Chernikov 
402775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v4_gw_direct_success);
403775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v4_gw_direct_success, tc)
404775dc861SAlexander V. Chernikov {
405775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv4 route addition with directly-reachable GW specified by IP");
406775dc861SAlexander V. Chernikov }
407775dc861SAlexander V. Chernikov 
408775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_gw_direct_success, tc)
409775dc861SAlexander V. Chernikov {
410775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
411775dc861SAlexander V. Chernikov 
412775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
413775dc861SAlexander V. Chernikov 
414775dc861SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
415775dc861SAlexander V. Chernikov 	struct sockaddr_in mask4;
416775dc861SAlexander V. Chernikov 	struct sockaddr_in net4;
417775dc861SAlexander V. Chernikov 	struct sockaddr_in gw4;
418775dc861SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
419775dc861SAlexander V. Chernikov 
420775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
421775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
422775dc861SAlexander V. Chernikov 
423775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
424775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
425775dc861SAlexander V. Chernikov 
426775dc861SAlexander V. Chernikov 	/*
427775dc861SAlexander V. Chernikov 	 * RTM_ADD: Add Route: len 200, pid: 46068, seq 42, errno 0, flags:<GATEWAY,DONE,STATIC>
428775dc861SAlexander V. Chernikov 	 * locks:  inits:
429775dc861SAlexander V. Chernikov 	 * sockaddrs: <DST,GATEWAY,NETMASK>
430775dc861SAlexander V. Chernikov 	 *  192.0.2.0 192.0.2.254 255.255.255.128
431775dc861SAlexander V. Chernikov 	 */
432775dc861SAlexander V. Chernikov 
433775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
434775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
435775dc861SAlexander V. Chernikov 	/* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
436775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
437775dc861SAlexander V. Chernikov }
438775dc861SAlexander V. Chernikov 
439775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v4_gw_direct_success, tc)
440775dc861SAlexander V. Chernikov {
441775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
442775dc861SAlexander V. Chernikov }
443775dc861SAlexander V. Chernikov 
444775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_del_v4_prefix_nogw_success);
445775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_del_v4_prefix_nogw_success, tc)
446775dc861SAlexander V. Chernikov {
447775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv4 route removal without specifying gateway");
448775dc861SAlexander V. Chernikov }
449775dc861SAlexander V. Chernikov 
450775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v4_prefix_nogw_success, tc)
451775dc861SAlexander V. Chernikov {
452775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
453775dc861SAlexander V. Chernikov 
454775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
455775dc861SAlexander V. Chernikov 
456775dc861SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
457775dc861SAlexander V. Chernikov 	struct sockaddr_in mask4;
458775dc861SAlexander V. Chernikov 	struct sockaddr_in net4;
459775dc861SAlexander V. Chernikov 	struct sockaddr_in gw4;
460775dc861SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
461775dc861SAlexander V. Chernikov 
462775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
463775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
464775dc861SAlexander V. Chernikov 
465775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
466775dc861SAlexander V. Chernikov 
467775dc861SAlexander V. Chernikov 	/* Route has been added successfully, try to delete it */
468775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
469775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, NULL);
470775dc861SAlexander V. Chernikov 
471775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
472775dc861SAlexander V. Chernikov 
473775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
474775dc861SAlexander V. Chernikov 
475775dc861SAlexander V. Chernikov 	/*
476775dc861SAlexander V. Chernikov 	 * RTM_DELETE: Delete Route: len 200, pid: 46417, seq 43, errno 0, flags: <GATEWAY,DONE,STATIC>
477775dc861SAlexander V. Chernikov 	 * sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
478775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
479775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.254 hd={10, 02, 00{2}, C0, 00, 02, FE, 00{8}}
480775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.128 hd={10, 02, FF{5}, 80, 00{8}}
481775dc861SAlexander V. Chernikov 	 */
482775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
483775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
484775dc861SAlexander V. Chernikov 
485775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
486775dc861SAlexander V. Chernikov }
487775dc861SAlexander V. Chernikov 
488775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_del_v4_prefix_nogw_success, tc)
489775dc861SAlexander V. Chernikov {
490775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
491775dc861SAlexander V. Chernikov }
492775dc861SAlexander V. Chernikov 
493*272bd698SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_change_v4_gw_success,
494*272bd698SAlexander V. Chernikov     "Tests IPv4 gateway change");
495*272bd698SAlexander V. Chernikov 
496*272bd698SAlexander V. Chernikov ATF_TC_BODY(rtm_change_v4_gw_success, tc)
497*272bd698SAlexander V. Chernikov {
498*272bd698SAlexander V. Chernikov 	DECLARE_TEST_VARS;
499*272bd698SAlexander V. Chernikov 	struct rtsock_config_options co;
500*272bd698SAlexander V. Chernikov 
501*272bd698SAlexander V. Chernikov 	bzero(&co, sizeof(co));
502*272bd698SAlexander V. Chernikov 	co.num_interfaces = 2;
503*272bd698SAlexander V. Chernikov 
504*272bd698SAlexander V. Chernikov 	c = config_setup(tc, &co);
505*272bd698SAlexander V. Chernikov 	jump_vnet(c, tc);
506*272bd698SAlexander V. Chernikov 
507*272bd698SAlexander V. Chernikov 	ret = iface_turn_up(c->ifnames[0]);
508*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[0]);
509*272bd698SAlexander V. Chernikov 	ret = iface_turn_up(c->ifnames[1]);
510*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[1]);
511*272bd698SAlexander V. Chernikov 
512*272bd698SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifnames[0], c->addr4_str, c->plen4);
513*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
514*272bd698SAlexander V. Chernikov 
515*272bd698SAlexander V. Chernikov 	/* Use 198.51.100.0/24 "TEST-NET-2" for the second interface */
516*272bd698SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifnames[1], "198.51.100.1", 24);
517*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
518*272bd698SAlexander V. Chernikov 
519*272bd698SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
520*272bd698SAlexander V. Chernikov 
521*272bd698SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
522*272bd698SAlexander V. Chernikov 	struct sockaddr_in mask4;
523*272bd698SAlexander V. Chernikov 	struct sockaddr_in net4;
524*272bd698SAlexander V. Chernikov 	struct sockaddr_in gw4;
525*272bd698SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
526*272bd698SAlexander V. Chernikov 
527*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
528*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
529*272bd698SAlexander V. Chernikov 
530*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
531*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
532*272bd698SAlexander V. Chernikov 
533*272bd698SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
534*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
535*272bd698SAlexander V. Chernikov 
536*272bd698SAlexander V. Chernikov 	/* Change gateway to the one on desiding on the other interface */
537*272bd698SAlexander V. Chernikov 	inet_pton(AF_INET, "198.51.100.2", &gw4.sin_addr.s_addr);
538*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
539*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
540*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
541*272bd698SAlexander V. Chernikov 
542*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
543*272bd698SAlexander V. Chernikov 
544*272bd698SAlexander V. Chernikov 	verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
545*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
546*272bd698SAlexander V. Chernikov 
547*272bd698SAlexander V. Chernikov 	verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
548*272bd698SAlexander V. Chernikov 	    RTF_DONE | RTF_GATEWAY | RTF_STATIC);
549*272bd698SAlexander V. Chernikov 
550*272bd698SAlexander V. Chernikov 	/* Verify the change has actually taken place */
551*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4,
552*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, NULL);
553*272bd698SAlexander V. Chernikov 
554*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
555*272bd698SAlexander V. Chernikov 
556*272bd698SAlexander V. Chernikov 	/*
557*272bd698SAlexander V. Chernikov 	 * RTM_GET: len 200, pid: 3894, seq 44, errno 0, flags: <UP,GATEWAY,DONE,STATIC>
558*272bd698SAlexander V. Chernikov 	 *  sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
559*272bd698SAlexander V. Chernikov  	 *  af=inet len=16 addr=192.0.2.0 hd={x10, x02, x00{2}, xC0, x00, x02, x00{9}}
560*272bd698SAlexander V. Chernikov 	 *  af=inet len=16 addr=198.51.100.2 hd={x10, x02, x00{2}, xC6, x33, x64, x02, x00{8}}
561*272bd698SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.128 hd={x10, x02, xFF, xFF, xFF, xFF, xFF, x80, x00{8}}
562*272bd698SAlexander V. Chernikov 	 */
563*272bd698SAlexander V. Chernikov 
564*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
565*272bd698SAlexander V. Chernikov 	verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
566*272bd698SAlexander V. Chernikov 	    RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
567*272bd698SAlexander V. Chernikov 
568*272bd698SAlexander V. Chernikov }
569*272bd698SAlexander V. Chernikov 
570*272bd698SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_change_v4_mtu_success,
571*272bd698SAlexander V. Chernikov     "Tests IPv4 path  mtu change");
572*272bd698SAlexander V. Chernikov 
573*272bd698SAlexander V. Chernikov ATF_TC_BODY(rtm_change_v4_mtu_success, tc)
574*272bd698SAlexander V. Chernikov {
575*272bd698SAlexander V. Chernikov 	DECLARE_TEST_VARS;
576*272bd698SAlexander V. Chernikov 
577*272bd698SAlexander V. Chernikov 	unsigned long test_mtu = 1442;
578*272bd698SAlexander V. Chernikov 
579*272bd698SAlexander V. Chernikov 	c = presetup_ipv4(tc);
580*272bd698SAlexander V. Chernikov 
581*272bd698SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
582*272bd698SAlexander V. Chernikov 	struct sockaddr_in mask4;
583*272bd698SAlexander V. Chernikov 	struct sockaddr_in net4;
584*272bd698SAlexander V. Chernikov 	struct sockaddr_in gw4;
585*272bd698SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
586*272bd698SAlexander V. Chernikov 
587*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
588*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
589*272bd698SAlexander V. Chernikov 
590*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
591*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
592*272bd698SAlexander V. Chernikov 
593*272bd698SAlexander V. Chernikov 	/* Change MTU */
594*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
595*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, NULL);
596*272bd698SAlexander V. Chernikov 	rtm->rtm_inits |= RTV_MTU;
597*272bd698SAlexander V. Chernikov 	rtm->rtm_rmx.rmx_mtu = test_mtu;
598*272bd698SAlexander V. Chernikov 
599*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
600*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
601*272bd698SAlexander V. Chernikov 
602*272bd698SAlexander V. Chernikov 	verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
603*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, NULL);
604*272bd698SAlexander V. Chernikov 
605*272bd698SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
606*272bd698SAlexander V. Chernikov 	    "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
607*272bd698SAlexander V. Chernikov 
608*272bd698SAlexander V. Chernikov 	/* Verify the change has actually taken place */
609*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4,
610*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, NULL);
611*272bd698SAlexander V. Chernikov 
612*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
613*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
614*272bd698SAlexander V. Chernikov 
615*272bd698SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
616*272bd698SAlexander V. Chernikov 	    "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
617*272bd698SAlexander V. Chernikov }
618*272bd698SAlexander V. Chernikov 
619*272bd698SAlexander V. Chernikov 
620775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success);
621775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v6_gu_gw_gu_direct_success, tc)
622775dc861SAlexander V. Chernikov {
623775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
624775dc861SAlexander V. Chernikov }
625775dc861SAlexander V. Chernikov 
626775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_gw_gu_direct_success, tc)
627775dc861SAlexander V. Chernikov {
628775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
629775dc861SAlexander V. Chernikov 
630775dc861SAlexander V. Chernikov 	c = presetup_ipv6(tc);
631775dc861SAlexander V. Chernikov 
632775dc861SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
633775dc861SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
634775dc861SAlexander V. Chernikov 	struct sockaddr_in6 net6;
635775dc861SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
636775dc861SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
637775dc861SAlexander V. Chernikov 
638775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
639775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
640775dc861SAlexander V. Chernikov 
641775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
642775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
643775dc861SAlexander V. Chernikov 
644775dc861SAlexander V. Chernikov 	/*
645775dc861SAlexander V. Chernikov 	 * RTM_ADD: Add Route: len 200, pid: 46068, seq 42, errno 0, flags:<GATEWAY,DONE,STATIC>
646775dc861SAlexander V. Chernikov 	 * locks:  inits:
647775dc861SAlexander V. Chernikov 	 * sockaddrs: <DST,GATEWAY,NETMASK>
648775dc861SAlexander V. Chernikov 	 *  192.0.2.0 192.0.2.254 255.255.255.128
649775dc861SAlexander V. Chernikov 	 */
650775dc861SAlexander V. Chernikov 
651775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
652775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
653775dc861SAlexander V. Chernikov 
654775dc861SAlexander V. Chernikov 	/* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
655775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
656775dc861SAlexander V. Chernikov }
657775dc861SAlexander V. Chernikov 
658775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success, tc)
659775dc861SAlexander V. Chernikov {
660775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
661775dc861SAlexander V. Chernikov }
662775dc861SAlexander V. Chernikov 
663775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_del_v6_gu_prefix_nogw_success);
664775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_del_v6_gu_prefix_nogw_success, tc)
665775dc861SAlexander V. Chernikov {
666775dc861SAlexander V. Chernikov 
667775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix removal without specifying gateway");
668775dc861SAlexander V. Chernikov }
669775dc861SAlexander V. Chernikov 
670775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v6_gu_prefix_nogw_success, tc)
671775dc861SAlexander V. Chernikov {
672775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
673775dc861SAlexander V. Chernikov 
674775dc861SAlexander V. Chernikov 	c = presetup_ipv6(tc);
675775dc861SAlexander V. Chernikov 
676775dc861SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
677775dc861SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
678775dc861SAlexander V. Chernikov 	struct sockaddr_in6 net6;
679775dc861SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
680775dc861SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
681775dc861SAlexander V. Chernikov 
682775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
683775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
684775dc861SAlexander V. Chernikov 
685775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
686775dc861SAlexander V. Chernikov 
687775dc861SAlexander V. Chernikov 	/* Route has been added successfully, try to delete it */
688775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
689775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, NULL);
690775dc861SAlexander V. Chernikov 
691775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
692775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
693775dc861SAlexander V. Chernikov 
694775dc861SAlexander V. Chernikov 	/*
695775dc861SAlexander V. Chernikov 	 * RTM_DELETE: Delete Route: len 200, pid: 46417, seq 43, errno 0, flags: <GATEWAY,DONE,STATIC>
696775dc861SAlexander V. Chernikov 	 * sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
697775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
698775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.254 hd={10, 02, 00{2}, C0, 00, 02, FE, 00{8}}
699775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.128 hd={10, 02, FF{5}, 80, 00{8}}
700775dc861SAlexander V. Chernikov 	 */
701775dc861SAlexander V. Chernikov 
702775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
703775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
704775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
705775dc861SAlexander V. Chernikov }
706775dc861SAlexander V. Chernikov 
707775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_del_v6_gu_prefix_nogw_success, tc)
708775dc861SAlexander V. Chernikov {
709775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
710775dc861SAlexander V. Chernikov }
711775dc861SAlexander V. Chernikov 
712*272bd698SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_change_v6_gw_success,
713*272bd698SAlexander V. Chernikov     "Tests IPv6 gateway change");
714*272bd698SAlexander V. Chernikov 
715*272bd698SAlexander V. Chernikov ATF_TC_BODY(rtm_change_v6_gw_success, tc)
716*272bd698SAlexander V. Chernikov {
717*272bd698SAlexander V. Chernikov 	DECLARE_TEST_VARS;
718*272bd698SAlexander V. Chernikov 	struct rtsock_config_options co;
719*272bd698SAlexander V. Chernikov 
720*272bd698SAlexander V. Chernikov 	bzero(&co, sizeof(co));
721*272bd698SAlexander V. Chernikov 	co.num_interfaces = 2;
722*272bd698SAlexander V. Chernikov 
723*272bd698SAlexander V. Chernikov 	c = config_setup(tc, &co);
724*272bd698SAlexander V. Chernikov 	jump_vnet(c, tc);
725*272bd698SAlexander V. Chernikov 
726*272bd698SAlexander V. Chernikov 	ret = iface_turn_up(c->ifnames[0]);
727*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[0]);
728*272bd698SAlexander V. Chernikov 	ret = iface_turn_up(c->ifnames[1]);
729*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[1]);
730*272bd698SAlexander V. Chernikov 
731*272bd698SAlexander V. Chernikov 	ret = iface_enable_ipv6(c->ifnames[0]);
732*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifnames[0]);
733*272bd698SAlexander V. Chernikov 	ret = iface_enable_ipv6(c->ifnames[1]);
734*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifnames[1]);
735*272bd698SAlexander V. Chernikov 
736*272bd698SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifnames[0], c->addr6_str, c->plen6);
737*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
738*272bd698SAlexander V. Chernikov 
739*272bd698SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifnames[1], "2001:DB8:4242::1", 64);
740*272bd698SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
741*272bd698SAlexander V. Chernikov 
742*272bd698SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
743*272bd698SAlexander V. Chernikov 
744*272bd698SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
745*272bd698SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
746*272bd698SAlexander V. Chernikov 	struct sockaddr_in6 net6;
747*272bd698SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
748*272bd698SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
749*272bd698SAlexander V. Chernikov 
750*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
751*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
752*272bd698SAlexander V. Chernikov 
753*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
754*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
755*272bd698SAlexander V. Chernikov 
756*272bd698SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
757*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
758*272bd698SAlexander V. Chernikov 
759*272bd698SAlexander V. Chernikov 	/* Change gateway to the one on residing on the other interface */
760*272bd698SAlexander V. Chernikov 	inet_pton(AF_INET6, "2001:DB8:4242::4242", &gw6.sin6_addr);
761*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
762*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
763*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
764*272bd698SAlexander V. Chernikov 
765*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
766*272bd698SAlexander V. Chernikov 
767*272bd698SAlexander V. Chernikov 	verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
768*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
769*272bd698SAlexander V. Chernikov 
770*272bd698SAlexander V. Chernikov 	verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
771*272bd698SAlexander V. Chernikov 	    RTF_DONE | RTF_GATEWAY | RTF_STATIC);
772*272bd698SAlexander V. Chernikov 
773*272bd698SAlexander V. Chernikov 	/* Verify the change has actually taken place */
774*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6,
775*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, NULL);
776*272bd698SAlexander V. Chernikov 
777*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
778*272bd698SAlexander V. Chernikov 
779*272bd698SAlexander V. Chernikov 	/*
780*272bd698SAlexander V. Chernikov 	 * RTM_GET: len 248, pid: 2268, seq 44, errno 0, flags: <UP,GATEWAY,DONE,STATIC>
781*272bd698SAlexander V. Chernikov 	 *  sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
782*272bd698SAlexander V. Chernikov 	 *  af=inet6 len=28 addr=2001:db8:: hd={x1C, x1C, x00{6}, x20, x01, x0D, xB8, x00{16}}
783*272bd698SAlexander V. Chernikov 	 *  af=inet6 len=28 addr=2001:db8:4242::4242 hd={x1C, x1C, x00{6}, x20, x01, x0D, xB8, x42, x42, x00{8}, x42, x42, x00{4}}
784*272bd698SAlexander V. Chernikov 	 *  af=inet6 len=28 addr=ffff:ffff:8000:: hd={x1C, x1C, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, x80, x00{15}}
785*272bd698SAlexander V. Chernikov 	 */
786*272bd698SAlexander V. Chernikov 
787*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
788*272bd698SAlexander V. Chernikov 	verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
789*272bd698SAlexander V. Chernikov 	    RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
790*272bd698SAlexander V. Chernikov }
791*272bd698SAlexander V. Chernikov 
792*272bd698SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_change_v6_mtu_success,
793*272bd698SAlexander V. Chernikov     "Tests IPv6 path mtu change");
794*272bd698SAlexander V. Chernikov 
795*272bd698SAlexander V. Chernikov ATF_TC_BODY(rtm_change_v6_mtu_success, tc)
796*272bd698SAlexander V. Chernikov {
797*272bd698SAlexander V. Chernikov 	DECLARE_TEST_VARS;
798*272bd698SAlexander V. Chernikov 
799*272bd698SAlexander V. Chernikov 	unsigned long test_mtu = 1442;
800*272bd698SAlexander V. Chernikov 
801*272bd698SAlexander V. Chernikov 	c = presetup_ipv6(tc);
802*272bd698SAlexander V. Chernikov 
803*272bd698SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
804*272bd698SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
805*272bd698SAlexander V. Chernikov 	struct sockaddr_in6 net6;
806*272bd698SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
807*272bd698SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
808*272bd698SAlexander V. Chernikov 
809*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
810*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
811*272bd698SAlexander V. Chernikov 
812*272bd698SAlexander V. Chernikov 	/* Send route add */
813*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
814*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
815*272bd698SAlexander V. Chernikov 
816*272bd698SAlexander V. Chernikov 	/* Change MTU */
817*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
818*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, NULL);
819*272bd698SAlexander V. Chernikov 	rtm->rtm_inits |= RTV_MTU;
820*272bd698SAlexander V. Chernikov 	rtm->rtm_rmx.rmx_mtu = test_mtu;
821*272bd698SAlexander V. Chernikov 
822*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
823*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
824*272bd698SAlexander V. Chernikov 
825*272bd698SAlexander V. Chernikov 	verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
826*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, NULL);
827*272bd698SAlexander V. Chernikov 
828*272bd698SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
829*272bd698SAlexander V. Chernikov 	    "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
830*272bd698SAlexander V. Chernikov 
831*272bd698SAlexander V. Chernikov 	/* Verify the change has actually taken place */
832*272bd698SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6,
833*272bd698SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, NULL);
834*272bd698SAlexander V. Chernikov 
835*272bd698SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
836*272bd698SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
837*272bd698SAlexander V. Chernikov 
838*272bd698SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
839*272bd698SAlexander V. Chernikov 	    "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
840*272bd698SAlexander V. Chernikov }
841*272bd698SAlexander V. Chernikov 
842e02d3fe7SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v4_temporal1_success);
843e02d3fe7SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v4_temporal1_success, tc)
844e02d3fe7SAlexander V. Chernikov {
845e02d3fe7SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv4 route expiration with expire time set");
846e02d3fe7SAlexander V. Chernikov }
847e02d3fe7SAlexander V. Chernikov 
848e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_temporal1_success, tc)
849e02d3fe7SAlexander V. Chernikov {
850e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
851e02d3fe7SAlexander V. Chernikov 
852e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4(tc);
853e02d3fe7SAlexander V. Chernikov 
854e02d3fe7SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
855e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in mask4;
856e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in net4;
857e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in gw4;
858e02d3fe7SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
859e02d3fe7SAlexander V. Chernikov 
860e02d3fe7SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
861e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
862e02d3fe7SAlexander V. Chernikov 
863e02d3fe7SAlexander V. Chernikov 	/* Set expire time to now */
864e02d3fe7SAlexander V. Chernikov 	struct timeval tv;
865e02d3fe7SAlexander V. Chernikov 	gettimeofday(&tv, NULL);
866e02d3fe7SAlexander V. Chernikov 	rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
867e02d3fe7SAlexander V. Chernikov 	rtm->rtm_inits |= RTV_EXPIRE;
868e02d3fe7SAlexander V. Chernikov 
869e02d3fe7SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
870e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
871e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
872e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
873e02d3fe7SAlexander V. Chernikov 
874e02d3fe7SAlexander V. Chernikov 	/* The next should be route deletion */
875e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
876e02d3fe7SAlexander V. Chernikov 
877e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
878e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
879e02d3fe7SAlexander V. Chernikov 
88034a5582cSAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_GATEWAY | RTF_DONE | RTF_STATIC);
881e02d3fe7SAlexander V. Chernikov }
882e02d3fe7SAlexander V. Chernikov 
883e02d3fe7SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v4_temporal1_success, tc)
884e02d3fe7SAlexander V. Chernikov {
885e02d3fe7SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
886e02d3fe7SAlexander V. Chernikov }
887e02d3fe7SAlexander V. Chernikov 
888e02d3fe7SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v6_temporal1_success);
889e02d3fe7SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v6_temporal1_success, tc)
890e02d3fe7SAlexander V. Chernikov {
891e02d3fe7SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
892e02d3fe7SAlexander V. Chernikov }
893e02d3fe7SAlexander V. Chernikov 
894e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_temporal1_success, tc)
895e02d3fe7SAlexander V. Chernikov {
896e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
897e02d3fe7SAlexander V. Chernikov 
898e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6(tc);
899e02d3fe7SAlexander V. Chernikov 
900e02d3fe7SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
901e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
902e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in6 net6;
903e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
904e02d3fe7SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
905e02d3fe7SAlexander V. Chernikov 
906e02d3fe7SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
907e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
908e02d3fe7SAlexander V. Chernikov 
909e02d3fe7SAlexander V. Chernikov 	/* Set expire time to now */
910e02d3fe7SAlexander V. Chernikov 	struct timeval tv;
911e02d3fe7SAlexander V. Chernikov 	gettimeofday(&tv, NULL);
912e02d3fe7SAlexander V. Chernikov 	rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
913e02d3fe7SAlexander V. Chernikov 	rtm->rtm_inits |= RTV_EXPIRE;
914e02d3fe7SAlexander V. Chernikov 
915e02d3fe7SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
916e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
917e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
918e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
919e02d3fe7SAlexander V. Chernikov 
920e02d3fe7SAlexander V. Chernikov 	/* The next should be route deletion */
921e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
922e02d3fe7SAlexander V. Chernikov 
923e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
924e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
925e02d3fe7SAlexander V. Chernikov 
926e02d3fe7SAlexander V. Chernikov 
927e02d3fe7SAlexander V. Chernikov 	/* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
92834a5582cSAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_GATEWAY | RTF_DONE | RTF_STATIC);
929e02d3fe7SAlexander V. Chernikov }
930e02d3fe7SAlexander V. Chernikov 
931e02d3fe7SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v6_temporal1_success, tc)
932e02d3fe7SAlexander V. Chernikov {
933e02d3fe7SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
934e02d3fe7SAlexander V. Chernikov }
935e02d3fe7SAlexander V. Chernikov 
936e02d3fe7SAlexander V. Chernikov /* Interface address messages tests */
937e02d3fe7SAlexander V. Chernikov 
938e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_hostroute_success,
939e02d3fe7SAlexander V. Chernikov     "Tests validness for /128 host route announce after ifaddr assignment");
940e02d3fe7SAlexander V. Chernikov 
941e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_ifa_hostroute_success, tc)
942e02d3fe7SAlexander V. Chernikov {
943e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
944e02d3fe7SAlexander V. Chernikov 
945e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
946e02d3fe7SAlexander V. Chernikov 
947e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
948e02d3fe7SAlexander V. Chernikov 
949e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
950e02d3fe7SAlexander V. Chernikov 
951e02d3fe7SAlexander V. Chernikov 	/*
952e02d3fe7SAlexander V. Chernikov 	 * There will be multiple.
953e02d3fe7SAlexander V. Chernikov 	 * RTM_ADD without llinfo.
954e02d3fe7SAlexander V. Chernikov 	 */
955e02d3fe7SAlexander V. Chernikov 
956e02d3fe7SAlexander V. Chernikov 	while (true) {
957e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
958e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && ((rtm->rtm_flags & RTF_LLINFO) == 0))
959e02d3fe7SAlexander V. Chernikov 			break;
960e02d3fe7SAlexander V. Chernikov 	}
961e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the host route */
962e02d3fe7SAlexander V. Chernikov 
963e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->addr6, NULL, NULL);
964e02d3fe7SAlexander V. Chernikov 	rtsock_validate_pid_kernel(rtm);
965e02d3fe7SAlexander V. Chernikov 	/* No netmask should be set */
966e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL, "netmask is set");
967e02d3fe7SAlexander V. Chernikov 
968e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
969e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
970e02d3fe7SAlexander V. Chernikov 
971e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_UP | RTF_HOST | RTF_DONE | RTF_STATIC | RTF_PINNED;
972e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, if_nametoindex("lo0"), expected_rt_flags);
973e02d3fe7SAlexander V. Chernikov }
974e02d3fe7SAlexander V. Chernikov 
975e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_prefixroute_success,
976e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route announce after ifaddr assignment");
977e02d3fe7SAlexander V. Chernikov 
978e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_ifa_prefixroute_success, tc)
979e02d3fe7SAlexander V. Chernikov {
980e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
981e02d3fe7SAlexander V. Chernikov 
982e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
983e02d3fe7SAlexander V. Chernikov 
984e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
985e02d3fe7SAlexander V. Chernikov 
986e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
987e02d3fe7SAlexander V. Chernikov 
988e02d3fe7SAlexander V. Chernikov 	/*
989e02d3fe7SAlexander V. Chernikov 	 * Multiple RTM_ADD messages will be generated:
990e02d3fe7SAlexander V. Chernikov 	 * 1) lladdr mapping (RTF_LLDATA)
991e02d3fe7SAlexander V. Chernikov 	 * 2) host route (one w/o netmask)
992e02d3fe7SAlexander V. Chernikov 	 * 3) prefix route
993e02d3fe7SAlexander V. Chernikov 	 */
994e02d3fe7SAlexander V. Chernikov 
995e02d3fe7SAlexander V. Chernikov 	while (true) {
996e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
997e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
998e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
999e02d3fe7SAlexander V. Chernikov 			break;
1000e02d3fe7SAlexander V. Chernikov 	}
1001e02d3fe7SAlexander V. Chernikov 
1002e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
1003e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->net6,
1004e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask6, NULL);
1005e02d3fe7SAlexander V. Chernikov 
1006e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
1007e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
1008e02d3fe7SAlexander V. Chernikov 
1009e02d3fe7SAlexander V. Chernikov 	/* TODO: PINNED? */
1010e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_UP | RTF_DONE;
1011e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
1012e02d3fe7SAlexander V. Chernikov }
1013e02d3fe7SAlexander V. Chernikov 
1014e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_ordered_success,
1015e02d3fe7SAlexander V. Chernikov     "Tests ordering of the messages for IPv6 global unicast ifaddr assignment");
1016e02d3fe7SAlexander V. Chernikov 
1017e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_ifa_ordered_success, tc)
1018e02d3fe7SAlexander V. Chernikov {
1019e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
1020e02d3fe7SAlexander V. Chernikov 
1021e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
1022e02d3fe7SAlexander V. Chernikov 
1023e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
1024e02d3fe7SAlexander V. Chernikov 
1025e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
1026e02d3fe7SAlexander V. Chernikov 
1027e02d3fe7SAlexander V. Chernikov 	int count = 0, tries = 0;
1028e02d3fe7SAlexander V. Chernikov 
1029e02d3fe7SAlexander V. Chernikov 	enum msgtype {
1030e02d3fe7SAlexander V. Chernikov 		MSG_IFADDR,
1031e02d3fe7SAlexander V. Chernikov 		MSG_HOSTROUTE,
1032e02d3fe7SAlexander V. Chernikov 		MSG_PREFIXROUTE,
1033e02d3fe7SAlexander V. Chernikov 		MSG_MAX,
1034e02d3fe7SAlexander V. Chernikov 	};
1035e02d3fe7SAlexander V. Chernikov 
1036e02d3fe7SAlexander V. Chernikov 	int msg_array[MSG_MAX];
1037e02d3fe7SAlexander V. Chernikov 
1038e02d3fe7SAlexander V. Chernikov 	bzero(msg_array, sizeof(msg_array));
1039e02d3fe7SAlexander V. Chernikov 
1040e02d3fe7SAlexander V. Chernikov 	while (count < 3 && tries < 20) {
1041e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
1042e02d3fe7SAlexander V. Chernikov 		tries++;
1043e02d3fe7SAlexander V. Chernikov 		/* Classify */
1044e02d3fe7SAlexander V. Chernikov 		if (rtm->rtm_type == RTM_NEWADDR) {
1045e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_IFADDR: %d", count);
1046e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_IFADDR] = count++;
1047e02d3fe7SAlexander V. Chernikov 			continue;
1048e02d3fe7SAlexander V. Chernikov 		}
1049e02d3fe7SAlexander V. Chernikov 
1050e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
1051e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK))) {
1052e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_PREFIXROUTE: %d", count);
1053e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_PREFIXROUTE] = count++;
1054e02d3fe7SAlexander V. Chernikov 			continue;
1055e02d3fe7SAlexander V. Chernikov 		}
1056e02d3fe7SAlexander V. Chernikov 
1057e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && ((rtm->rtm_flags & RTF_LLDATA) == 0)) {
1058e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_HOSTROUTE: %d", count);
1059e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_HOSTROUTE] = count++;
1060e02d3fe7SAlexander V. Chernikov 			continue;
1061e02d3fe7SAlexander V. Chernikov 		}
1062e02d3fe7SAlexander V. Chernikov 
1063e02d3fe7SAlexander V. Chernikov 		RLOG("skipping msg type %s, try: %d", rtsock_print_cmdtype(rtm->rtm_type),
1064e02d3fe7SAlexander V. Chernikov 		    tries);
1065e02d3fe7SAlexander V. Chernikov 	}
1066e02d3fe7SAlexander V. Chernikov 
1067e02d3fe7SAlexander V. Chernikov 	/* TODO: verify multicast */
1068e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(count == 3, "Received only %d/3 messages", count);
1069e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(msg_array[MSG_IFADDR] == 0, "ifaddr message is not the first");
1070e02d3fe7SAlexander V. Chernikov }
1071e02d3fe7SAlexander V. Chernikov 
1072e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_ifa_hostroute_success,
1073e02d3fe7SAlexander V. Chernikov     "Tests validness for /128 host route removal after ifaddr removal");
1074e02d3fe7SAlexander V. Chernikov 
1075e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v6_gu_ifa_hostroute_success, tc)
1076e02d3fe7SAlexander V. Chernikov {
1077e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
1078e02d3fe7SAlexander V. Chernikov 
1079e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
1080e02d3fe7SAlexander V. Chernikov 
1081e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
1082e02d3fe7SAlexander V. Chernikov 
1083e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
1084e02d3fe7SAlexander V. Chernikov 
1085e02d3fe7SAlexander V. Chernikov 	ret = iface_delete_addr(c->ifname, c->addr6_str);
1086e02d3fe7SAlexander V. Chernikov 
1087e02d3fe7SAlexander V. Chernikov 	while (true) {
1088e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
1089e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_DELETE) &&
1090e02d3fe7SAlexander V. Chernikov 		    ((rtm->rtm_flags & RTF_LLINFO) == 0) &&
1091e02d3fe7SAlexander V. Chernikov 		    rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL)
1092e02d3fe7SAlexander V. Chernikov 			break;
1093e02d3fe7SAlexander V. Chernikov 	}
1094e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the host route */
1095e02d3fe7SAlexander V. Chernikov 
1096e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->addr6, NULL, NULL);
1097e02d3fe7SAlexander V. Chernikov 	rtsock_validate_pid_kernel(rtm);
1098e02d3fe7SAlexander V. Chernikov 	/* No netmask should be set */
1099e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL, "netmask is set");
1100e02d3fe7SAlexander V. Chernikov 
1101e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
1102e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
1103e02d3fe7SAlexander V. Chernikov 
1104e02d3fe7SAlexander V. Chernikov 	/* XXX: consider passing ifindex in rtm_index as done in RTM_ADD. */
1105e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_HOST | RTF_DONE | RTF_STATIC | RTF_PINNED;
1106e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == expected_rt_flags,
1107e02d3fe7SAlexander V. Chernikov 	    "expected rtm flags: 0x%X, got 0x%X", expected_rt_flags, rtm->rtm_flags);
1108e02d3fe7SAlexander V. Chernikov }
1109e02d3fe7SAlexander V. Chernikov 
1110e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_ifa_prefixroute_success,
1111e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route removal after ifaddr assignment");
1112e02d3fe7SAlexander V. Chernikov 
1113e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v6_gu_ifa_prefixroute_success, tc)
1114e02d3fe7SAlexander V. Chernikov {
1115e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
1116e02d3fe7SAlexander V. Chernikov 
1117e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
1118e02d3fe7SAlexander V. Chernikov 
1119e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
1120e02d3fe7SAlexander V. Chernikov 
1121e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
1122e02d3fe7SAlexander V. Chernikov 
1123e02d3fe7SAlexander V. Chernikov 	ret = iface_delete_addr(c->ifname, c->addr6_str);
1124e02d3fe7SAlexander V. Chernikov 
1125e02d3fe7SAlexander V. Chernikov 	while (true) {
1126e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
1127e02d3fe7SAlexander V. Chernikov 		/* Find RTM_DELETE with netmask - this should skip both host route and LLADDR */
1128e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_DELETE) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
1129e02d3fe7SAlexander V. Chernikov 			break;
1130e02d3fe7SAlexander V. Chernikov 	}
1131e02d3fe7SAlexander V. Chernikov 
1132e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
1133e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->net6,
1134e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask6, NULL);
1135e02d3fe7SAlexander V. Chernikov 
1136e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
1137e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
1138e02d3fe7SAlexander V. Chernikov 
1139e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_DONE;
1140e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
1141e02d3fe7SAlexander V. Chernikov }
1142e02d3fe7SAlexander V. Chernikov 
1143e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_ifa_prefixroute_success,
1144e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route announce after ifaddr assignment");
1145e02d3fe7SAlexander V. Chernikov 
1146e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_gu_ifa_prefixroute_success, tc)
1147e02d3fe7SAlexander V. Chernikov {
1148e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
1149e02d3fe7SAlexander V. Chernikov 
1150e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
1151e02d3fe7SAlexander V. Chernikov 
1152e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
1153e02d3fe7SAlexander V. Chernikov 
1154e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
1155e02d3fe7SAlexander V. Chernikov 
1156e02d3fe7SAlexander V. Chernikov 	/*
1157e02d3fe7SAlexander V. Chernikov 	 * Multiple RTM_ADD messages will be generated:
1158e02d3fe7SAlexander V. Chernikov 	 * 1) lladdr mapping (RTF_LLDATA)
1159e02d3fe7SAlexander V. Chernikov 	 * 3) prefix route
1160e02d3fe7SAlexander V. Chernikov 	 */
1161e02d3fe7SAlexander V. Chernikov 
1162e02d3fe7SAlexander V. Chernikov 	while (true) {
1163e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
1164e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
1165e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
1166e02d3fe7SAlexander V. Chernikov 			break;
1167e02d3fe7SAlexander V. Chernikov 	}
1168e02d3fe7SAlexander V. Chernikov 
1169e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
1170e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->net4,
1171e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
1172e02d3fe7SAlexander V. Chernikov 
1173e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
1174e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
1175e02d3fe7SAlexander V. Chernikov 
1176e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_UP | RTF_DONE | RTF_PINNED;
1177e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
1178e02d3fe7SAlexander V. Chernikov }
1179e02d3fe7SAlexander V. Chernikov 
1180e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_ifa_ordered_success,
1181e02d3fe7SAlexander V. Chernikov     "Tests ordering of the messages for IPv4 unicast ifaddr assignment");
1182e02d3fe7SAlexander V. Chernikov 
1183e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_gu_ifa_ordered_success, tc)
1184e02d3fe7SAlexander V. Chernikov {
1185e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
1186e02d3fe7SAlexander V. Chernikov 
1187e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
1188e02d3fe7SAlexander V. Chernikov 
1189e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
1190e02d3fe7SAlexander V. Chernikov 
1191e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
1192e02d3fe7SAlexander V. Chernikov 
1193e02d3fe7SAlexander V. Chernikov 	int count = 0, tries = 0;
1194e02d3fe7SAlexander V. Chernikov 
1195e02d3fe7SAlexander V. Chernikov 	enum msgtype {
1196e02d3fe7SAlexander V. Chernikov 		MSG_IFADDR,
1197e02d3fe7SAlexander V. Chernikov 		MSG_PREFIXROUTE,
1198e02d3fe7SAlexander V. Chernikov 		MSG_MAX,
1199e02d3fe7SAlexander V. Chernikov 	};
1200e02d3fe7SAlexander V. Chernikov 
1201e02d3fe7SAlexander V. Chernikov 	int msg_array[MSG_MAX];
1202e02d3fe7SAlexander V. Chernikov 
1203e02d3fe7SAlexander V. Chernikov 	bzero(msg_array, sizeof(msg_array));
1204e02d3fe7SAlexander V. Chernikov 
1205e02d3fe7SAlexander V. Chernikov 	while (count < 2 && tries < 20) {
1206e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
1207e02d3fe7SAlexander V. Chernikov 		tries++;
1208e02d3fe7SAlexander V. Chernikov 		/* Classify */
1209e02d3fe7SAlexander V. Chernikov 		if (rtm->rtm_type == RTM_NEWADDR) {
1210e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_IFADDR: %d", count);
1211e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_IFADDR] = count++;
1212e02d3fe7SAlexander V. Chernikov 			continue;
1213e02d3fe7SAlexander V. Chernikov 		}
1214e02d3fe7SAlexander V. Chernikov 
1215e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
1216e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK))) {
1217e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_PREFIXROUTE: %d", count);
1218e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_PREFIXROUTE] = count++;
1219e02d3fe7SAlexander V. Chernikov 			continue;
1220e02d3fe7SAlexander V. Chernikov 		}
1221e02d3fe7SAlexander V. Chernikov 
1222e02d3fe7SAlexander V. Chernikov 		RLOG("skipping msg type %s, try: %d", rtsock_print_cmdtype(rtm->rtm_type),
1223e02d3fe7SAlexander V. Chernikov 		    tries);
1224e02d3fe7SAlexander V. Chernikov 	}
1225e02d3fe7SAlexander V. Chernikov 
1226e02d3fe7SAlexander V. Chernikov 	/* TODO: verify multicast */
1227e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(count == 2, "Received only %d/2 messages", count);
1228e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(msg_array[MSG_IFADDR] == 0, "ifaddr message is not the first");
1229e02d3fe7SAlexander V. Chernikov }
1230e02d3fe7SAlexander V. Chernikov 
1231e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_del_v4_gu_ifa_prefixroute_success,
1232e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route removal after ifaddr assignment");
1233e02d3fe7SAlexander V. Chernikov 
1234e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v4_gu_ifa_prefixroute_success, tc)
1235e02d3fe7SAlexander V. Chernikov {
1236e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
1237e02d3fe7SAlexander V. Chernikov 
1238e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
1239e02d3fe7SAlexander V. Chernikov 
1240e02d3fe7SAlexander V. Chernikov 
1241e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
1242e02d3fe7SAlexander V. Chernikov 
1243e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
1244e02d3fe7SAlexander V. Chernikov 
1245e02d3fe7SAlexander V. Chernikov 	ret = iface_delete_addr(c->ifname, c->addr4_str);
1246e02d3fe7SAlexander V. Chernikov 
1247e02d3fe7SAlexander V. Chernikov 	while (true) {
1248e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
1249e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
1250e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_DELETE) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
1251e02d3fe7SAlexander V. Chernikov 			break;
1252e02d3fe7SAlexander V. Chernikov 	}
1253e02d3fe7SAlexander V. Chernikov 
1254e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
1255e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->net4,
1256e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
1257e02d3fe7SAlexander V. Chernikov 
1258e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
1259e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
1260e02d3fe7SAlexander V. Chernikov 
1261e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_DONE | RTF_PINNED;
1262e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
1263e02d3fe7SAlexander V. Chernikov }
1264775dc861SAlexander V. Chernikov 
1265775dc861SAlexander V. Chernikov 
1266775dc861SAlexander V. Chernikov ATF_TP_ADD_TCS(tp)
1267775dc861SAlexander V. Chernikov {
1268775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_exact_success);
1269775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_lpm_success);
1270775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_hostbits_failure);
1271775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_empty_dst_failure);
1272775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v4_gw_direct_success);
1273775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v4_prefix_nogw_success);
1274775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_gw_gu_direct_success);
1275775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_prefix_nogw_success);
1276*272bd698SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_change_v4_gw_success);
1277*272bd698SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_change_v4_mtu_success);
1278*272bd698SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_change_v6_gw_success);
1279*272bd698SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_change_v6_mtu_success);
1280e02d3fe7SAlexander V. Chernikov 	/* ifaddr tests */
1281e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_hostroute_success);
1282e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_prefixroute_success);
1283e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_ordered_success);
1284e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_ifa_hostroute_success);
1285e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_ifa_prefixroute_success);
1286e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v4_gu_ifa_ordered_success);
1287e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v4_gu_ifa_prefixroute_success);
128834a5582cSAlexander V. Chernikov 	/* temporal routes */
128934a5582cSAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v4_temporal1_success);
129034a5582cSAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_temporal1_success);
1291775dc861SAlexander V. Chernikov 
1292775dc861SAlexander V. Chernikov 	return (atf_no_error());
1293775dc861SAlexander V. Chernikov }
1294775dc861SAlexander V. Chernikov 
1295