Index: head/tests/sys/net/routing/rtsock_print.h =================================================================== --- head/tests/sys/net/routing/rtsock_print.h (revision 356595) +++ head/tests/sys/net/routing/rtsock_print.h (revision 356596) @@ -1,376 +1,384 @@ /*- * 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$ */ #ifndef _NET_ROUTING_RTSOCK_PRINT_H_ #define _NET_ROUTING_RTSOCK_PRINT_H_ #define RLOG(_fmt, ...) printf("%s: " _fmt "\n", __func__, ##__VA_ARGS__) #define RLOG_ERRNO(_fmt, ...) do { \ printf("%s: " _fmt, __func__, ##__VA_ARGS__); \ printf(": %s\n", strerror(errno)); \ } while(0) #define RTSOCK_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...) do { \ if (!(_cond)) { \ printf("-- CONDITION FAILED, rtm dump --\n\n");\ 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); /* from route.c */ static const char *const msgtypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING", "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE", "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR", "RTM_IFANNOUNCE", "RTM_IEEE80211", }; static const char metricnames[] = "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" "\1mtu"; static const char routeflags[] = "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; static const char ifnetflags[] = "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" "\017LINK2\020MULTICAST"; static const char addrnames[] = "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; static int _printb(char *buf, size_t bufsize, int b, const char *str) { int i; int gotsome = 0; char *pbuf = buf; if (b == 0) { *pbuf = '\0'; return (0); } while ((i = *str++) != 0) { if (b & (1 << (i-1))) { if (gotsome == 0) i = '<'; else i = ','; *pbuf++ = i; gotsome = 1; for (; (i = *str) > 32; str++) *pbuf++ = i; } else while (*str > 32) str++; } if (gotsome) *pbuf++ = '>'; *pbuf = '\0'; return (int)(pbuf - buf); } const char * rtsock_print_cmdtype(int cmd) { return (msgtypes[cmd]); } +char * +rtsock_print_rtm_flags(char *buf, int buflen, int rtm_flags) +{ + _printb(buf, buflen, rtm_flags, routeflags); + return (buf); +} + + #define _PRINTX(fmt, ...) do { \ one_len = snprintf(ptr, rem_len, fmt, __VA_ARGS__); \ ptr += one_len; \ rem_len -= one_len; \ } while(0) void sa_print_hd(char *buf, int buflen, const char *data, int len) { char *ptr; int one_len, rem_len; ptr = buf; rem_len = buflen; const char *last_char = NULL; unsigned char v; int repeat_count = 0; for (int i = 0; i < len; i++) { if (last_char && *last_char == data[i] && data[i] == 0x00) { repeat_count++; continue; } if (repeat_count > 1) { _PRINTX("{%d}", repeat_count); repeat_count = 0; } v = ((const unsigned char *)data)[i]; if (last_char == NULL) _PRINTX("x%02X", v); else _PRINTX(", x%02X", v); last_char = &data[i]; repeat_count = 1; } if (repeat_count > 1) snprintf(ptr, rem_len, "{%d}", repeat_count); } #undef _PRINTX void sa_print(const struct sockaddr *sa, int include_hexdump) { char hdbuf[512], abuf[64]; char ifbuf[128]; const struct sockaddr_dl *sdl; const struct sockaddr_in6 *sin6; const struct sockaddr_in *sin; int i; switch (sa->sa_family) { case AF_INET: sin = (struct sockaddr_in *)sa; inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf)); printf(" af=inet len=%d addr=%s", sa->sa_len, abuf); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)sa; inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof(abuf)); int scope_id = sin6->sin6_scope_id; printf(" af=inet6 len=%d addr=%s", sa->sa_len, abuf); if (scope_id != 0) { memset(ifbuf, 0, sizeof(ifbuf)); if_indextoname(scope_id, ifbuf); printf(" scope_id=%d if_name=%s", scope_id, ifbuf); } break; case AF_LINK: sdl = (const struct sockaddr_dl *)sa; int sdl_index = sdl->sdl_index; if (sdl_index != 0) { memset(ifbuf, 0, sizeof(ifbuf)); if_indextoname(sdl_index, ifbuf); printf(" af=link len=%d sdl_index=%d if_name=%s", sdl->sdl_len, sdl_index, ifbuf); } if (sdl->sdl_nlen) { char _ifname[IFNAMSIZ]; memcpy(_ifname, sdl->sdl_data, sdl->sdl_nlen); _ifname[sdl->sdl_nlen] = '\0'; printf(" name=%s", _ifname); } if (sdl->sdl_alen) { printf(" addr="); const char *lladdr = LLADDR(sdl); for (int i = 0; i < sdl->sdl_alen; i++) { if (i + 1 < sdl->sdl_alen) printf("%02X:", ((const unsigned char *)lladdr)[i]); else printf("%02X", ((const unsigned char *)lladdr)[i]); } } break; default: printf(" af=%d len=%d", sa->sa_family, sa->sa_len); } if (include_hexdump) { sa_print_hd(hdbuf, sizeof(hdbuf), ((char *)sa), sa->sa_len); printf(" hd={%s}", hdbuf); } printf("\n"); } /* got message of size 240 on Mon Dec 16 09:23:31 2019 RTM_ADD: Add Route: len 240, pid: 25534, seq 2, errno 0, flags: locks: inits: sockaddrs: */ void rtsock_print_rtm(struct rt_msghdr *rtm) { 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", rtm->rtm_msglen, buf); char flags_buf[256]; - _printb(flags_buf, sizeof(flags_buf), rtm->rtm_flags, routeflags); + rtsock_print_rtm_flags(flags_buf, sizeof(flags_buf), rtm->rtm_flags); 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); char *ptr = (char *)(rtm + 1); for (int i = 0; i < RTAX_MAX; i++) { if (rtm->rtm_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_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 Index: head/tests/sys/net/routing/test_rtsock_l3.c =================================================================== --- head/tests/sys/net/routing/test_rtsock_l3.c (revision 356595) +++ head/tests/sys/net/routing/test_rtsock_l3.c (revision 356596) @@ -1,1005 +1,1015 @@ /*- * 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 #include #include "net/bpf.h" 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); 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); 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(); 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); 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) { ret = iface_open(c->ifname); 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); } 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)); 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); - RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_flags == rtm_flags, - "expected flags: 0x%X, got 0x%X", rtm_flags, rtm->rtm_flags); + 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(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) { 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: * sockaddrs: 0x7 * 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: * locks: inits: * sockaddrs: * 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; c = config_setup_base(tc); c->rtsock_fd = rtsock_setup_socket(); rtsock_prepare_route_message(rtm, RTM_GET, NULL, (struct sockaddr *)&c->mask4, NULL); rtsock_update_rtm_len(rtm); write(c->rtsock_fd, rtm, rtm->rtm_msglen); ATF_CHECK_ERRNO(EINVAL, write(c->rtsock_fd, rtm, rtm->rtm_msglen)); } ATF_TC_CLEANUP(rtm_get_v4_empty_dst_failure, tc) { CLEANUP_AFTER_TEST; } ATF_TC_WITH_CLEANUP(rtm_get_v4_hostbits_failure); ATF_TC_HEAD(rtm_get_v4_hostbits_failure, tc) { DESCRIBE_ROOT_TEST("Tests RTM_GET with prefix with some hosts-bits set"); } ATF_TC_BODY(rtm_get_v4_hostbits_failure, 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_CHECK_ERRNO(ESRCH, write(c->rtsock_fd, rtm, rtm->rtm_msglen)); } ATF_TC_CLEANUP(rtm_get_v4_hostbits_failure, 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: * locks: inits: * sockaddrs: * 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); /* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */ verify_route_message_extra(rtm, c->ifindex, RTF_DONE | RTF_GATEWAY | RTF_STATIC); } ATF_TC_CLEANUP(rtm_add_v4_gw_direct_success, tc) { CLEANUP_AFTER_TEST; } 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: * sockaddrs: 0x7 * 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; } 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: * locks: inits: * sockaddrs: * 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); /* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */ verify_route_message_extra(rtm, c->ifindex, 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: * sockaddrs: 0x7 * 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; } 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) { 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_failure); ATF_TP_ADD_TC(tp, rtm_get_v4_empty_dst_failure); 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); /* 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()); }