aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/net
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2020-01-07 21:16:30 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2020-01-07 21:16:30 +0000
commite02d3fe70c7247027c85d60179c331618554ba34 (patch)
tree3afa43dce43c8d86de536b441c08a4c5ea4c15f1 /tests/sys/net
parent9a1d4b00122fb5a9d5594b468baee4c10d7f47f3 (diff)
downloadsrc-e02d3fe70c7247027c85d60179c331618554ba34.tar.gz
src-e02d3fe70c7247027c85d60179c331618554ba34.zip
Fix rtsock route message generation for interface addresses.
Reviewed by: olivier MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D22974
Notes
Notes: svn path=/head/; revision=356473
Diffstat (limited to 'tests/sys/net')
-rw-r--r--tests/sys/net/routing/rtsock_common.h66
-rw-r--r--tests/sys/net/routing/rtsock_print.h104
-rw-r--r--tests/sys/net/routing/test_rtsock_l3.c502
3 files changed, 646 insertions, 26 deletions
diff --git a/tests/sys/net/routing/rtsock_common.h b/tests/sys/net/routing/rtsock_common.h
index 9029a752cb78..de5b39e170fe 100644
--- a/tests/sys/net/routing/rtsock_common.h
+++ b/tests/sys/net/routing/rtsock_common.h
@@ -37,6 +37,7 @@
#include <fcntl.h>
#include <stdbool.h>
#include <ctype.h>
+#include <poll.h>
#include <sys/types.h>
#include <sys/time.h>
@@ -594,6 +595,17 @@ struct rt_msghdr *
rtsock_read_rtm(int fd, char *buffer, size_t buflen)
{
ssize_t len;
+ struct pollfd pfd;
+ int poll_delay = 5 * 1000; /* 5 seconds */
+
+ /* Check for the data available to read first */
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ if (poll(&pfd, 1, poll_delay) == 0)
+ ATF_REQUIRE_MSG(1 == 0, "rtsock read timed out (%d seconds passed)",
+ poll_delay / 1000);
len = read(fd, buffer, buflen);
int my_errno = errno;
@@ -706,35 +718,36 @@ rtsock_update_rtm_len(struct rt_msghdr *rtm)
}
static void
-_validate_route_message(struct rt_msghdr *rtm)
+_validate_message_sockaddrs(char *buffer, int rtm_len, size_t offset, int rtm_addrs)
{
struct sockaddr *sa;
- size_t parsed_len = sizeof(struct rt_msghdr);
- int len = rtm->rtm_msglen;
+ size_t parsed_len = offset;
- sa = (struct sockaddr *)(rtm + 1);
+ /* Offset denotes initial header size */
+ sa = (struct sockaddr *)(buffer + offset);
for (int i = 0; i < RTAX_MAX; i++) {
- if ((rtm->rtm_addrs & (1 << i)) == 0)
+ if ((rtm_addrs & (1 << i)) == 0)
continue;
parsed_len += SA_SIZE(sa);
- RTSOCK_ATF_REQUIRE_MSG(rtm, parsed_len <= len,
- "SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, len);
+ RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len <= rtm_len,
+ "SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, rtm_len);
if (sa->sa_family == AF_LINK) {
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
int data_len = sdl->sdl_nlen + sdl->sdl_alen;
data_len += offsetof(struct sockaddr_dl, sdl_data);
- RTSOCK_ATF_REQUIRE_MSG(rtm, data_len <= len,
- "AF_LINK data size exceeds total len: %u vs %u",
- data_len, len);
+ RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer,
+ data_len <= rtm_len,
+ "AF_LINK data size exceeds total len: %u vs %u, nlen=%d alen=%d",
+ data_len, rtm_len, sdl->sdl_nlen, sdl->sdl_alen);
}
sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
}
- RTSOCK_ATF_REQUIRE_MSG(rtm, parsed_len == rtm->rtm_msglen,
+ RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len == rtm_len,
"message len != parsed len: expected %d parsed %d",
- rtm->rtm_msglen, (int)parsed_len);
+ rtm_len, (int)parsed_len);
}
/*
@@ -758,9 +771,36 @@ rtsock_validate_message(char *buffer, ssize_t len)
case RTM_ADD:
case RTM_DELETE:
case RTM_CHANGE:
- _validate_route_message(rtm);
+ _validate_message_sockaddrs(buffer, rtm->rtm_msglen,
+ sizeof(struct rt_msghdr), rtm->rtm_addrs);
+ break;
+ case RTM_DELADDR:
+ case RTM_NEWADDR:
+ _validate_message_sockaddrs(buffer, rtm->rtm_msglen,
+ sizeof(struct ifa_msghdr), ((struct ifa_msghdr *)buffer)->ifam_addrs);
break;
}
}
+void
+rtsock_validate_pid_ours(struct rt_msghdr *rtm)
+{
+ RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == getpid(), "expected pid %d, got %d",
+ getpid(), rtm->rtm_pid);
+}
+
+void
+rtsock_validate_pid_user(struct rt_msghdr *rtm)
+{
+ RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid, got %d",
+ rtm->rtm_pid);
+}
+
+void
+rtsock_validate_pid_kernel(struct rt_msghdr *rtm)
+{
+ RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == 0, "expected zero pid, got %d",
+ rtm->rtm_pid);
+}
+
#endif
diff --git a/tests/sys/net/routing/rtsock_print.h b/tests/sys/net/routing/rtsock_print.h
index a4c16ebdbca9..cdb661febea0 100644
--- a/tests/sys/net/routing/rtsock_print.h
+++ b/tests/sys/net/routing/rtsock_print.h
@@ -40,7 +40,15 @@
#define RTSOCK_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...) do { \
if (!(_cond)) { \
printf("-- CONDITION FAILED, rtm dump --\n\n");\
- rtsock_print_rtm(_rtm); \
+ rtsock_print_message(_rtm); \
+ } \
+ ATF_REQUIRE_MSG(_cond, _fmt, ##__VA_ARGS__); \
+} while (0);
+
+#define RTSOCKHD_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...) do { \
+ if (!(_cond)) { \
+ printf("-- CONDITION FAILED, rtm hexdump--\n\n");\
+ rtsock_print_message_hd(_rtm); \
} \
ATF_REQUIRE_MSG(_cond, _fmt, ##__VA_ARGS__); \
} while (0);
@@ -145,7 +153,7 @@ sa_print_hd(char *buf, int buflen, const char *data, int len)
unsigned char v;
int repeat_count = 0;
for (int i = 0; i < len; i++) {
- if (last_char && *last_char == data[i]) {
+ if (last_char && *last_char == data[i] && data[i] == 0x00) {
repeat_count++;
continue;
}
@@ -157,9 +165,9 @@ sa_print_hd(char *buf, int buflen, const char *data, int len)
v = ((const unsigned char *)data)[i];
if (last_char == NULL)
- _PRINTX("%02X", v);
+ _PRINTX("x%02X", v);
else
- _PRINTX(", %02X", v);
+ _PRINTX(", x%02X", v);
last_char = &data[i];
repeat_count = 1;
@@ -259,6 +267,19 @@ rtsock_print_rtm(struct rt_msghdr *rtm)
printf("%s: len %hu, pid: %d, seq %d, errno %d, flags: %s\n", msgtypes[rtm->rtm_type],
rtm->rtm_msglen, rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno, flags_buf);
+ if (rtm->rtm_inits > 0) {
+ _printb(flags_buf, sizeof(flags_buf), rtm->rtm_inits, metricnames);
+ printf("metrics: %s\n", flags_buf);
+ if (rtm->rtm_inits & RTV_MTU)
+ printf("mtu: %lu\n", rtm->rtm_rmx.rmx_mtu);
+ if (rtm->rtm_inits & RTV_EXPIRE) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ printf("expire: %d (%lu raw)\n",
+ (int)(rtm->rtm_rmx.rmx_expire - tv.tv_sec), rtm->rtm_rmx.rmx_expire);
+ }
+ }
+
_printb(flags_buf, sizeof(flags_buf), rtm->rtm_addrs, addrnames);
printf("sockaddrs: 0x%X %s\n", rtm->rtm_addrs, flags_buf);
@@ -277,4 +298,79 @@ rtsock_print_rtm(struct rt_msghdr *rtm)
}
+void
+rtsock_print_ifa(struct ifa_msghdr *ifam)
+{
+ struct timeval tv;
+ struct tm tm_res;
+ char buf[64];
+
+ gettimeofday(&tv, NULL);
+ localtime_r(&tv.tv_sec, &tm_res);
+ strftime(buf, sizeof(buf), "%F %T", &tm_res);
+ printf("Got message of size %hu on %s\n", ifam->ifam_msglen, buf);
+
+ char flags_buf[256];
+ _printb(flags_buf, sizeof(flags_buf), ifam->ifam_flags, routeflags);
+
+ printf("%s: len %hu, ifindex: %d, flags: %s\n", msgtypes[ifam->ifam_type],
+ ifam->ifam_msglen, ifam->ifam_index, flags_buf);
+
+ _printb(flags_buf, sizeof(flags_buf), ifam->ifam_addrs, addrnames);
+ printf("sockaddrs: 0x%X %s\n", ifam->ifam_addrs, flags_buf);
+
+ char *ptr = (char *)(ifam + 1);
+ for (int i = 0; i < RTAX_MAX; i++) {
+ if (ifam->ifam_addrs & (1 << i)) {
+ struct sockaddr *sa = (struct sockaddr *)ptr;
+ sa_print(sa, 1);
+
+ /* add */
+ ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
+ }
+ }
+
+ printf("\n");
+
+}
+
+void
+rtsock_print_message_hd(struct rt_msghdr *rtm)
+{
+ struct timeval tv;
+ struct tm tm_res;
+ char buf[64];
+ char dumpbuf[2048];
+
+ gettimeofday(&tv, NULL);
+ localtime_r(&tv.tv_sec, &tm_res);
+ strftime(buf, sizeof(buf), "%F %T", &tm_res);
+ printf("Got message type %s of size %hu on %s\n",
+ rtsock_print_cmdtype(rtm->rtm_type),
+ rtm->rtm_msglen, buf);
+
+ sa_print_hd(dumpbuf, sizeof(dumpbuf), (char *)rtm, rtm->rtm_msglen);
+ printf(" %s\n", dumpbuf);
+}
+
+void
+rtsock_print_message(struct rt_msghdr *rtm)
+{
+
+ switch (rtm->rtm_type) {
+ case RTM_GET:
+ case RTM_ADD:
+ case RTM_DELETE:
+ case RTM_CHANGE:
+ rtsock_print_rtm(rtm);
+ break;
+ case RTM_DELADDR:
+ case RTM_NEWADDR:
+ rtsock_print_ifa((struct ifa_msghdr *)rtm);
+ break;
+ default:
+ printf("unknown rt message type %X\n", rtm->rtm_type);
+ }
+}
+
#endif
diff --git a/tests/sys/net/routing/test_rtsock_l3.c b/tests/sys/net/routing/test_rtsock_l3.c
index 5d1bd88bbb92..ad02f130ead9 100644
--- a/tests/sys/net/routing/test_rtsock_l3.c
+++ b/tests/sys/net/routing/test_rtsock_l3.c
@@ -29,9 +29,14 @@
#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 inline struct rtsock_test_config *
-presetup_ipv6(const atf_tc_t *tc)
+presetup_ipv6_iface(const atf_tc_t *tc)
{
struct rtsock_test_config *c;
int ret;
@@ -44,6 +49,17 @@ presetup_ipv6(const atf_tc_t *tc)
ret = iface_enable_ipv6(c->ifname);
ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifname);
+ 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();
@@ -52,16 +68,15 @@ presetup_ipv6(const atf_tc_t *tc)
}
static inline struct rtsock_test_config *
-presetup_ipv4(const atf_tc_t *tc)
+presetup_ipv4_iface(const atf_tc_t *tc)
{
struct rtsock_test_config *c;
int ret;
c = config_setup(tc);
- /* assumes ifconfig doing IFF_UP */
- ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
- ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
+ ret = iface_turn_up(c->ifname);
+ ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
/* Actually open interface, so kernel writes won't fail */
if (c->autocreated_interface) {
@@ -69,6 +84,21 @@ presetup_ipv4(const atf_tc_t *tc)
ATF_REQUIRE_MSG(ret >= 0, "unable to open interface %s", c->ifname);
}
+ 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();
return (c);
@@ -158,8 +188,6 @@ verify_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
ret = sa_equal_msg(sa, gw, msg, sizeof(msg));
RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
}
-
- RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid");
}
static void
@@ -169,7 +197,20 @@ verify_route_message_extra(struct rt_msghdr *rtm, int ifindex, int rtm_flags)
"expected ifindex %d, got %d", ifindex, rtm->rtm_index);
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == rtm_flags,
- "expected flags: %X, got %X", rtm_flags, rtm->rtm_flags);
+ "expected flags: 0x%X, got 0x%X", rtm_flags, rtm->rtm_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 */
@@ -185,6 +226,16 @@ verify_route_message_extra(struct rt_msghdr *rtm, int ifindex, int rtm_flags)
#define DESCRIBE_ROOT_TEST(_msg) config_describe_root_test(tc, _msg)
#define CLEANUP_AFTER_TEST config_generic_cleanup(config_setup(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)
@@ -219,6 +270,7 @@ ATF_TC_BODY(rtm_get_v4_exact_success, tc)
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);
@@ -247,7 +299,7 @@ ATF_TC_BODY(rtm_get_v4_lpm_success, tc)
rtsock_send_rtm(c->rtsock_fd, rtm);
- rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
+ 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>
@@ -503,6 +555,430 @@ ATF_TC_CLEANUP(rtm_del_v6_gu_prefix_nogw_success, tc)
CLEANUP_AFTER_TEST;
}
+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);
+
+ /* TODO: add RTF_DONE */
+ verify_route_message_extra(rtm, c->ifindex, 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);
+
+
+ /* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
+ /* TODO: add RTF_DONE */
+ verify_route_message_extra(rtm, c->ifindex, 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);
+
+ /* TODO: PINNED? */
+ int expected_rt_flags = RTF_UP | RTF_DONE;
+ 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;
+ 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)
@@ -515,6 +991,14 @@ ATF_TP_ADD_TCS(tp)
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);
+ /* 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);
return (atf_no_error());
}