Fix rtsock route message generation for interface addresses.
Reviewed by: olivier MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D22974
This commit is contained in:
parent
9a1d4b0012
commit
e02d3fe70c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356473
@ -2147,7 +2147,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
|
||||
#endif
|
||||
RT_ADDREF(rt);
|
||||
RT_UNLOCK(rt);
|
||||
rt_newaddrmsg_fib(cmd, ifa, error, rt, fibnum);
|
||||
rt_newaddrmsg_fib(cmd, ifa, rt, fibnum);
|
||||
RT_LOCK(rt);
|
||||
RT_REMREF(rt);
|
||||
if (cmd == RTM_DELETE) {
|
||||
@ -2233,17 +2233,16 @@ rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
|
||||
}
|
||||
|
||||
/*
|
||||
* Announce route addition/removal.
|
||||
* Users of this function MUST validate input data BEFORE calling.
|
||||
* However we have to be able to handle invalid data:
|
||||
* if some userland app sends us "invalid" route message (invalid mask,
|
||||
* no dst, wrong address families, etc...) we need to pass it back
|
||||
* to app (and any other rtsock consumers) with rtm_errno field set to
|
||||
* non-zero value.
|
||||
* Announce kernel-originated route addition/removal to rtsock based on @rt data.
|
||||
* cmd: RTM_ cmd
|
||||
* @rt: valid rtentry
|
||||
* @ifp: target route interface
|
||||
* @fibnum: fib id or RT_ALL_FIBS
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
rt_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
|
||||
rt_routemsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int rti_addrs,
|
||||
int fibnum)
|
||||
{
|
||||
|
||||
@ -2255,23 +2254,39 @@ rt_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
|
||||
|
||||
KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__));
|
||||
|
||||
return (rtsock_routemsg(cmd, ifp, error, rt, fibnum));
|
||||
return (rtsock_routemsg(cmd, rt, ifp, 0, fibnum));
|
||||
}
|
||||
|
||||
void
|
||||
rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
|
||||
/*
|
||||
* Announce kernel-originated route addition/removal to rtsock based on @rt data.
|
||||
* cmd: RTM_ cmd
|
||||
* @info: addrinfo structure with valid data.
|
||||
* @fibnum: fib id or RT_ALL_FIBS
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum)
|
||||
{
|
||||
|
||||
rt_newaddrmsg_fib(cmd, ifa, error, rt, RT_ALL_FIBS);
|
||||
KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE,
|
||||
("unexpected cmd %d", cmd));
|
||||
|
||||
KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
|
||||
("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
|
||||
|
||||
KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__));
|
||||
|
||||
return (rtsock_routemsg_info(cmd, info, fibnum));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is called to generate messages from the routing socket
|
||||
* indicating a network interface has had addresses associated with it.
|
||||
*/
|
||||
void
|
||||
rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
|
||||
int fibnum)
|
||||
rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, struct rtentry *rt, int fibnum)
|
||||
{
|
||||
|
||||
KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
|
||||
@ -2282,10 +2297,10 @@ rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
|
||||
if (cmd == RTM_ADD) {
|
||||
rt_addrmsg(cmd, ifa, fibnum);
|
||||
if (rt != NULL)
|
||||
rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
|
||||
rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum);
|
||||
} else {
|
||||
if (rt != NULL)
|
||||
rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
|
||||
rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum);
|
||||
rt_addrmsg(cmd, ifa, fibnum);
|
||||
}
|
||||
}
|
||||
|
@ -448,10 +448,10 @@ void rt_ifannouncemsg(struct ifnet *, int);
|
||||
void rt_ifmsg(struct ifnet *);
|
||||
void rt_missmsg(int, struct rt_addrinfo *, int, int);
|
||||
void rt_missmsg_fib(int, struct rt_addrinfo *, int, int, int);
|
||||
void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *);
|
||||
void rt_newaddrmsg_fib(int, struct ifaddr *, int, struct rtentry *, int);
|
||||
void rt_newaddrmsg_fib(int, struct ifaddr *, struct rtentry *, int);
|
||||
int rt_addrmsg(int, struct ifaddr *, int);
|
||||
int rt_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
|
||||
int rt_routemsg(int, struct rtentry *, struct ifnet *ifp, int, int);
|
||||
int rt_routemsg_info(int, struct rt_addrinfo *, int);
|
||||
void rt_newmaddrmsg(int, struct ifmultiaddr *);
|
||||
int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *);
|
||||
void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *);
|
||||
@ -460,7 +460,8 @@ void rt_table_destroy(struct rib_head *);
|
||||
u_int rt_tables_get_gen(int table, int fam);
|
||||
|
||||
int rtsock_addrmsg(int, struct ifaddr *, int);
|
||||
int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
|
||||
int rtsock_routemsg(int, struct rtentry *, struct ifnet *ifp, int, int);
|
||||
int rtsock_routemsg_info(int, struct rt_addrinfo *, int);
|
||||
|
||||
/*
|
||||
* Note the following locking behavior:
|
||||
|
@ -1450,7 +1450,7 @@ rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
|
||||
info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
|
||||
info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
|
||||
info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(
|
||||
info.rti_info[RTAX_IFP], ifa->ifa_netmask, &ss);
|
||||
info.rti_info[RTAX_IFA], ifa->ifa_netmask, &ss);
|
||||
info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
|
||||
if ((m = rtsock_msg_mbuf(ncmd, &info)) == NULL)
|
||||
return (ENOBUFS);
|
||||
@ -1471,46 +1471,69 @@ rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
|
||||
}
|
||||
|
||||
/*
|
||||
* Announce route addition/removal.
|
||||
* Please do not call directly, use rt_routemsg().
|
||||
* Note that @rt data MAY be inconsistent/invalid:
|
||||
* if some userland app sends us "invalid" route message (invalid mask,
|
||||
* no dst, wrong address families, etc...) we need to pass it back
|
||||
* to app (and any other rtsock consumers) with rtm_errno field set to
|
||||
* non-zero value.
|
||||
* Announce route addition/removal to rtsock based on @rt data.
|
||||
* Callers are advives to use rt_routemsg() instead of using this
|
||||
* function directly.
|
||||
* Assume @rt data is consistent.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
rtsock_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
|
||||
rtsock_routemsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int rti_addrs,
|
||||
int fibnum)
|
||||
{
|
||||
struct rt_addrinfo info;
|
||||
struct sockaddr *sa;
|
||||
struct mbuf *m;
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr_storage ss;
|
||||
struct rt_addrinfo info;
|
||||
|
||||
if (V_route_cb.any_count == 0)
|
||||
return (0);
|
||||
|
||||
bzero((caddr_t)&info, sizeof(info));
|
||||
info.rti_info[RTAX_DST] = sa = rt_key(rt);
|
||||
info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(sa, rt_mask(rt), &ss);
|
||||
info.rti_info[RTAX_DST] = rt_key(rt);
|
||||
info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt), rt_mask(rt), &ss);
|
||||
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
|
||||
if ((m = rtsock_msg_mbuf(cmd, &info)) == NULL)
|
||||
info.rti_flags = rt->rt_flags;
|
||||
info.rti_ifp = ifp;
|
||||
|
||||
return (rtsock_routemsg_info(cmd, &info, fibnum));
|
||||
}
|
||||
|
||||
int
|
||||
rtsock_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum)
|
||||
{
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr *sa;
|
||||
struct mbuf *m;
|
||||
|
||||
if (V_route_cb.any_count == 0)
|
||||
return (0);
|
||||
|
||||
if (info->rti_flags & RTF_HOST)
|
||||
info->rti_info[RTAX_NETMASK] = NULL;
|
||||
|
||||
m = rtsock_msg_mbuf(cmd, info);
|
||||
if (m == NULL)
|
||||
return (ENOBUFS);
|
||||
rtm = mtod(m, struct rt_msghdr *);
|
||||
rtm->rtm_index = ifp->if_index;
|
||||
rtm->rtm_flags |= rt->rt_flags;
|
||||
rtm->rtm_errno = error;
|
||||
rtm->rtm_addrs = info.rti_addrs;
|
||||
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: fibnum out "
|
||||
"of range 0 <= %d < %d", __func__, fibnum, rt_numfibs));
|
||||
M_SETFIB(m, fibnum);
|
||||
m->m_flags |= RTS_FILTER_FIB;
|
||||
}
|
||||
|
||||
rtm = mtod(m, struct rt_msghdr *);
|
||||
rtm->rtm_addrs = info->rti_addrs;
|
||||
if (info->rti_ifp != NULL)
|
||||
rtm->rtm_index = info->rti_ifp->if_index;
|
||||
/* Add RTF_DONE to indicate command 'completion' required by API */
|
||||
info->rti_flags |= RTF_DONE;
|
||||
/* Reported routes has to be up */
|
||||
if (cmd == RTM_ADD || cmd == RTM_CHANGE)
|
||||
info->rti_flags |= RTF_UP;
|
||||
rtm->rtm_flags = info->rti_flags;
|
||||
|
||||
sa = info->rti_info[RTAX_DST];
|
||||
rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
|
||||
|
||||
return (0);
|
||||
|
@ -168,30 +168,35 @@ static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *,
|
||||
void
|
||||
in6_newaddrmsg(struct in6_ifaddr *ia, int cmd)
|
||||
{
|
||||
struct rt_addrinfo info;
|
||||
struct ifaddr *ifa;
|
||||
struct sockaddr_dl gateway;
|
||||
struct sockaddr_in6 mask, addr;
|
||||
struct rtentry rt;
|
||||
int fibnum;
|
||||
|
||||
/*
|
||||
* initialize for rtmsg generation
|
||||
*/
|
||||
bzero(&gateway, sizeof(gateway));
|
||||
gateway.sdl_len = sizeof(gateway);
|
||||
gateway.sdl_family = AF_LINK;
|
||||
ifa = &ia->ia_ifa;
|
||||
|
||||
/*
|
||||
* Prepare info data for the host route.
|
||||
* This code mimics one from ifa_maintain_loopback_route().
|
||||
*/
|
||||
bzero(&info, sizeof(struct rt_addrinfo));
|
||||
info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC | RTF_PINNED;
|
||||
info.rti_info[RTAX_DST] = ifa->ifa_addr;
|
||||
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gateway;
|
||||
link_init_sdl(ifa->ifa_ifp, (struct sockaddr *)&gateway, ifa->ifa_ifp->if_type);
|
||||
if (cmd != RTM_DELETE)
|
||||
info.rti_ifp = V_loif;
|
||||
|
||||
|
||||
bzero(&rt, sizeof(rt));
|
||||
rt.rt_gateway = (struct sockaddr *)&gateway;
|
||||
memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
|
||||
memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
|
||||
rt_mask(&rt) = (struct sockaddr *)&mask;
|
||||
rt_key(&rt) = (struct sockaddr *)&addr;
|
||||
rt.rt_flags = RTF_HOST | RTF_STATIC;
|
||||
if (cmd == RTM_ADD)
|
||||
rt.rt_flags |= RTF_UP;
|
||||
fibnum = V_rt_add_addr_allfibs ? RT_ALL_FIBS : ia62ifa(ia)->ifa_ifp->if_fib;
|
||||
/* Announce arrival of local address to this FIB. */
|
||||
rt_newaddrmsg_fib(cmd, &ia->ia_ifa, 0, &rt, fibnum);
|
||||
|
||||
if (cmd == RTM_ADD) {
|
||||
rt_addrmsg(cmd, &ia->ia_ifa, fibnum);
|
||||
rt_routemsg_info(cmd, &info, fibnum);
|
||||
} else if (cmd == RTM_DELETE) {
|
||||
rt_routemsg_info(cmd, &info, fibnum);
|
||||
rt_addrmsg(cmd, &ia->ia_ifa, fibnum);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -609,30 +609,8 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
|
||||
static void
|
||||
nd6_rtmsg(int cmd, struct rtentry *rt)
|
||||
{
|
||||
struct rt_addrinfo info;
|
||||
struct ifnet *ifp;
|
||||
struct ifaddr *ifa;
|
||||
|
||||
bzero((caddr_t)&info, sizeof(info));
|
||||
info.rti_info[RTAX_DST] = rt_key(rt);
|
||||
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
|
||||
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
|
||||
ifp = rt->rt_ifp;
|
||||
if (ifp != NULL) {
|
||||
struct epoch_tracker et;
|
||||
|
||||
NET_EPOCH_ENTER(et);
|
||||
ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
|
||||
info.rti_info[RTAX_IFP] = ifa->ifa_addr;
|
||||
ifa_ref(ifa);
|
||||
NET_EPOCH_EXIT(et);
|
||||
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
||||
} else
|
||||
ifa = NULL;
|
||||
|
||||
rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum);
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
rt_routemsg(cmd, rt, rt->rt_ifp, 0, rt->rt_fibnum);
|
||||
}
|
||||
|
||||
/* PFXRTR */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
@ -51,24 +67,38 @@ presetup_ipv6(const atf_tc_t *tc)
|
||||
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 = config_setup(tc);
|
||||
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");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user