freebsd-src/tests/sys/net/routing/test_rtsock_l3.c
Alex Richardson 67f2f67fc8 Update rtsock_l3 test after 2fe5a79425
Two of these tests now pass. Looking at Jenkins to find the first commit
where this behaviour changed indicates that
2fe5a79425 is the most likely cause.

Reviewed By:	melifaro
Differential Revision: https://reviews.freebsd.org/D28886
2021-04-21 10:58:34 +01:00

1424 lines
43 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Alexander V. Chernikov
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "rtsock_common.h"
#include "rtsock_config.h"
#include "sys/types.h"
#include <sys/time.h>
#include <sys/ioctl.h>
#include "net/bpf.h"
static void
jump_vnet(struct rtsock_test_config *c, const atf_tc_t *tc)
{
char vnet_name[512];
snprintf(vnet_name, sizeof(vnet_name), "vt-%s", atf_tc_get_ident(tc));
RLOG("jumping to %s", vnet_name);
vnet_switch(vnet_name, c->ifnames, c->num_interfaces);
/* Update ifindex cache */
c->ifindex = if_nametoindex(c->ifname);
}
static inline struct rtsock_test_config *
presetup_ipv6_iface(const atf_tc_t *tc)
{
struct rtsock_test_config *c;
int ret;
c = config_setup(tc, NULL);
jump_vnet(c, tc);
ret = iface_turn_up(c->ifname);
ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
ret = iface_enable_ipv6(c->ifname);
ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifname);
ATF_REQUIRE_ERRNO(0, true);
return (c);
}
static inline struct rtsock_test_config *
presetup_ipv6(const atf_tc_t *tc)
{
struct rtsock_test_config *c;
int ret;
c = presetup_ipv6_iface(tc);
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
c->rtsock_fd = rtsock_setup_socket();
ATF_REQUIRE_ERRNO(0, true);
return (c);
}
static inline struct rtsock_test_config *
presetup_ipv4_iface(const atf_tc_t *tc)
{
struct rtsock_test_config *c;
int ret;
c = config_setup(tc, NULL);
ATF_REQUIRE(c != NULL);
jump_vnet(c, tc);
ret = iface_turn_up(c->ifname);
ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
ATF_REQUIRE_ERRNO(0, true);
return (c);
}
static inline struct rtsock_test_config *
presetup_ipv4(const atf_tc_t *tc)
{
struct rtsock_test_config *c;
int ret;
c = presetup_ipv4_iface(tc);
/* assumes ifconfig doing IFF_UP */
ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
c->rtsock_fd = rtsock_setup_socket();
ATF_REQUIRE_ERRNO(0, true);
return (c);
}
static void
prepare_v4_network(struct rtsock_test_config *c, struct sockaddr_in *dst,
struct sockaddr_in *mask, struct sockaddr_in *gw)
{
/* Create IPv4 subnetwork with smaller prefix */
sa_fill_mask4(mask, c->plen4 + 1);
*dst = c->net4;
/* Calculate GW as last-net-address - 1 */
*gw = c->net4;
gw->sin_addr.s_addr = htonl((ntohl(c->net4.sin_addr.s_addr) | ~ntohl(c->mask4.sin_addr.s_addr)) - 1);
sa_print((struct sockaddr *)dst, 0);
sa_print((struct sockaddr *)mask, 0);
sa_print((struct sockaddr *)gw, 0);
}
static void
prepare_v6_network(struct rtsock_test_config *c, struct sockaddr_in6 *dst,
struct sockaddr_in6 *mask, struct sockaddr_in6 *gw)
{
/* Create IPv6 subnetwork with smaller prefix */
sa_fill_mask6(mask, c->plen6 + 1);
*dst = c->net6;
/* Calculate GW as last-net-address - 1 */
*gw = c->net6;
#define _s6_addr32 __u6_addr.__u6_addr32
gw->sin6_addr._s6_addr32[0] = htonl((ntohl(gw->sin6_addr._s6_addr32[0]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[0])));
gw->sin6_addr._s6_addr32[1] = htonl((ntohl(gw->sin6_addr._s6_addr32[1]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[1])));
gw->sin6_addr._s6_addr32[2] = htonl((ntohl(gw->sin6_addr._s6_addr32[2]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[2])));
gw->sin6_addr._s6_addr32[3] = htonl((ntohl(gw->sin6_addr._s6_addr32[3]) | ~ntohl(c->mask6.sin6_addr._s6_addr32[3])) - 1);
#undef _s6_addr32
sa_print((struct sockaddr *)dst, 0);
sa_print((struct sockaddr *)mask, 0);
sa_print((struct sockaddr *)gw, 0);
}
static void
prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
struct sockaddr *mask, struct sockaddr *gw)
{
rtsock_prepare_route_message(rtm, cmd, dst, mask, gw);
if (cmd == RTM_ADD || cmd == RTM_CHANGE)
rtm->rtm_flags |= RTF_STATIC;
}
static void
verify_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
struct sockaddr *mask, struct sockaddr *gw)
{
char msg[512];
struct sockaddr *sa;
int ret;
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_type == cmd,
"expected %s message, got %d (%s)", rtsock_print_cmdtype(cmd),
rtm->rtm_type, rtsock_print_cmdtype(rtm->rtm_type));
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_errno == 0,
"got got errno %d as message reply", rtm->rtm_errno);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->_rtm_spare1 == 0,
"expected rtm_spare==0, got %d", rtm->_rtm_spare1);
/* kernel MAY return more sockaddrs, including RTA_IFP / RTA_IFA, so verify the needed ones */
if (dst != NULL) {
sa = rtsock_find_rtm_sa(rtm, RTA_DST);
RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "DST is not set");
ret = sa_equal_msg(sa, dst, msg, sizeof(msg));
RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
}
if (mask != NULL) {
sa = rtsock_find_rtm_sa(rtm, RTA_NETMASK);
RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "NETMASK is not set");
ret = sa_equal_msg(sa, mask, msg, sizeof(msg));
ret = 1;
RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "NETMASK sa diff: %s", msg);
}
if (gw != NULL) {
sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
ret = sa_equal_msg(sa, gw, msg, sizeof(msg));
RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
}
}
static void
verify_route_message_extra(struct rt_msghdr *rtm, int ifindex, int rtm_flags)
{
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_index == ifindex,
"expected ifindex %d, got %d", ifindex, rtm->rtm_index);
if (rtm->rtm_flags != rtm_flags) {
char got_flags[64], expected_flags[64];
rtsock_print_rtm_flags(got_flags, sizeof(got_flags),
rtm->rtm_flags);
rtsock_print_rtm_flags(expected_flags, sizeof(expected_flags),
rtm_flags);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == rtm_flags,
"expected flags: 0x%X %s, got 0x%X %s",
rtm_flags, expected_flags,
rtm->rtm_flags, got_flags);
}
}
static void
verify_link_gateway(struct rt_msghdr *rtm, int ifindex)
{
struct sockaddr *sa;
struct sockaddr_dl *sdl;
sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
RTSOCK_ATF_REQUIRE_MSG(rtm, sa->sa_family == AF_LINK, "GW sa family is %d", sa->sa_family);
sdl = (struct sockaddr_dl *)sa;
RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_index == ifindex, "GW ifindex is %d", sdl->sdl_index);
}
/* TESTS */
#define DECLARE_TEST_VARS \
char buffer[2048]; \
struct rtsock_test_config *c; \
struct rt_msghdr *rtm = (struct rt_msghdr *)buffer; \
struct sockaddr *sa; \
int ret; \
\
#define DESCRIBE_ROOT_TEST(_msg) config_describe_root_test(tc, _msg)
#define CLEANUP_AFTER_TEST config_generic_cleanup(tc)
#define RTM_DECLARE_ROOT_TEST(_name, _descr) \
ATF_TC_WITH_CLEANUP(_name); \
ATF_TC_HEAD(_name, tc) \
{ \
DESCRIBE_ROOT_TEST(_descr); \
} \
ATF_TC_CLEANUP(_name, tc) \
{ \
CLEANUP_AFTER_TEST; \
}
ATF_TC_WITH_CLEANUP(rtm_get_v4_exact_success);
ATF_TC_HEAD(rtm_get_v4_exact_success, tc)
{
DESCRIBE_ROOT_TEST("Tests RTM_GET with exact prefix lookup on an interface prefix");
}
ATF_TC_BODY(rtm_get_v4_exact_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
(struct sockaddr *)&c->mask4, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/*
* RTM_GET: Report Metrics: len 240, pid: 45072, seq 42, errno 0, flags: <UP,DONE,PINNED>
* sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
* af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
* af=link len=54 sdl_index=3 if_name=tap4242 hd={36, 12, 03, 00, 06, 00{49}}
* af=inet len=16 addr=255.255.255.0 hd={10, 02, FF{5}, 00{9}}
*/
verify_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
(struct sockaddr *)&c->mask4, NULL);
verify_route_message_extra(rtm, c->ifindex, RTF_UP | RTF_DONE | RTF_PINNED);
/* Explicitly verify gateway for the interface route */
verify_link_gateway(rtm, c->ifindex);
sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
RTSOCK_ATF_REQUIRE_MSG(rtm, sa != NULL, "GATEWAY is not set");
RTSOCK_ATF_REQUIRE_MSG(rtm, sa->sa_family == AF_LINK, "GW sa family is %d", sa->sa_family);
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_index == c->ifindex, "GW ifindex is %d", sdl->sdl_index);
}
ATF_TC_CLEANUP(rtm_get_v4_exact_success, tc)
{
CLEANUP_AFTER_TEST;
}
ATF_TC_WITH_CLEANUP(rtm_get_v4_lpm_success);
ATF_TC_HEAD(rtm_get_v4_lpm_success, tc)
{
DESCRIBE_ROOT_TEST("Tests RTM_GET with address lookup on an existing prefix");
}
ATF_TC_BODY(rtm_get_v4_lpm_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4, NULL, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/*
* RTM_GET: Report Metrics: len 312, pid: 67074, seq 1, errno 0, flags:<UP,DONE,PINNED>
* locks: inits:
* sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
* 10.0.0.0 link#1 255.255.255.0 vtnet0:52.54.0.42.f.ef 10.0.0.157
*/
verify_route_message(rtm, RTM_GET, (struct sockaddr *)&c->net4,
(struct sockaddr *)&c->mask4, NULL);
verify_route_message_extra(rtm, c->ifindex, RTF_UP | RTF_DONE | RTF_PINNED);
}
ATF_TC_CLEANUP(rtm_get_v4_lpm_success, tc)
{
CLEANUP_AFTER_TEST;
}
ATF_TC_WITH_CLEANUP(rtm_get_v4_empty_dst_failure);
ATF_TC_HEAD(rtm_get_v4_empty_dst_failure, tc)
{
DESCRIBE_ROOT_TEST("Tests RTM_GET with empty DST addr");
}
ATF_TC_BODY(rtm_get_v4_empty_dst_failure, tc)
{
DECLARE_TEST_VARS;
struct rtsock_config_options co;
bzero(&co, sizeof(co));
co.num_interfaces = 0;
c = config_setup(tc,&co);
c->rtsock_fd = rtsock_setup_socket();
rtsock_prepare_route_message(rtm, RTM_GET, NULL,
(struct sockaddr *)&c->mask4, NULL);
rtsock_update_rtm_len(rtm);
ATF_CHECK_ERRNO(EINVAL, write(c->rtsock_fd, rtm, rtm->rtm_msglen) == -1);
}
ATF_TC_CLEANUP(rtm_get_v4_empty_dst_failure, tc)
{
CLEANUP_AFTER_TEST;
}
ATF_TC_WITH_CLEANUP(rtm_get_v4_hostbits_success);
ATF_TC_HEAD(rtm_get_v4_hostbits_success, tc)
{
DESCRIBE_ROOT_TEST("Tests RTM_GET with prefix with some hosts-bits set");
}
ATF_TC_BODY(rtm_get_v4_hostbits_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
/* Q the same prefix */
rtsock_prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&c->addr4,
(struct sockaddr *)&c->mask4, NULL);
rtsock_update_rtm_len(rtm);
ATF_REQUIRE_ERRNO(0, true);
ATF_CHECK_ERRNO(0, write(c->rtsock_fd, rtm, rtm->rtm_msglen) > 0);
}
ATF_TC_CLEANUP(rtm_get_v4_hostbits_success, tc)
{
CLEANUP_AFTER_TEST;
}
ATF_TC_WITH_CLEANUP(rtm_add_v4_gw_direct_success);
ATF_TC_HEAD(rtm_add_v4_gw_direct_success, tc)
{
DESCRIBE_ROOT_TEST("Tests IPv4 route addition with directly-reachable GW specified by IP");
}
ATF_TC_BODY(rtm_add_v4_gw_direct_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/*
* RTM_ADD: Add Route: len 200, pid: 46068, seq 42, errno 0, flags:<GATEWAY,DONE,STATIC>
* locks: inits:
* sockaddrs: <DST,GATEWAY,NETMASK>
* 192.0.2.0 192.0.2.254 255.255.255.128
*/
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
verify_route_message_extra(rtm, c->ifindex,
RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
ATF_TC_CLEANUP(rtm_add_v4_gw_direct_success, tc)
{
CLEANUP_AFTER_TEST;
}
RTM_DECLARE_ROOT_TEST(rtm_add_v4_no_rtf_host_success,
"Tests success with netmask sa and RTF_HOST inconsistency");
ATF_TC_BODY(rtm_add_v4_no_rtf_host_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
NULL, (struct sockaddr *)&gw4);
rtsock_update_rtm_len(rtm);
/* RTF_HOST is NOT specified, while netmask is empty */
ATF_REQUIRE_ERRNO(0, true);
ATF_CHECK_ERRNO(0, write(c->rtsock_fd, rtm, rtm->rtm_msglen) > 0);
}
ATF_TC_WITH_CLEANUP(rtm_del_v4_prefix_nogw_success);
ATF_TC_HEAD(rtm_del_v4_prefix_nogw_success, tc)
{
DESCRIBE_ROOT_TEST("Tests IPv4 route removal without specifying gateway");
}
ATF_TC_BODY(rtm_del_v4_prefix_nogw_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
rtsock_send_rtm(c->rtsock_fd, rtm);
/* Route has been added successfully, try to delete it */
prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/*
* RTM_DELETE: Delete Route: len 200, pid: 46417, seq 43, errno 0, flags: <GATEWAY,DONE,STATIC>
* sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
* af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
* af=inet len=16 addr=192.0.2.254 hd={10, 02, 00{2}, C0, 00, 02, FE, 00{8}}
* af=inet len=16 addr=255.255.255.128 hd={10, 02, FF{5}, 80, 00{8}}
*/
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
ATF_TC_CLEANUP(rtm_del_v4_prefix_nogw_success, tc)
{
CLEANUP_AFTER_TEST;
}
RTM_DECLARE_ROOT_TEST(rtm_change_v4_gw_success,
"Tests IPv4 gateway change");
ATF_TC_BODY(rtm_change_v4_gw_success, tc)
{
DECLARE_TEST_VARS;
struct rtsock_config_options co;
bzero(&co, sizeof(co));
co.num_interfaces = 2;
c = config_setup(tc, &co);
jump_vnet(c, tc);
ret = iface_turn_up(c->ifnames[0]);
ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[0]);
ret = iface_turn_up(c->ifnames[1]);
ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[1]);
ret = iface_setup_addr(c->ifnames[0], c->addr4_str, c->plen4);
ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
/* Use 198.51.100.0/24 "TEST-NET-2" for the second interface */
ret = iface_setup_addr(c->ifnames[1], "198.51.100.1", 24);
ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
c->rtsock_fd = rtsock_setup_socket();
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
/* Change gateway to the one on desiding on the other interface */
inet_pton(AF_INET, "198.51.100.2", &gw4.sin_addr.s_addr);
prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
/* Verify the change has actually taken place */
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
/*
* RTM_GET: len 200, pid: 3894, seq 44, errno 0, flags: <UP,GATEWAY,DONE,STATIC>
* sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
* af=inet len=16 addr=192.0.2.0 hd={x10, x02, x00{2}, xC0, x00, x02, x00{9}}
* af=inet len=16 addr=198.51.100.2 hd={x10, x02, x00{2}, xC6, x33, x64, x02, x00{8}}
* af=inet len=16 addr=255.255.255.128 hd={x10, x02, xFF, xFF, xFF, xFF, xFF, x80, x00{8}}
*/
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
RTM_DECLARE_ROOT_TEST(rtm_change_v4_mtu_success,
"Tests IPv4 path mtu change");
ATF_TC_BODY(rtm_change_v4_mtu_success, tc)
{
DECLARE_TEST_VARS;
unsigned long test_mtu = 1442;
c = presetup_ipv4(tc);
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/* Change MTU */
prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
rtm->rtm_inits |= RTV_MTU;
rtm->rtm_rmx.rmx_mtu = test_mtu;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
"expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
/* Verify the change has actually taken place */
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
"expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
}
RTM_DECLARE_ROOT_TEST(rtm_change_v4_flags_success,
"Tests IPv4 path flags change");
ATF_TC_BODY(rtm_change_v4_flags_success, tc)
{
DECLARE_TEST_VARS;
uint32_t test_flags = RTF_PROTO1 | RTF_PROTO2 | RTF_PROTO3 | RTF_STATIC;
uint32_t desired_flags;
c = presetup_ipv4(tc);
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
/* Set test flags during route addition */
desired_flags = RTF_UP | RTF_DONE | RTF_GATEWAY | test_flags;
rtm->rtm_flags |= test_flags;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/* Change flags */
prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
rtm->rtm_flags &= ~test_flags;
desired_flags &= ~test_flags;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/* Verify updated flags */
verify_route_message_extra(rtm, c->ifindex, desired_flags | RTF_DONE);
/* Verify the change has actually taken place */
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message_extra(rtm, c->ifindex, desired_flags | RTF_DONE);
}
ATF_TC_WITH_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success);
ATF_TC_HEAD(rtm_add_v6_gu_gw_gu_direct_success, tc)
{
DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
}
ATF_TC_BODY(rtm_add_v6_gu_gw_gu_direct_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6(tc);
/* Create IPv6 subnetwork with smaller prefix */
struct sockaddr_in6 mask6;
struct sockaddr_in6 net6;
struct sockaddr_in6 gw6;
prepare_v6_network(c, &net6, &mask6, &gw6);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/*
* RTM_ADD: Add Route: len 200, pid: 46068, seq 42, errno 0, flags:<GATEWAY,DONE,STATIC>
* locks: inits:
* sockaddrs: <DST,GATEWAY,NETMASK>
* 192.0.2.0 192.0.2.254 255.255.255.128
*/
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
verify_route_message_extra(rtm, c->ifindex,
RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
ATF_TC_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success, tc)
{
CLEANUP_AFTER_TEST;
}
ATF_TC_WITH_CLEANUP(rtm_del_v6_gu_prefix_nogw_success);
ATF_TC_HEAD(rtm_del_v6_gu_prefix_nogw_success, tc)
{
DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix removal without specifying gateway");
}
ATF_TC_BODY(rtm_del_v6_gu_prefix_nogw_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6(tc);
/* Create IPv6 subnetwork with smaller prefix */
struct sockaddr_in6 mask6;
struct sockaddr_in6 net6;
struct sockaddr_in6 gw6;
prepare_v6_network(c, &net6, &mask6, &gw6);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
rtsock_send_rtm(c->rtsock_fd, rtm);
/* Route has been added successfully, try to delete it */
prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/*
* RTM_DELETE: Delete Route: len 200, pid: 46417, seq 43, errno 0, flags: <GATEWAY,DONE,STATIC>
* sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
* af=inet len=16 addr=192.0.2.0 hd={10, 02, 00{2}, C0, 00, 02, 00{9}}
* af=inet len=16 addr=192.0.2.254 hd={10, 02, 00{2}, C0, 00, 02, FE, 00{8}}
* af=inet len=16 addr=255.255.255.128 hd={10, 02, FF{5}, 80, 00{8}}
*/
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
ATF_TC_CLEANUP(rtm_del_v6_gu_prefix_nogw_success, tc)
{
CLEANUP_AFTER_TEST;
}
RTM_DECLARE_ROOT_TEST(rtm_change_v6_gw_success,
"Tests IPv6 gateway change");
ATF_TC_BODY(rtm_change_v6_gw_success, tc)
{
DECLARE_TEST_VARS;
struct rtsock_config_options co;
bzero(&co, sizeof(co));
co.num_interfaces = 2;
c = config_setup(tc, &co);
jump_vnet(c, tc);
ret = iface_turn_up(c->ifnames[0]);
ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[0]);
ret = iface_turn_up(c->ifnames[1]);
ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[1]);
ret = iface_enable_ipv6(c->ifnames[0]);
ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifnames[0]);
ret = iface_enable_ipv6(c->ifnames[1]);
ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifnames[1]);
ret = iface_setup_addr(c->ifnames[0], c->addr6_str, c->plen6);
ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
ret = iface_setup_addr(c->ifnames[1], "2001:DB8:4242::1", 64);
ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
c->rtsock_fd = rtsock_setup_socket();
/* Create IPv6 subnetwork with smaller prefix */
struct sockaddr_in6 mask6;
struct sockaddr_in6 net6;
struct sockaddr_in6 gw6;
prepare_v6_network(c, &net6, &mask6, &gw6);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
/* Change gateway to the one on residing on the other interface */
inet_pton(AF_INET6, "2001:DB8:4242::4242", &gw6.sin6_addr);
prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
/* Verify the change has actually taken place */
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
/*
* RTM_GET: len 248, pid: 2268, seq 44, errno 0, flags: <UP,GATEWAY,DONE,STATIC>
* sockaddrs: 0x7 <DST,GATEWAY,NETMASK>
* af=inet6 len=28 addr=2001:db8:: hd={x1C, x1C, x00{6}, x20, x01, x0D, xB8, x00{16}}
* 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}}
* af=inet6 len=28 addr=ffff:ffff:8000:: hd={x1C, x1C, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, x80, x00{15}}
*/
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]),
RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
RTM_DECLARE_ROOT_TEST(rtm_change_v6_mtu_success,
"Tests IPv6 path mtu change");
ATF_TC_BODY(rtm_change_v6_mtu_success, tc)
{
DECLARE_TEST_VARS;
unsigned long test_mtu = 1442;
c = presetup_ipv6(tc);
/* Create IPv6 subnetwork with smaller prefix */
struct sockaddr_in6 mask6;
struct sockaddr_in6 net6;
struct sockaddr_in6 gw6;
prepare_v6_network(c, &net6, &mask6, &gw6);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
/* Send route add */
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/* Change MTU */
prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
rtm->rtm_inits |= RTV_MTU;
rtm->rtm_rmx.rmx_mtu = test_mtu;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
"expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
/* Verify the change has actually taken place */
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu,
"expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu);
}
RTM_DECLARE_ROOT_TEST(rtm_change_v6_flags_success,
"Tests IPv6 path flags change");
ATF_TC_BODY(rtm_change_v6_flags_success, tc)
{
DECLARE_TEST_VARS;
uint32_t test_flags = RTF_PROTO1 | RTF_PROTO2 | RTF_PROTO3 | RTF_STATIC;
uint32_t desired_flags;
c = presetup_ipv6(tc);
/* Create IPv6 subnetwork with smaller prefix */
struct sockaddr_in6 mask6;
struct sockaddr_in6 net6;
struct sockaddr_in6 gw6;
prepare_v6_network(c, &net6, &mask6, &gw6);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
/* Set test flags during route addition */
desired_flags = RTF_UP | RTF_DONE | RTF_GATEWAY | test_flags;
rtm->rtm_flags |= test_flags;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/* Change flags */
prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
rtm->rtm_flags &= ~test_flags;
desired_flags &= ~test_flags;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
/* Verify updated flags */
verify_route_message_extra(rtm, c->ifindex, desired_flags | RTF_DONE);
/* Verify the change has actually taken place */
prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, NULL);
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
verify_route_message_extra(rtm, c->ifindex, desired_flags | RTF_DONE);
}
ATF_TC_WITH_CLEANUP(rtm_add_v4_temporal1_success);
ATF_TC_HEAD(rtm_add_v4_temporal1_success, tc)
{
DESCRIBE_ROOT_TEST("Tests IPv4 route expiration with expire time set");
}
ATF_TC_BODY(rtm_add_v4_temporal1_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4(tc);
/* Create IPv4 subnetwork with smaller prefix */
struct sockaddr_in mask4;
struct sockaddr_in net4;
struct sockaddr_in gw4;
prepare_v4_network(c, &net4, &mask4, &gw4);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
/* Set expire time to now */
struct timeval tv;
gettimeofday(&tv, NULL);
rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
rtm->rtm_inits |= RTV_EXPIRE;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
/* The next should be route deletion */
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
(struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
verify_route_message_extra(rtm, c->ifindex,
RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
ATF_TC_CLEANUP(rtm_add_v4_temporal1_success, tc)
{
CLEANUP_AFTER_TEST;
}
ATF_TC_WITH_CLEANUP(rtm_add_v6_temporal1_success);
ATF_TC_HEAD(rtm_add_v6_temporal1_success, tc)
{
DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
}
ATF_TC_BODY(rtm_add_v6_temporal1_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6(tc);
/* Create IPv6 subnetwork with smaller prefix */
struct sockaddr_in6 mask6;
struct sockaddr_in6 net6;
struct sockaddr_in6 gw6;
prepare_v6_network(c, &net6, &mask6, &gw6);
prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
/* Set expire time to now */
struct timeval tv;
gettimeofday(&tv, NULL);
rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
rtm->rtm_inits |= RTV_EXPIRE;
rtsock_send_rtm(c->rtsock_fd, rtm);
rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
/* The next should be route deletion */
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
(struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
verify_route_message_extra(rtm, c->ifindex,
RTF_DONE | RTF_GATEWAY | RTF_STATIC);
}
ATF_TC_CLEANUP(rtm_add_v6_temporal1_success, tc)
{
CLEANUP_AFTER_TEST;
}
/* Interface address messages tests */
RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_hostroute_success,
"Tests validness for /128 host route announce after ifaddr assignment");
ATF_TC_BODY(rtm_add_v6_gu_ifa_hostroute_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6_iface(tc);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
/*
* There will be multiple.
* RTM_ADD without llinfo.
*/
while (true) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
if ((rtm->rtm_type == RTM_ADD) && ((rtm->rtm_flags & RTF_LLINFO) == 0))
break;
}
/* This should be a message for the host route */
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->addr6, NULL, NULL);
rtsock_validate_pid_kernel(rtm);
/* No netmask should be set */
RTSOCK_ATF_REQUIRE_MSG(rtm, rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL, "netmask is set");
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
int expected_rt_flags = RTF_UP | RTF_HOST | RTF_DONE | RTF_STATIC | RTF_PINNED;
verify_route_message_extra(rtm, if_nametoindex("lo0"), expected_rt_flags);
}
RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_prefixroute_success,
"Tests validness for the prefix route announce after ifaddr assignment");
ATF_TC_BODY(rtm_add_v6_gu_ifa_prefixroute_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6_iface(tc);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
/*
* Multiple RTM_ADD messages will be generated:
* 1) lladdr mapping (RTF_LLDATA)
* 2) host route (one w/o netmask)
* 3) prefix route
*/
while (true) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
break;
}
/* This should be a message for the prefix route */
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->net6,
(struct sockaddr *)&c->mask6, NULL);
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
int expected_rt_flags = RTF_UP | RTF_DONE | RTF_PINNED;
verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
}
RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_ifa_ordered_success,
"Tests ordering of the messages for IPv6 global unicast ifaddr assignment");
ATF_TC_BODY(rtm_add_v6_gu_ifa_ordered_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6_iface(tc);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
int count = 0, tries = 0;
enum msgtype {
MSG_IFADDR,
MSG_HOSTROUTE,
MSG_PREFIXROUTE,
MSG_MAX,
};
int msg_array[MSG_MAX];
bzero(msg_array, sizeof(msg_array));
while (count < 3 && tries < 20) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
tries++;
/* Classify */
if (rtm->rtm_type == RTM_NEWADDR) {
RLOG("MSG_IFADDR: %d", count);
msg_array[MSG_IFADDR] = count++;
continue;
}
/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK))) {
RLOG("MSG_PREFIXROUTE: %d", count);
msg_array[MSG_PREFIXROUTE] = count++;
continue;
}
if ((rtm->rtm_type == RTM_ADD) && ((rtm->rtm_flags & RTF_LLDATA) == 0)) {
RLOG("MSG_HOSTROUTE: %d", count);
msg_array[MSG_HOSTROUTE] = count++;
continue;
}
RLOG("skipping msg type %s, try: %d", rtsock_print_cmdtype(rtm->rtm_type),
tries);
}
/* TODO: verify multicast */
ATF_REQUIRE_MSG(count == 3, "Received only %d/3 messages", count);
ATF_REQUIRE_MSG(msg_array[MSG_IFADDR] == 0, "ifaddr message is not the first");
}
RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_ifa_hostroute_success,
"Tests validness for /128 host route removal after ifaddr removal");
ATF_TC_BODY(rtm_del_v6_gu_ifa_hostroute_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6_iface(tc);
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_delete_addr(c->ifname, c->addr6_str);
while (true) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
if ((rtm->rtm_type == RTM_DELETE) &&
((rtm->rtm_flags & RTF_LLINFO) == 0) &&
rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL)
break;
}
/* This should be a message for the host route */
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->addr6, NULL, NULL);
rtsock_validate_pid_kernel(rtm);
/* No netmask should be set */
RTSOCK_ATF_REQUIRE_MSG(rtm, rtsock_find_rtm_sa(rtm, RTA_NETMASK) == NULL, "netmask is set");
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
/* XXX: consider passing ifindex in rtm_index as done in RTM_ADD. */
int expected_rt_flags = RTF_HOST | RTF_DONE | RTF_STATIC | RTF_PINNED;
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == expected_rt_flags,
"expected rtm flags: 0x%X, got 0x%X", expected_rt_flags, rtm->rtm_flags);
}
RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_ifa_prefixroute_success,
"Tests validness for the prefix route removal after ifaddr assignment");
ATF_TC_BODY(rtm_del_v6_gu_ifa_prefixroute_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv6_iface(tc);
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_delete_addr(c->ifname, c->addr6_str);
while (true) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
/* Find RTM_DELETE with netmask - this should skip both host route and LLADDR */
if ((rtm->rtm_type == RTM_DELETE) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
break;
}
/* This should be a message for the prefix route */
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->net6,
(struct sockaddr *)&c->mask6, NULL);
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
int expected_rt_flags = RTF_DONE | RTF_PINNED;
verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
}
RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_ifa_prefixroute_success,
"Tests validness for the prefix route announce after ifaddr assignment");
ATF_TC_BODY(rtm_add_v4_gu_ifa_prefixroute_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4_iface(tc);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_setup_addr(c->ifname, c->addr6_str, c->plen6);
/*
* Multiple RTM_ADD messages will be generated:
* 1) lladdr mapping (RTF_LLDATA)
* 3) prefix route
*/
while (true) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
break;
}
/* This should be a message for the prefix route */
verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&c->net4,
(struct sockaddr *)&c->mask4, NULL);
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
int expected_rt_flags = RTF_UP | RTF_DONE | RTF_PINNED;
verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
}
RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_ifa_ordered_success,
"Tests ordering of the messages for IPv4 unicast ifaddr assignment");
ATF_TC_BODY(rtm_add_v4_gu_ifa_ordered_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4_iface(tc);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
int count = 0, tries = 0;
enum msgtype {
MSG_IFADDR,
MSG_PREFIXROUTE,
MSG_MAX,
};
int msg_array[MSG_MAX];
bzero(msg_array, sizeof(msg_array));
while (count < 2 && tries < 20) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
tries++;
/* Classify */
if (rtm->rtm_type == RTM_NEWADDR) {
RLOG("MSG_IFADDR: %d", count);
msg_array[MSG_IFADDR] = count++;
continue;
}
/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
if ((rtm->rtm_type == RTM_ADD) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK))) {
RLOG("MSG_PREFIXROUTE: %d", count);
msg_array[MSG_PREFIXROUTE] = count++;
continue;
}
RLOG("skipping msg type %s, try: %d", rtsock_print_cmdtype(rtm->rtm_type),
tries);
}
/* TODO: verify multicast */
ATF_REQUIRE_MSG(count == 2, "Received only %d/2 messages", count);
ATF_REQUIRE_MSG(msg_array[MSG_IFADDR] == 0, "ifaddr message is not the first");
}
RTM_DECLARE_ROOT_TEST(rtm_del_v4_gu_ifa_prefixroute_success,
"Tests validness for the prefix route removal after ifaddr assignment");
ATF_TC_BODY(rtm_del_v4_gu_ifa_prefixroute_success, tc)
{
DECLARE_TEST_VARS;
c = presetup_ipv4_iface(tc);
ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
c->rtsock_fd = rtsock_setup_socket();
ret = iface_delete_addr(c->ifname, c->addr4_str);
while (true) {
rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
/* Find RTM_ADD with netmask - this should skip both host route and LLADDR */
if ((rtm->rtm_type == RTM_DELETE) && (rtsock_find_rtm_sa(rtm, RTA_NETMASK)))
break;
}
/* This should be a message for the prefix route */
verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&c->net4,
(struct sockaddr *)&c->mask4, NULL);
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
int expected_rt_flags = RTF_DONE | RTF_PINNED;
verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, rtm_get_v4_exact_success);
ATF_TP_ADD_TC(tp, rtm_get_v4_lpm_success);
ATF_TP_ADD_TC(tp, rtm_get_v4_hostbits_success);
ATF_TP_ADD_TC(tp, rtm_get_v4_empty_dst_failure);
ATF_TP_ADD_TC(tp, rtm_add_v4_no_rtf_host_success);
ATF_TP_ADD_TC(tp, rtm_add_v4_gw_direct_success);
ATF_TP_ADD_TC(tp, rtm_del_v4_prefix_nogw_success);
ATF_TP_ADD_TC(tp, rtm_add_v6_gu_gw_gu_direct_success);
ATF_TP_ADD_TC(tp, rtm_del_v6_gu_prefix_nogw_success);
ATF_TP_ADD_TC(tp, rtm_change_v4_gw_success);
ATF_TP_ADD_TC(tp, rtm_change_v4_mtu_success);
ATF_TP_ADD_TC(tp, rtm_change_v4_flags_success);
ATF_TP_ADD_TC(tp, rtm_change_v6_gw_success);
ATF_TP_ADD_TC(tp, rtm_change_v6_mtu_success);
ATF_TP_ADD_TC(tp, rtm_change_v6_flags_success);
/* ifaddr tests */
ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_hostroute_success);
ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_prefixroute_success);
ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_ordered_success);
ATF_TP_ADD_TC(tp, rtm_del_v6_gu_ifa_hostroute_success);
ATF_TP_ADD_TC(tp, rtm_del_v6_gu_ifa_prefixroute_success);
ATF_TP_ADD_TC(tp, rtm_add_v4_gu_ifa_ordered_success);
ATF_TP_ADD_TC(tp, rtm_del_v4_gu_ifa_prefixroute_success);
/* temporal routes */
ATF_TP_ADD_TC(tp, rtm_add_v4_temporal1_success);
ATF_TP_ADD_TC(tp, rtm_add_v6_temporal1_success);
return (atf_no_error());
}