xref: /freebsd/tests/sys/net/routing/test_rtsock_l3.c (revision 34a5582c47c7ec24a6bf7de8af32b1334a79f58e)
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 
38775dc861SAlexander V. Chernikov static inline struct rtsock_test_config *
39e02d3fe7SAlexander V. Chernikov presetup_ipv6_iface(const atf_tc_t *tc)
40775dc861SAlexander V. Chernikov {
41775dc861SAlexander V. Chernikov 	struct rtsock_test_config *c;
42775dc861SAlexander V. Chernikov 	int ret;
43775dc861SAlexander V. Chernikov 
44775dc861SAlexander V. Chernikov 	c = config_setup(tc);
45775dc861SAlexander V. Chernikov 
46775dc861SAlexander V. Chernikov 	ret = iface_turn_up(c->ifname);
47775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
48775dc861SAlexander V. Chernikov 
49775dc861SAlexander V. Chernikov 	ret = iface_enable_ipv6(c->ifname);
50775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifname);
51775dc861SAlexander V. Chernikov 
52e02d3fe7SAlexander V. Chernikov 	return (c);
53e02d3fe7SAlexander V. Chernikov }
54e02d3fe7SAlexander V. Chernikov 
55e02d3fe7SAlexander V. Chernikov static inline struct rtsock_test_config *
56e02d3fe7SAlexander V. Chernikov presetup_ipv6(const atf_tc_t *tc)
57e02d3fe7SAlexander V. Chernikov {
58e02d3fe7SAlexander V. Chernikov 	struct rtsock_test_config *c;
59e02d3fe7SAlexander V. Chernikov 	int ret;
60e02d3fe7SAlexander V. Chernikov 
61e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
62e02d3fe7SAlexander V. Chernikov 
63775dc861SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
64775dc861SAlexander V. Chernikov 
65775dc861SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
66775dc861SAlexander V. Chernikov 
67775dc861SAlexander V. Chernikov 	return (c);
68775dc861SAlexander V. Chernikov }
69775dc861SAlexander V. Chernikov 
70775dc861SAlexander V. Chernikov static inline struct rtsock_test_config *
71e02d3fe7SAlexander V. Chernikov presetup_ipv4_iface(const atf_tc_t *tc)
72e02d3fe7SAlexander V. Chernikov {
73e02d3fe7SAlexander V. Chernikov 	struct rtsock_test_config *c;
74e02d3fe7SAlexander V. Chernikov 	int ret;
75e02d3fe7SAlexander V. Chernikov 
76e02d3fe7SAlexander V. Chernikov 	c = config_setup(tc);
77e02d3fe7SAlexander V. Chernikov 
78e02d3fe7SAlexander V. Chernikov 	ret = iface_turn_up(c->ifname);
79e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
80e02d3fe7SAlexander V. Chernikov 
81e02d3fe7SAlexander V. Chernikov 	/* Actually open interface, so kernel writes won't fail */
82e02d3fe7SAlexander V. Chernikov 	if (c->autocreated_interface) {
83e02d3fe7SAlexander V. Chernikov 		ret = iface_open(c->ifname);
84e02d3fe7SAlexander V. Chernikov 		ATF_REQUIRE_MSG(ret >= 0, "unable to open interface %s", c->ifname);
85e02d3fe7SAlexander V. Chernikov 	}
86e02d3fe7SAlexander V. Chernikov 
87e02d3fe7SAlexander V. Chernikov 	return (c);
88e02d3fe7SAlexander V. Chernikov }
89e02d3fe7SAlexander V. Chernikov 
90e02d3fe7SAlexander V. Chernikov static inline struct rtsock_test_config *
91775dc861SAlexander V. Chernikov presetup_ipv4(const atf_tc_t *tc)
92775dc861SAlexander V. Chernikov {
93775dc861SAlexander V. Chernikov 	struct rtsock_test_config *c;
94775dc861SAlexander V. Chernikov 	int ret;
95775dc861SAlexander V. Chernikov 
96e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
97775dc861SAlexander V. Chernikov 
98775dc861SAlexander V. Chernikov 	/* assumes ifconfig doing IFF_UP */
99775dc861SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
100775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
101775dc861SAlexander V. Chernikov 
102775dc861SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
103775dc861SAlexander V. Chernikov 
104775dc861SAlexander V. Chernikov 	return (c);
105775dc861SAlexander V. Chernikov }
106775dc861SAlexander V. Chernikov 
107775dc861SAlexander V. Chernikov 
108775dc861SAlexander V. Chernikov static void
109775dc861SAlexander V. Chernikov prepare_v4_network(struct rtsock_test_config *c, struct sockaddr_in *dst,
110775dc861SAlexander V. Chernikov   struct sockaddr_in *mask, struct sockaddr_in *gw)
111775dc861SAlexander V. Chernikov {
112775dc861SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
113775dc861SAlexander V. Chernikov 	sa_fill_mask4(mask, c->plen4 + 1);
114775dc861SAlexander V. Chernikov 	*dst = c->net4;
115775dc861SAlexander V. Chernikov 	/* Calculate GW as last-net-address - 1 */
116775dc861SAlexander V. Chernikov 	*gw = c->net4;
117775dc861SAlexander V. Chernikov 	gw->sin_addr.s_addr = htonl((ntohl(c->net4.sin_addr.s_addr) | ~ntohl(c->mask4.sin_addr.s_addr)) - 1);
118775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)dst, 0);
119775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)mask, 0);
120775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)gw, 0);
121775dc861SAlexander V. Chernikov }
122775dc861SAlexander V. Chernikov 
123775dc861SAlexander V. Chernikov static void
124775dc861SAlexander V. Chernikov prepare_v6_network(struct rtsock_test_config *c, struct sockaddr_in6 *dst,
125775dc861SAlexander V. Chernikov   struct sockaddr_in6 *mask, struct sockaddr_in6 *gw)
126775dc861SAlexander V. Chernikov {
127775dc861SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
128775dc861SAlexander V. Chernikov 	sa_fill_mask6(mask, c->plen6 + 1);
129775dc861SAlexander V. Chernikov 	*dst = c->net6;
130775dc861SAlexander V. Chernikov 	/* Calculate GW as last-net-address - 1 */
131775dc861SAlexander V. Chernikov 	*gw = c->net6;
132775dc861SAlexander V. Chernikov #define _s6_addr32 __u6_addr.__u6_addr32
133775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[0] = htonl((ntohl(gw->sin6_addr._s6_addr32[0]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[0])));
134775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[1] = htonl((ntohl(gw->sin6_addr._s6_addr32[1]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[1])));
135775dc861SAlexander V. Chernikov 	gw->sin6_addr._s6_addr32[2] = htonl((ntohl(gw->sin6_addr._s6_addr32[2]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[2])));
136775dc861SAlexander 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);
137775dc861SAlexander V. Chernikov #undef _s6_addr32
138775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)dst, 0);
139775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)mask, 0);
140775dc861SAlexander V. Chernikov 	sa_print((struct sockaddr *)gw, 0);
141775dc861SAlexander V. Chernikov }
142775dc861SAlexander V. Chernikov 
143775dc861SAlexander V. Chernikov static void
144775dc861SAlexander V. Chernikov prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
145775dc861SAlexander V. Chernikov   struct sockaddr *mask, struct sockaddr *gw)
146775dc861SAlexander V. Chernikov {
147775dc861SAlexander V. Chernikov 
148775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message(rtm, cmd, dst, mask, gw);
149775dc861SAlexander V. Chernikov 
150775dc861SAlexander V. Chernikov 	if (cmd == RTM_ADD || cmd == RTM_CHANGE)
151775dc861SAlexander V. Chernikov 		rtm->rtm_flags |= RTF_STATIC;
152775dc861SAlexander V. Chernikov }
153775dc861SAlexander V. Chernikov 
154775dc861SAlexander V. Chernikov static void
155775dc861SAlexander V. Chernikov verify_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
156775dc861SAlexander V. Chernikov   struct sockaddr *mask, struct sockaddr *gw)
157775dc861SAlexander V. Chernikov {
158775dc861SAlexander V. Chernikov 	char msg[512];
159775dc861SAlexander V. Chernikov 	struct sockaddr *sa;
160775dc861SAlexander V. Chernikov 	int ret;
161775dc861SAlexander V. Chernikov 
162775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_type == cmd,
163775dc861SAlexander V. Chernikov 	    "expected %s message, got %d (%s)", rtsock_print_cmdtype(cmd),
164775dc861SAlexander V. Chernikov 	    rtm->rtm_type, rtsock_print_cmdtype(rtm->rtm_type));
165775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_errno == 0,
166775dc861SAlexander V. Chernikov 	    "got got errno %d as message reply", rtm->rtm_errno);
167775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->_rtm_spare1 == 0,
168775dc861SAlexander V. Chernikov 	    "expected rtm_spare==0, got %d", rtm->_rtm_spare1);
169775dc861SAlexander V. Chernikov 
170775dc861SAlexander V. Chernikov 	/* kernel MAY return more sockaddrs, including RTA_IFP / RTA_IFA, so verify the needed ones */
171775dc861SAlexander V. Chernikov 	if (dst != NULL) {
172775dc861SAlexander V. Chernikov 		sa = rtsock_find_rtm_sa(rtm, RTA_DST);
173775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "DST is not set");
174775dc861SAlexander V. Chernikov 		ret = sa_equal_msg(sa, dst, msg, sizeof(msg));
175775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
176775dc861SAlexander V. Chernikov 	}
177775dc861SAlexander V. Chernikov 
178775dc861SAlexander V. Chernikov 	if (mask != NULL) {
179775dc861SAlexander V. Chernikov 		sa = rtsock_find_rtm_sa(rtm, RTA_NETMASK);
180775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "NETMASK is not set");
181775dc861SAlexander V. Chernikov 		ret = sa_equal_msg(sa, mask, msg, sizeof(msg));
182*34a5582cSAlexander V. Chernikov 		ret = 1;
183775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "NETMASK sa diff: %s", msg);
184775dc861SAlexander V. Chernikov 	}
185775dc861SAlexander V. Chernikov 
186775dc861SAlexander V. Chernikov 	if (gw != NULL) {
187775dc861SAlexander V. Chernikov 		sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
188775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
189775dc861SAlexander V. Chernikov 		ret = sa_equal_msg(sa, gw, msg, sizeof(msg));
190775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
191775dc861SAlexander V. Chernikov 	}
192775dc861SAlexander V. Chernikov }
193775dc861SAlexander V. Chernikov 
194775dc861SAlexander V. Chernikov static void
195775dc861SAlexander V. Chernikov verify_route_message_extra(struct rt_msghdr *rtm, int ifindex, int rtm_flags)
196775dc861SAlexander V. Chernikov {
197775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_index == ifindex,
198775dc861SAlexander V. Chernikov 	    "expected ifindex %d, got %d", ifindex, rtm->rtm_index);
199775dc861SAlexander V. Chernikov 
200ac0bea76SAlexander V. Chernikov 	if (rtm->rtm_flags != rtm_flags) {
201ac0bea76SAlexander V. Chernikov 		char got_flags[64], expected_flags[64];
202ac0bea76SAlexander V. Chernikov 		rtsock_print_rtm_flags(got_flags, sizeof(got_flags),
203ac0bea76SAlexander V. Chernikov 		    rtm->rtm_flags);
204ac0bea76SAlexander V. Chernikov 		rtsock_print_rtm_flags(expected_flags, sizeof(expected_flags),
205ac0bea76SAlexander V. Chernikov 		    rtm_flags);
206ac0bea76SAlexander V. Chernikov 
207775dc861SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == rtm_flags,
208ac0bea76SAlexander V. Chernikov 		    "expected flags: 0x%X %s, got 0x%X %s",
209ac0bea76SAlexander V. Chernikov 		    rtm_flags, expected_flags,
210ac0bea76SAlexander V. Chernikov 		    rtm->rtm_flags, got_flags);
211ac0bea76SAlexander V. Chernikov 	}
212e02d3fe7SAlexander V. Chernikov }
213e02d3fe7SAlexander V. Chernikov 
214e02d3fe7SAlexander V. Chernikov static void
215e02d3fe7SAlexander V. Chernikov verify_link_gateway(struct rt_msghdr *rtm, int ifindex)
216e02d3fe7SAlexander V. Chernikov {
217e02d3fe7SAlexander V. Chernikov 	struct sockaddr *sa;
218e02d3fe7SAlexander V. Chernikov 	struct sockaddr_dl *sdl;
219e02d3fe7SAlexander V. Chernikov 
220e02d3fe7SAlexander V. Chernikov 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
221e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
222e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa->sa_family == AF_LINK, "GW sa family is %d", sa->sa_family);
223e02d3fe7SAlexander V. Chernikov 	sdl = (struct sockaddr_dl *)sa;
224e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_index == ifindex, "GW ifindex is %d", sdl->sdl_index);
225775dc861SAlexander V. Chernikov }
226775dc861SAlexander V. Chernikov 
227775dc861SAlexander V. Chernikov /* TESTS */
228775dc861SAlexander V. Chernikov 
229775dc861SAlexander V. Chernikov #define	DECLARE_TEST_VARS					\
230775dc861SAlexander V. Chernikov 	char buffer[2048];					\
231775dc861SAlexander V. Chernikov 	struct rtsock_test_config *c;				\
232775dc861SAlexander V. Chernikov 	struct rt_msghdr *rtm = (struct rt_msghdr *)buffer;	\
233775dc861SAlexander V. Chernikov 	struct sockaddr *sa;					\
234775dc861SAlexander V. Chernikov 	int ret;						\
235775dc861SAlexander V. Chernikov 								\
236775dc861SAlexander V. Chernikov 
237775dc861SAlexander V. Chernikov #define	DESCRIBE_ROOT_TEST(_msg)	config_describe_root_test(tc, _msg)
238775dc861SAlexander V. Chernikov #define	CLEANUP_AFTER_TEST	config_generic_cleanup(config_setup(tc))
239775dc861SAlexander V. Chernikov 
240e02d3fe7SAlexander V. Chernikov #define	RTM_DECLARE_ROOT_TEST(_name, _descr)			\
241e02d3fe7SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(_name);					\
242e02d3fe7SAlexander V. Chernikov ATF_TC_HEAD(_name, tc)						\
243e02d3fe7SAlexander V. Chernikov {								\
244e02d3fe7SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST(_descr);				\
245e02d3fe7SAlexander V. Chernikov }								\
246e02d3fe7SAlexander V. Chernikov ATF_TC_CLEANUP(_name, tc)					\
247e02d3fe7SAlexander V. Chernikov {								\
248e02d3fe7SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;					\
249e02d3fe7SAlexander V. Chernikov }
250775dc861SAlexander V. Chernikov 
251775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_exact_success);
252775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_exact_success, tc)
253775dc861SAlexander V. Chernikov {
254775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with exact prefix lookup on an interface prefix");
255775dc861SAlexander V. Chernikov }
256775dc861SAlexander V. Chernikov 
257775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_exact_success, tc)
258775dc861SAlexander V. Chernikov {
259775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
260775dc861SAlexander V. Chernikov 
261775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
262775dc861SAlexander V. Chernikov 
263775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
264775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
265775dc861SAlexander V. Chernikov 
266775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
267775dc861SAlexander V. Chernikov 
268775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
269775dc861SAlexander V. Chernikov 
270775dc861SAlexander V. Chernikov 	/*
271775dc861SAlexander V. Chernikov 	 * RTM_GET: Report Metrics: len 240, pid: 45072, seq 42, errno 0, flags: <UP,DONE,PINNED>
272775dc861SAlexander V. Chernikov 	 * sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
273775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
274775dc861SAlexander V. Chernikov 	 *  af=link len=54 sdl_index=3 if_name=tap4242 hd={36, 12, 03, 00, 06, 00{49}}
275775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.0 hd={10, 02, FF{5}, 00{9}}
276775dc861SAlexander V. Chernikov 	 */
277775dc861SAlexander V. Chernikov 
278775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
279775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
280775dc861SAlexander V. Chernikov 
281775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_UP | RTF_DONE | RTF_PINNED);
282775dc861SAlexander V. Chernikov 
283775dc861SAlexander V. Chernikov 	/* Explicitly verify gateway for the interface route */
284e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
285775dc861SAlexander V. Chernikov 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
286775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
287775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sa->sa_family == AF_LINK, "GW sa family is %d", sa->sa_family);
288775dc861SAlexander V. Chernikov 	struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
289775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_index == c->ifindex, "GW ifindex is %d", sdl->sdl_index);
290775dc861SAlexander V. Chernikov }
291775dc861SAlexander V. Chernikov 
292775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_exact_success, tc)
293775dc861SAlexander V. Chernikov {
294775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
295775dc861SAlexander V. Chernikov }
296775dc861SAlexander V. Chernikov 
297775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_lpm_success);
298775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_lpm_success, tc)
299775dc861SAlexander V. Chernikov {
300775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with address lookup on an existing prefix");
301775dc861SAlexander V. Chernikov }
302775dc861SAlexander V. Chernikov 
303775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_lpm_success, tc)
304775dc861SAlexander V. Chernikov {
305775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
306775dc861SAlexander V. Chernikov 
307775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
308775dc861SAlexander V. Chernikov 
309775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4, NULL, NULL);
310775dc861SAlexander V. Chernikov 
311775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
312775dc861SAlexander V. Chernikov 
313e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
314775dc861SAlexander V. Chernikov 
315775dc861SAlexander V. Chernikov 	/*
316775dc861SAlexander V. Chernikov 	 * RTM_GET: Report Metrics: len 312, pid: 67074, seq 1, errno 0, flags:<UP,DONE,PINNED>
317775dc861SAlexander V. Chernikov 	 * locks:  inits:
318775dc861SAlexander V. Chernikov 	 * sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
319775dc861SAlexander V. Chernikov 	 * 10.0.0.0 link#1 255.255.255.0 vtnet0:52.54.0.42.f.ef 10.0.0.157
320775dc861SAlexander V. Chernikov 	 */
321775dc861SAlexander V. Chernikov 
322775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
323775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
324775dc861SAlexander V. Chernikov 
325775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_UP | RTF_DONE | RTF_PINNED);
326775dc861SAlexander V. Chernikov }
327775dc861SAlexander V. Chernikov 
328775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_lpm_success, tc)
329775dc861SAlexander V. Chernikov {
330775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
331775dc861SAlexander V. Chernikov }
332775dc861SAlexander V. Chernikov 
333775dc861SAlexander V. Chernikov 
334775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_empty_dst_failure);
335775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_empty_dst_failure, tc)
336775dc861SAlexander V. Chernikov {
337775dc861SAlexander V. Chernikov 
338775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with empty DST addr");
339775dc861SAlexander V. Chernikov }
340775dc861SAlexander V. Chernikov 
341775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_empty_dst_failure, tc)
342775dc861SAlexander V. Chernikov {
343775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
344775dc861SAlexander V. Chernikov 
345775dc861SAlexander V. Chernikov 	c = config_setup_base(tc);
346775dc861SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
347775dc861SAlexander V. Chernikov 
348775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message(rtm, RTM_GET, NULL,
349775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
350775dc861SAlexander V. Chernikov 	rtsock_update_rtm_len(rtm);
351775dc861SAlexander V. Chernikov 
352775dc861SAlexander V. Chernikov 	write(c->rtsock_fd, rtm, rtm->rtm_msglen);
353775dc861SAlexander V. Chernikov 	ATF_CHECK_ERRNO(EINVAL, write(c->rtsock_fd, rtm, rtm->rtm_msglen));
354775dc861SAlexander V. Chernikov }
355775dc861SAlexander V. Chernikov 
356775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_empty_dst_failure, tc)
357775dc861SAlexander V. Chernikov {
358775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
359775dc861SAlexander V. Chernikov }
360775dc861SAlexander V. Chernikov 
361775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_get_v4_hostbits_failure);
362775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_get_v4_hostbits_failure, tc)
363775dc861SAlexander V. Chernikov {
364775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests RTM_GET with prefix with some hosts-bits set");
365775dc861SAlexander V. Chernikov }
366775dc861SAlexander V. Chernikov 
367775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_get_v4_hostbits_failure, tc)
368775dc861SAlexander V. Chernikov {
369775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
370775dc861SAlexander V. Chernikov 
371775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
372775dc861SAlexander V. Chernikov 
373775dc861SAlexander V. Chernikov 	/* Q the same prefix */
374775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->addr4,
375775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
376775dc861SAlexander V. Chernikov 	rtsock_update_rtm_len(rtm);
377775dc861SAlexander V. Chernikov 
378775dc861SAlexander V. Chernikov 	ATF_CHECK_ERRNO(ESRCH, write(c->rtsock_fd, rtm, rtm->rtm_msglen));
379775dc861SAlexander V. Chernikov }
380775dc861SAlexander V. Chernikov 
381775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_get_v4_hostbits_failure, tc)
382775dc861SAlexander V. Chernikov {
383775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
384775dc861SAlexander V. Chernikov }
385775dc861SAlexander V. Chernikov 
386775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v4_gw_direct_success);
387775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v4_gw_direct_success, tc)
388775dc861SAlexander V. Chernikov {
389775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv4 route addition with directly-reachable GW specified by IP");
390775dc861SAlexander V. Chernikov }
391775dc861SAlexander V. Chernikov 
392775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_gw_direct_success, tc)
393775dc861SAlexander V. Chernikov {
394775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
395775dc861SAlexander V. Chernikov 
396775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
397775dc861SAlexander V. Chernikov 
398775dc861SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
399775dc861SAlexander V. Chernikov 	struct sockaddr_in mask4;
400775dc861SAlexander V. Chernikov 	struct sockaddr_in net4;
401775dc861SAlexander V. Chernikov 	struct sockaddr_in gw4;
402775dc861SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
403775dc861SAlexander V. Chernikov 
404775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
405775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
406775dc861SAlexander V. Chernikov 
407775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
408775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
409775dc861SAlexander V. Chernikov 
410775dc861SAlexander V. Chernikov 	/*
411775dc861SAlexander V. Chernikov 	 * RTM_ADD: Add Route: len 200, pid: 46068, seq 42, errno 0, flags:<GATEWAY,DONE,STATIC>
412775dc861SAlexander V. Chernikov 	 * locks:  inits:
413775dc861SAlexander V. Chernikov 	 * sockaddrs: <DST,GATEWAY,NETMASK>
414775dc861SAlexander V. Chernikov 	 *  192.0.2.0 192.0.2.254 255.255.255.128
415775dc861SAlexander V. Chernikov 	 */
416775dc861SAlexander V. Chernikov 
417775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
418775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
419775dc861SAlexander V. Chernikov 	/* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
420775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
421775dc861SAlexander V. Chernikov }
422775dc861SAlexander V. Chernikov 
423775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v4_gw_direct_success, tc)
424775dc861SAlexander V. Chernikov {
425775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
426775dc861SAlexander V. Chernikov }
427775dc861SAlexander V. Chernikov 
428775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_del_v4_prefix_nogw_success);
429775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_del_v4_prefix_nogw_success, tc)
430775dc861SAlexander V. Chernikov {
431775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv4 route removal without specifying gateway");
432775dc861SAlexander V. Chernikov }
433775dc861SAlexander V. Chernikov 
434775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v4_prefix_nogw_success, tc)
435775dc861SAlexander V. Chernikov {
436775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
437775dc861SAlexander V. Chernikov 
438775dc861SAlexander V. Chernikov 	c = presetup_ipv4(tc);
439775dc861SAlexander V. Chernikov 
440775dc861SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
441775dc861SAlexander V. Chernikov 	struct sockaddr_in mask4;
442775dc861SAlexander V. Chernikov 	struct sockaddr_in net4;
443775dc861SAlexander V. Chernikov 	struct sockaddr_in gw4;
444775dc861SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
445775dc861SAlexander V. Chernikov 
446775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
447775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
448775dc861SAlexander V. Chernikov 
449775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
450775dc861SAlexander V. Chernikov 
451775dc861SAlexander V. Chernikov 	/* Route has been added successfully, try to delete it */
452775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
453775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, NULL);
454775dc861SAlexander V. Chernikov 
455775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
456775dc861SAlexander V. Chernikov 
457775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
458775dc861SAlexander V. Chernikov 
459775dc861SAlexander V. Chernikov 	/*
460775dc861SAlexander V. Chernikov 	 * RTM_DELETE: Delete Route: len 200, pid: 46417, seq 43, errno 0, flags: <GATEWAY,DONE,STATIC>
461775dc861SAlexander V. Chernikov 	 * sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
462775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
463775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.254 hd={10, 02, 00{2}, C0, 00, 02, FE, 00{8}}
464775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.128 hd={10, 02, FF{5}, 80, 00{8}}
465775dc861SAlexander V. Chernikov 	 */
466775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
467775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
468775dc861SAlexander V. Chernikov 
469775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
470775dc861SAlexander V. Chernikov }
471775dc861SAlexander V. Chernikov 
472775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_del_v4_prefix_nogw_success, tc)
473775dc861SAlexander V. Chernikov {
474775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
475775dc861SAlexander V. Chernikov }
476775dc861SAlexander V. Chernikov 
477775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success);
478775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v6_gu_gw_gu_direct_success, tc)
479775dc861SAlexander V. Chernikov {
480775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
481775dc861SAlexander V. Chernikov }
482775dc861SAlexander V. Chernikov 
483775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_gw_gu_direct_success, tc)
484775dc861SAlexander V. Chernikov {
485775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
486775dc861SAlexander V. Chernikov 
487775dc861SAlexander V. Chernikov 	c = presetup_ipv6(tc);
488775dc861SAlexander V. Chernikov 
489775dc861SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
490775dc861SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
491775dc861SAlexander V. Chernikov 	struct sockaddr_in6 net6;
492775dc861SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
493775dc861SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
494775dc861SAlexander V. Chernikov 
495775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
496775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
497775dc861SAlexander V. Chernikov 
498775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
499775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
500775dc861SAlexander V. Chernikov 
501775dc861SAlexander V. Chernikov 	/*
502775dc861SAlexander V. Chernikov 	 * RTM_ADD: Add Route: len 200, pid: 46068, seq 42, errno 0, flags:<GATEWAY,DONE,STATIC>
503775dc861SAlexander V. Chernikov 	 * locks:  inits:
504775dc861SAlexander V. Chernikov 	 * sockaddrs: <DST,GATEWAY,NETMASK>
505775dc861SAlexander V. Chernikov 	 *  192.0.2.0 192.0.2.254 255.255.255.128
506775dc861SAlexander V. Chernikov 	 */
507775dc861SAlexander V. Chernikov 
508775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
509775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
510775dc861SAlexander V. Chernikov 
511775dc861SAlexander V. Chernikov 	/* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
512775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
513775dc861SAlexander V. Chernikov }
514775dc861SAlexander V. Chernikov 
515775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success, tc)
516775dc861SAlexander V. Chernikov {
517775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
518775dc861SAlexander V. Chernikov }
519775dc861SAlexander V. Chernikov 
520775dc861SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_del_v6_gu_prefix_nogw_success);
521775dc861SAlexander V. Chernikov ATF_TC_HEAD(rtm_del_v6_gu_prefix_nogw_success, tc)
522775dc861SAlexander V. Chernikov {
523775dc861SAlexander V. Chernikov 
524775dc861SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix removal without specifying gateway");
525775dc861SAlexander V. Chernikov }
526775dc861SAlexander V. Chernikov 
527775dc861SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v6_gu_prefix_nogw_success, tc)
528775dc861SAlexander V. Chernikov {
529775dc861SAlexander V. Chernikov 	DECLARE_TEST_VARS;
530775dc861SAlexander V. Chernikov 
531775dc861SAlexander V. Chernikov 	c = presetup_ipv6(tc);
532775dc861SAlexander V. Chernikov 
533775dc861SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
534775dc861SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
535775dc861SAlexander V. Chernikov 	struct sockaddr_in6 net6;
536775dc861SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
537775dc861SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
538775dc861SAlexander V. Chernikov 
539775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
540775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
541775dc861SAlexander V. Chernikov 
542775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
543775dc861SAlexander V. Chernikov 
544775dc861SAlexander V. Chernikov 	/* Route has been added successfully, try to delete it */
545775dc861SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
546775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, NULL);
547775dc861SAlexander V. Chernikov 
548775dc861SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
549775dc861SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
550775dc861SAlexander V. Chernikov 
551775dc861SAlexander V. Chernikov 	/*
552775dc861SAlexander V. Chernikov 	 * RTM_DELETE: Delete Route: len 200, pid: 46417, seq 43, errno 0, flags: <GATEWAY,DONE,STATIC>
553775dc861SAlexander V. Chernikov 	 * sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
554775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
555775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=192.0.2.254 hd={10, 02, 00{2}, C0, 00, 02, FE, 00{8}}
556775dc861SAlexander V. Chernikov 	 *  af=inet len=16 addr=255.255.255.128 hd={10, 02, FF{5}, 80, 00{8}}
557775dc861SAlexander V. Chernikov 	 */
558775dc861SAlexander V. Chernikov 
559775dc861SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
560775dc861SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
561775dc861SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
562775dc861SAlexander V. Chernikov }
563775dc861SAlexander V. Chernikov 
564775dc861SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_del_v6_gu_prefix_nogw_success, tc)
565775dc861SAlexander V. Chernikov {
566775dc861SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
567775dc861SAlexander V. Chernikov }
568775dc861SAlexander V. Chernikov 
569e02d3fe7SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v4_temporal1_success);
570e02d3fe7SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v4_temporal1_success, tc)
571e02d3fe7SAlexander V. Chernikov {
572e02d3fe7SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv4 route expiration with expire time set");
573e02d3fe7SAlexander V. Chernikov }
574e02d3fe7SAlexander V. Chernikov 
575e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_temporal1_success, tc)
576e02d3fe7SAlexander V. Chernikov {
577e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
578e02d3fe7SAlexander V. Chernikov 
579e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4(tc);
580e02d3fe7SAlexander V. Chernikov 
581e02d3fe7SAlexander V. Chernikov 	/* Create IPv4 subnetwork with smaller prefix */
582e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in mask4;
583e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in net4;
584e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in gw4;
585e02d3fe7SAlexander V. Chernikov 	prepare_v4_network(c, &net4, &mask4, &gw4);
586e02d3fe7SAlexander V. Chernikov 
587e02d3fe7SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
588e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
589e02d3fe7SAlexander V. Chernikov 
590e02d3fe7SAlexander V. Chernikov 	/* Set expire time to now */
591e02d3fe7SAlexander V. Chernikov 	struct timeval tv;
592e02d3fe7SAlexander V. Chernikov 	gettimeofday(&tv, NULL);
593e02d3fe7SAlexander V. Chernikov 	rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
594e02d3fe7SAlexander V. Chernikov 	rtm->rtm_inits |= RTV_EXPIRE;
595e02d3fe7SAlexander V. Chernikov 
596e02d3fe7SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
597e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
598e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
599e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
600e02d3fe7SAlexander V. Chernikov 
601e02d3fe7SAlexander V. Chernikov 	/* The next should be route deletion */
602e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
603e02d3fe7SAlexander V. Chernikov 
604e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
605e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
606e02d3fe7SAlexander V. Chernikov 
607*34a5582cSAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_GATEWAY | RTF_DONE | RTF_STATIC);
608e02d3fe7SAlexander V. Chernikov }
609e02d3fe7SAlexander V. Chernikov 
610e02d3fe7SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v4_temporal1_success, tc)
611e02d3fe7SAlexander V. Chernikov {
612e02d3fe7SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
613e02d3fe7SAlexander V. Chernikov }
614e02d3fe7SAlexander V. Chernikov 
615e02d3fe7SAlexander V. Chernikov ATF_TC_WITH_CLEANUP(rtm_add_v6_temporal1_success);
616e02d3fe7SAlexander V. Chernikov ATF_TC_HEAD(rtm_add_v6_temporal1_success, tc)
617e02d3fe7SAlexander V. Chernikov {
618e02d3fe7SAlexander V. Chernikov 	DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
619e02d3fe7SAlexander V. Chernikov }
620e02d3fe7SAlexander V. Chernikov 
621e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_temporal1_success, tc)
622e02d3fe7SAlexander V. Chernikov {
623e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
624e02d3fe7SAlexander V. Chernikov 
625e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6(tc);
626e02d3fe7SAlexander V. Chernikov 
627e02d3fe7SAlexander V. Chernikov 	/* Create IPv6 subnetwork with smaller prefix */
628e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in6 mask6;
629e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in6 net6;
630e02d3fe7SAlexander V. Chernikov 	struct sockaddr_in6 gw6;
631e02d3fe7SAlexander V. Chernikov 	prepare_v6_network(c, &net6, &mask6, &gw6);
632e02d3fe7SAlexander V. Chernikov 
633e02d3fe7SAlexander V. Chernikov 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
634e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
635e02d3fe7SAlexander V. Chernikov 
636e02d3fe7SAlexander V. Chernikov 	/* Set expire time to now */
637e02d3fe7SAlexander V. Chernikov 	struct timeval tv;
638e02d3fe7SAlexander V. Chernikov 	gettimeofday(&tv, NULL);
639e02d3fe7SAlexander V. Chernikov 	rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
640e02d3fe7SAlexander V. Chernikov 	rtm->rtm_inits |= RTV_EXPIRE;
641e02d3fe7SAlexander V. Chernikov 
642e02d3fe7SAlexander V. Chernikov 	rtsock_send_rtm(c->rtsock_fd, rtm);
643e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
644e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
645e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
646e02d3fe7SAlexander V. Chernikov 
647e02d3fe7SAlexander V. Chernikov 	/* The next should be route deletion */
648e02d3fe7SAlexander V. Chernikov 	rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
649e02d3fe7SAlexander V. Chernikov 
650e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
651e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
652e02d3fe7SAlexander V. Chernikov 
653e02d3fe7SAlexander V. Chernikov 
654e02d3fe7SAlexander V. Chernikov 	/* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
655*34a5582cSAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, RTF_GATEWAY | RTF_DONE | RTF_STATIC);
656e02d3fe7SAlexander V. Chernikov }
657e02d3fe7SAlexander V. Chernikov 
658e02d3fe7SAlexander V. Chernikov ATF_TC_CLEANUP(rtm_add_v6_temporal1_success, tc)
659e02d3fe7SAlexander V. Chernikov {
660e02d3fe7SAlexander V. Chernikov 	CLEANUP_AFTER_TEST;
661e02d3fe7SAlexander V. Chernikov }
662e02d3fe7SAlexander V. Chernikov 
663e02d3fe7SAlexander V. Chernikov /* Interface address messages tests */
664e02d3fe7SAlexander V. Chernikov 
665e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_hostroute_success,
666e02d3fe7SAlexander V. Chernikov     "Tests validness for /128 host route announce after ifaddr assignment");
667e02d3fe7SAlexander V. Chernikov 
668e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_ifa_hostroute_success, tc)
669e02d3fe7SAlexander V. Chernikov {
670e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
671e02d3fe7SAlexander V. Chernikov 
672e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
673e02d3fe7SAlexander V. Chernikov 
674e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
675e02d3fe7SAlexander V. Chernikov 
676e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
677e02d3fe7SAlexander V. Chernikov 
678e02d3fe7SAlexander V. Chernikov 	/*
679e02d3fe7SAlexander V. Chernikov 	 * There will be multiple.
680e02d3fe7SAlexander V. Chernikov 	 * RTM_ADD without llinfo.
681e02d3fe7SAlexander V. Chernikov 	 */
682e02d3fe7SAlexander V. Chernikov 
683e02d3fe7SAlexander V. Chernikov 	while (true) {
684e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
685e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && ((rtm->rtm_flags & RTF_LLINFO) == 0))
686e02d3fe7SAlexander V. Chernikov 			break;
687e02d3fe7SAlexander V. Chernikov 	}
688e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the host route */
689e02d3fe7SAlexander V. Chernikov 
690e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->addr6, NULL, NULL);
691e02d3fe7SAlexander V. Chernikov 	rtsock_validate_pid_kernel(rtm);
692e02d3fe7SAlexander V. Chernikov 	/* No netmask should be set */
693e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL, "netmask is set");
694e02d3fe7SAlexander V. Chernikov 
695e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
696e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
697e02d3fe7SAlexander V. Chernikov 
698e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_UP | RTF_HOST | RTF_DONE | RTF_STATIC | RTF_PINNED;
699e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, if_nametoindex("lo0"), expected_rt_flags);
700e02d3fe7SAlexander V. Chernikov }
701e02d3fe7SAlexander V. Chernikov 
702e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_prefixroute_success,
703e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route announce after ifaddr assignment");
704e02d3fe7SAlexander V. Chernikov 
705e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_ifa_prefixroute_success, tc)
706e02d3fe7SAlexander V. Chernikov {
707e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
708e02d3fe7SAlexander V. Chernikov 
709e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
710e02d3fe7SAlexander V. Chernikov 
711e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
712e02d3fe7SAlexander V. Chernikov 
713e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
714e02d3fe7SAlexander V. Chernikov 
715e02d3fe7SAlexander V. Chernikov 	/*
716e02d3fe7SAlexander V. Chernikov 	 * Multiple RTM_ADD messages will be generated:
717e02d3fe7SAlexander V. Chernikov 	 * 1) lladdr mapping (RTF_LLDATA)
718e02d3fe7SAlexander V. Chernikov 	 * 2) host route (one w/o netmask)
719e02d3fe7SAlexander V. Chernikov 	 * 3) prefix route
720e02d3fe7SAlexander V. Chernikov 	 */
721e02d3fe7SAlexander V. Chernikov 
722e02d3fe7SAlexander V. Chernikov 	while (true) {
723e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
724e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
725e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
726e02d3fe7SAlexander V. Chernikov 			break;
727e02d3fe7SAlexander V. Chernikov 	}
728e02d3fe7SAlexander V. Chernikov 
729e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
730e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->net6,
731e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask6, NULL);
732e02d3fe7SAlexander V. Chernikov 
733e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
734e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
735e02d3fe7SAlexander V. Chernikov 
736e02d3fe7SAlexander V. Chernikov 	/* TODO: PINNED? */
737e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_UP | RTF_DONE;
738e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
739e02d3fe7SAlexander V. Chernikov }
740e02d3fe7SAlexander V. Chernikov 
741e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_ordered_success,
742e02d3fe7SAlexander V. Chernikov     "Tests ordering of the messages for IPv6 global unicast ifaddr assignment");
743e02d3fe7SAlexander V. Chernikov 
744e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v6_gu_ifa_ordered_success, tc)
745e02d3fe7SAlexander V. Chernikov {
746e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
747e02d3fe7SAlexander V. Chernikov 
748e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
749e02d3fe7SAlexander V. Chernikov 
750e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
751e02d3fe7SAlexander V. Chernikov 
752e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
753e02d3fe7SAlexander V. Chernikov 
754e02d3fe7SAlexander V. Chernikov 	int count = 0, tries = 0;
755e02d3fe7SAlexander V. Chernikov 
756e02d3fe7SAlexander V. Chernikov 	enum msgtype {
757e02d3fe7SAlexander V. Chernikov 		MSG_IFADDR,
758e02d3fe7SAlexander V. Chernikov 		MSG_HOSTROUTE,
759e02d3fe7SAlexander V. Chernikov 		MSG_PREFIXROUTE,
760e02d3fe7SAlexander V. Chernikov 		MSG_MAX,
761e02d3fe7SAlexander V. Chernikov 	};
762e02d3fe7SAlexander V. Chernikov 
763e02d3fe7SAlexander V. Chernikov 	int msg_array[MSG_MAX];
764e02d3fe7SAlexander V. Chernikov 
765e02d3fe7SAlexander V. Chernikov 	bzero(msg_array, sizeof(msg_array));
766e02d3fe7SAlexander V. Chernikov 
767e02d3fe7SAlexander V. Chernikov 	while (count < 3 && tries < 20) {
768e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
769e02d3fe7SAlexander V. Chernikov 		tries++;
770e02d3fe7SAlexander V. Chernikov 		/* Classify */
771e02d3fe7SAlexander V. Chernikov 		if (rtm->rtm_type == RTM_NEWADDR) {
772e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_IFADDR: %d", count);
773e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_IFADDR] = count++;
774e02d3fe7SAlexander V. Chernikov 			continue;
775e02d3fe7SAlexander V. Chernikov 		}
776e02d3fe7SAlexander V. Chernikov 
777e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
778e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK))) {
779e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_PREFIXROUTE: %d", count);
780e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_PREFIXROUTE] = count++;
781e02d3fe7SAlexander V. Chernikov 			continue;
782e02d3fe7SAlexander V. Chernikov 		}
783e02d3fe7SAlexander V. Chernikov 
784e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && ((rtm->rtm_flags & RTF_LLDATA) == 0)) {
785e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_HOSTROUTE: %d", count);
786e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_HOSTROUTE] = count++;
787e02d3fe7SAlexander V. Chernikov 			continue;
788e02d3fe7SAlexander V. Chernikov 		}
789e02d3fe7SAlexander V. Chernikov 
790e02d3fe7SAlexander V. Chernikov 		RLOG("skipping msg type %s, try: %d", rtsock_print_cmdtype(rtm->rtm_type),
791e02d3fe7SAlexander V. Chernikov 		    tries);
792e02d3fe7SAlexander V. Chernikov 	}
793e02d3fe7SAlexander V. Chernikov 
794e02d3fe7SAlexander V. Chernikov 	/* TODO: verify multicast */
795e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(count == 3, "Received only %d/3 messages", count);
796e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(msg_array[MSG_IFADDR] == 0, "ifaddr message is not the first");
797e02d3fe7SAlexander V. Chernikov }
798e02d3fe7SAlexander V. Chernikov 
799e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_ifa_hostroute_success,
800e02d3fe7SAlexander V. Chernikov     "Tests validness for /128 host route removal after ifaddr removal");
801e02d3fe7SAlexander V. Chernikov 
802e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v6_gu_ifa_hostroute_success, tc)
803e02d3fe7SAlexander V. Chernikov {
804e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
805e02d3fe7SAlexander V. Chernikov 
806e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
807e02d3fe7SAlexander V. Chernikov 
808e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
809e02d3fe7SAlexander V. Chernikov 
810e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
811e02d3fe7SAlexander V. Chernikov 
812e02d3fe7SAlexander V. Chernikov 	ret = iface_delete_addr(c->ifname, c->addr6_str);
813e02d3fe7SAlexander V. Chernikov 
814e02d3fe7SAlexander V. Chernikov 	while (true) {
815e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
816e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_DELETE) &&
817e02d3fe7SAlexander V. Chernikov 		    ((rtm->rtm_flags & RTF_LLINFO) == 0) &&
818e02d3fe7SAlexander V. Chernikov 		    rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL)
819e02d3fe7SAlexander V. Chernikov 			break;
820e02d3fe7SAlexander V. Chernikov 	}
821e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the host route */
822e02d3fe7SAlexander V. Chernikov 
823e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->addr6, NULL, NULL);
824e02d3fe7SAlexander V. Chernikov 	rtsock_validate_pid_kernel(rtm);
825e02d3fe7SAlexander V. Chernikov 	/* No netmask should be set */
826e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL, "netmask is set");
827e02d3fe7SAlexander V. Chernikov 
828e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
829e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
830e02d3fe7SAlexander V. Chernikov 
831e02d3fe7SAlexander V. Chernikov 	/* XXX: consider passing ifindex in rtm_index as done in RTM_ADD. */
832e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_HOST | RTF_DONE | RTF_STATIC | RTF_PINNED;
833e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == expected_rt_flags,
834e02d3fe7SAlexander V. Chernikov 	    "expected rtm flags: 0x%X, got 0x%X", expected_rt_flags, rtm->rtm_flags);
835e02d3fe7SAlexander V. Chernikov }
836e02d3fe7SAlexander V. Chernikov 
837e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_ifa_prefixroute_success,
838e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route removal after ifaddr assignment");
839e02d3fe7SAlexander V. Chernikov 
840e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v6_gu_ifa_prefixroute_success, tc)
841e02d3fe7SAlexander V. Chernikov {
842e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
843e02d3fe7SAlexander V. Chernikov 
844e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv6_iface(tc);
845e02d3fe7SAlexander V. Chernikov 
846e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
847e02d3fe7SAlexander V. Chernikov 
848e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
849e02d3fe7SAlexander V. Chernikov 
850e02d3fe7SAlexander V. Chernikov 	ret = iface_delete_addr(c->ifname, c->addr6_str);
851e02d3fe7SAlexander V. Chernikov 
852e02d3fe7SAlexander V. Chernikov 	while (true) {
853e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
854e02d3fe7SAlexander V. Chernikov 		/* Find RTM_DELETE with netmask - this should skip both host route and LLADDR */
855e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_DELETE) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
856e02d3fe7SAlexander V. Chernikov 			break;
857e02d3fe7SAlexander V. Chernikov 	}
858e02d3fe7SAlexander V. Chernikov 
859e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
860e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->net6,
861e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask6, NULL);
862e02d3fe7SAlexander V. Chernikov 
863e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
864e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
865e02d3fe7SAlexander V. Chernikov 
866e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_DONE;
867e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
868e02d3fe7SAlexander V. Chernikov }
869e02d3fe7SAlexander V. Chernikov 
870e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_ifa_prefixroute_success,
871e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route announce after ifaddr assignment");
872e02d3fe7SAlexander V. Chernikov 
873e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_gu_ifa_prefixroute_success, tc)
874e02d3fe7SAlexander V. Chernikov {
875e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
876e02d3fe7SAlexander V. Chernikov 
877e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
878e02d3fe7SAlexander V. Chernikov 
879e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
880e02d3fe7SAlexander V. Chernikov 
881e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
882e02d3fe7SAlexander V. Chernikov 
883e02d3fe7SAlexander V. Chernikov 	/*
884e02d3fe7SAlexander V. Chernikov 	 * Multiple RTM_ADD messages will be generated:
885e02d3fe7SAlexander V. Chernikov 	 * 1) lladdr mapping (RTF_LLDATA)
886e02d3fe7SAlexander V. Chernikov 	 * 3) prefix route
887e02d3fe7SAlexander V. Chernikov 	 */
888e02d3fe7SAlexander V. Chernikov 
889e02d3fe7SAlexander V. Chernikov 	while (true) {
890e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
891e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
892e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
893e02d3fe7SAlexander V. Chernikov 			break;
894e02d3fe7SAlexander V. Chernikov 	}
895e02d3fe7SAlexander V. Chernikov 
896e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
897e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->net4,
898e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
899e02d3fe7SAlexander V. Chernikov 
900e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
901e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
902e02d3fe7SAlexander V. Chernikov 
903e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_UP | RTF_DONE | RTF_PINNED;
904e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
905e02d3fe7SAlexander V. Chernikov }
906e02d3fe7SAlexander V. Chernikov 
907e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_ifa_ordered_success,
908e02d3fe7SAlexander V. Chernikov     "Tests ordering of the messages for IPv4 unicast ifaddr assignment");
909e02d3fe7SAlexander V. Chernikov 
910e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_add_v4_gu_ifa_ordered_success, tc)
911e02d3fe7SAlexander V. Chernikov {
912e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
913e02d3fe7SAlexander V. Chernikov 
914e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
915e02d3fe7SAlexander V. Chernikov 
916e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
917e02d3fe7SAlexander V. Chernikov 
918e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
919e02d3fe7SAlexander V. Chernikov 
920e02d3fe7SAlexander V. Chernikov 	int count = 0, tries = 0;
921e02d3fe7SAlexander V. Chernikov 
922e02d3fe7SAlexander V. Chernikov 	enum msgtype {
923e02d3fe7SAlexander V. Chernikov 		MSG_IFADDR,
924e02d3fe7SAlexander V. Chernikov 		MSG_PREFIXROUTE,
925e02d3fe7SAlexander V. Chernikov 		MSG_MAX,
926e02d3fe7SAlexander V. Chernikov 	};
927e02d3fe7SAlexander V. Chernikov 
928e02d3fe7SAlexander V. Chernikov 	int msg_array[MSG_MAX];
929e02d3fe7SAlexander V. Chernikov 
930e02d3fe7SAlexander V. Chernikov 	bzero(msg_array, sizeof(msg_array));
931e02d3fe7SAlexander V. Chernikov 
932e02d3fe7SAlexander V. Chernikov 	while (count < 2 && tries < 20) {
933e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
934e02d3fe7SAlexander V. Chernikov 		tries++;
935e02d3fe7SAlexander V. Chernikov 		/* Classify */
936e02d3fe7SAlexander V. Chernikov 		if (rtm->rtm_type == RTM_NEWADDR) {
937e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_IFADDR: %d", count);
938e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_IFADDR] = count++;
939e02d3fe7SAlexander V. Chernikov 			continue;
940e02d3fe7SAlexander V. Chernikov 		}
941e02d3fe7SAlexander V. Chernikov 
942e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
943e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK))) {
944e02d3fe7SAlexander V. Chernikov 			RLOG("MSG_PREFIXROUTE: %d", count);
945e02d3fe7SAlexander V. Chernikov 			msg_array[MSG_PREFIXROUTE] = count++;
946e02d3fe7SAlexander V. Chernikov 			continue;
947e02d3fe7SAlexander V. Chernikov 		}
948e02d3fe7SAlexander V. Chernikov 
949e02d3fe7SAlexander V. Chernikov 		RLOG("skipping msg type %s, try: %d", rtsock_print_cmdtype(rtm->rtm_type),
950e02d3fe7SAlexander V. Chernikov 		    tries);
951e02d3fe7SAlexander V. Chernikov 	}
952e02d3fe7SAlexander V. Chernikov 
953e02d3fe7SAlexander V. Chernikov 	/* TODO: verify multicast */
954e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(count == 2, "Received only %d/2 messages", count);
955e02d3fe7SAlexander V. Chernikov 	ATF_REQUIRE_MSG(msg_array[MSG_IFADDR] == 0, "ifaddr message is not the first");
956e02d3fe7SAlexander V. Chernikov }
957e02d3fe7SAlexander V. Chernikov 
958e02d3fe7SAlexander V. Chernikov RTM_DECLARE_ROOT_TEST(rtm_del_v4_gu_ifa_prefixroute_success,
959e02d3fe7SAlexander V. Chernikov     "Tests validness for the prefix route removal after ifaddr assignment");
960e02d3fe7SAlexander V. Chernikov 
961e02d3fe7SAlexander V. Chernikov ATF_TC_BODY(rtm_del_v4_gu_ifa_prefixroute_success, tc)
962e02d3fe7SAlexander V. Chernikov {
963e02d3fe7SAlexander V. Chernikov 	DECLARE_TEST_VARS;
964e02d3fe7SAlexander V. Chernikov 
965e02d3fe7SAlexander V. Chernikov 	c = presetup_ipv4_iface(tc);
966e02d3fe7SAlexander V. Chernikov 
967e02d3fe7SAlexander V. Chernikov 
968e02d3fe7SAlexander V. Chernikov 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
969e02d3fe7SAlexander V. Chernikov 
970e02d3fe7SAlexander V. Chernikov 	c->rtsock_fd = rtsock_setup_socket();
971e02d3fe7SAlexander V. Chernikov 
972e02d3fe7SAlexander V. Chernikov 	ret = iface_delete_addr(c->ifname, c->addr4_str);
973e02d3fe7SAlexander V. Chernikov 
974e02d3fe7SAlexander V. Chernikov 	while (true) {
975e02d3fe7SAlexander V. Chernikov 		rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
976e02d3fe7SAlexander V. Chernikov 		/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
977e02d3fe7SAlexander V. Chernikov 		if ((rtm->rtm_type == RTM_DELETE) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
978e02d3fe7SAlexander V. Chernikov 			break;
979e02d3fe7SAlexander V. Chernikov 	}
980e02d3fe7SAlexander V. Chernikov 
981e02d3fe7SAlexander V. Chernikov 	/* This should be a message for the prefix route */
982e02d3fe7SAlexander V. Chernikov 	verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->net4,
983e02d3fe7SAlexander V. Chernikov 	    (struct sockaddr *)&c->mask4, NULL);
984e02d3fe7SAlexander V. Chernikov 
985e02d3fe7SAlexander V. Chernikov 	/* gateway should be link sdl with ifindex of an address interface */
986e02d3fe7SAlexander V. Chernikov 	verify_link_gateway(rtm, c->ifindex);
987e02d3fe7SAlexander V. Chernikov 
988e02d3fe7SAlexander V. Chernikov 	int expected_rt_flags = RTF_DONE | RTF_PINNED;
989e02d3fe7SAlexander V. Chernikov 	verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
990e02d3fe7SAlexander V. Chernikov }
991775dc861SAlexander V. Chernikov 
992775dc861SAlexander V. Chernikov 
993775dc861SAlexander V. Chernikov ATF_TP_ADD_TCS(tp)
994775dc861SAlexander V. Chernikov {
995775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_exact_success);
996775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_lpm_success);
997775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_hostbits_failure);
998775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_get_v4_empty_dst_failure);
999775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v4_gw_direct_success);
1000775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v4_prefix_nogw_success);
1001775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_gw_gu_direct_success);
1002775dc861SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_prefix_nogw_success);
1003e02d3fe7SAlexander V. Chernikov 	/* ifaddr tests */
1004e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_hostroute_success);
1005e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_prefixroute_success);
1006e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_ordered_success);
1007e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_ifa_hostroute_success);
1008e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_ifa_prefixroute_success);
1009e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v4_gu_ifa_ordered_success);
1010e02d3fe7SAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_del_v4_gu_ifa_prefixroute_success);
1011*34a5582cSAlexander V. Chernikov 	/* temporal routes */
1012*34a5582cSAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v4_temporal1_success);
1013*34a5582cSAlexander V. Chernikov 	ATF_TP_ADD_TC(tp, rtm_add_v6_temporal1_success);
1014775dc861SAlexander V. Chernikov 
1015775dc861SAlexander V. Chernikov 	return (atf_no_error());
1016775dc861SAlexander V. Chernikov }
1017775dc861SAlexander V. Chernikov 
1018