From e02d3fe70c7247027c85d60179c331618554ba34 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Tue, 7 Jan 2020 21:16:30 +0000 Subject: Fix rtsock route message generation for interface addresses. Reviewed by: olivier MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D22974 --- tests/sys/net/routing/rtsock_common.h | 66 ++++- tests/sys/net/routing/rtsock_print.h | 104 ++++++- tests/sys/net/routing/test_rtsock_l3.c | 502 ++++++++++++++++++++++++++++++++- 3 files changed, 646 insertions(+), 26 deletions(-) (limited to 'tests/sys/net') 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 #include #include +#include #include #include @@ -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 +#include + +#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: @@ -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()); } -- cgit v1.2.3