This is xnu-11215.1.10. See this file in:
/*
* Copyright (c) 2017-2024 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#include <TargetConditionals.h>
#include <arpa/inet.h>
#include <assert.h>
#include <err.h>
#include <net/if_utun.h>
#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <sys/event.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/kern_control.h>
#include <sys/sys_domain.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <darwintest.h>
#include "skywalk_test_common.h"
#include "skywalk_test_driver.h"
#include "skywalk_test_utils.h"
#define NX_PORT 3
#define BUF_SIZE 8192
#define MAX_FRAMES 8
typedef size_t (*reass_packet_builder_fn)(uint8_t *buf);
typedef int (*reass_packet_matcher_fn)(uint8_t *pkt_out, size_t len_out,
uint8_t *pkt_in, size_t len_in);
static int utun_fd;
static struct sktc_nexus_handles nexus;
static channel_port port;
static char utun_ifname[IFNAMSIZ + 1];
// to select one of the following global/linklocal addr
static char *utun_addr_str = NULL;
static char *peer_addr_str = NULL;
static char *our_ip_str = "192.168.255.2";
static char *dst_ip_str = "10.0.0.1";
static char *broad_ip_str = "192.168.255.255";
static char *utun_global_addr_str = "2607:1111::1111";
static char *peer_global_addr_str = "2607:2222::2222";
static char *utun_linklocal_addr_str = "fe80::1111";
static char *peer_linklocal_addr_str = "fe80::2222";
static int addr_prefix_length = 128; // 128 for POINTOPOINT UTUN
struct timeval timeout = {
.tv_sec = 10,
.tv_usec = 0,
};
static void
die_perror(const char *str)
{
perror(str);
assert(0);
}
void
reass_init()
{
int error;
utun_fd = sktu_create_interface(SKTU_IFT_UTUN, SKTU_IFF_ENABLE_NETIF);
sktu_get_interface_name(SKTU_IFT_UTUN, utun_fd, utun_ifname);
error = fcntl(utun_fd, F_SETFD, FD_CLOEXEC);
if (error != 0) {
die_perror("FD_CLOEXEC");
}
struct in6_addr utun_addr, dst_addr;
inet_pton(AF_INET6, utun_addr_str, &utun_addr);
inet_pton(AF_INET6, peer_addr_str, &dst_addr);
error = sktc_ifnet_add_addr6(utun_ifname, &utun_addr, &dst_addr,
addr_prefix_length, 0);
assert(error == 0);
}
void
reass_fini(void)
{
close(utun_fd);
}
void
reass_interface_send(reass_packet_builder_fn builder)
{
uint8_t pkt_in[BUF_SIZE];
size_t len_in = builder(pkt_in);
T_LOG("sending to utun, len %ld\n", len_in);
sktu_dump_buffer(stderr, NULL, pkt_in, len_in);
int i = 0;
while (i++ < 1000) {
write(utun_fd, pkt_in, len_in);
}
}
void
reass_interface_send_rece(reass_packet_builder_fn builder,
reass_packet_matcher_fn matcher, struct timeval *allowed)
{
struct timeval start, now, elapsed, left;
fd_set readfds, errorfds;
uint8_t pkt_in[BUF_SIZE];
uint8_t pkt_out[BUF_SIZE];
size_t len_in, len_out;
int retval;
len_in = builder(pkt_in);
T_LOG("sending to utun, len %ld\n", len_in);
sktu_dump_buffer(stderr, NULL, pkt_in, len_in);
write(utun_fd, pkt_in, len_in);
if (gettimeofday(&start, NULL) != 0) {
die_perror("gettimeofday");
}
left = *allowed;
while (1) {
FD_ZERO(&readfds);
FD_ZERO(&errorfds);
FD_SET(utun_fd, &readfds);
FD_SET(utun_fd, &errorfds);
retval = select(utun_fd + 1, &readfds, NULL, &errorfds, &left);
if (retval == -1) {
die_perror("select()");
}
if (!FD_ISSET(utun_fd, &readfds) && retval == 0) { // timeout
T_LOG("recv timeout\n");
assert(0);
}
assert(!FD_ISSET(utun_fd, &errorfds));
assert(retval == 1);
if (FD_ISSET(utun_fd, &readfds)) {
len_out = read(utun_fd, pkt_out, BUF_SIZE);
if (len_out < 1) {
T_LOG("utun read error\n");
assert(0);
}
}
T_LOG("read from utun, len %ld\n", len_out);
sktu_dump_buffer(stderr, NULL, pkt_out, len_out);
if (matcher(pkt_out, len_out, pkt_in, len_in) == 0) {
break;
}
if (gettimeofday(&now, NULL) != 0) {
die_perror("gettimeofday");
}
timersub(&now, &start, &elapsed);
timersub(allowed, &elapsed, &left);
}
}
void
reass_common(channel_port *ch_port, struct sktu_flow *flow, void *data,
size_t data_len)
{
struct sktu_frame *rx_frames[MAX_FRAMES];
struct sktu_frame *tx_frames[MAX_FRAMES];
size_t n_rx_frames;
size_t n_tx_frames;
n_tx_frames = flow->create_input_frames(flow, tx_frames, MAX_FRAMES,
data, data_len);
sktu_utun_fd_tx_burst(utun_fd, tx_frames, n_tx_frames);
n_rx_frames = sktu_channel_port_rx_burst(ch_port, rx_frames, MAX_FRAMES);
// verify rx_frames == tx_frames
assert(n_rx_frames == n_tx_frames);
assert(rx_frames[0]->len == tx_frames[0]->len);
assert(memcmp(rx_frames[0]->bytes, tx_frames[0]->bytes,
tx_frames[0]->len) == 0);
assert(rx_frames[1]->len == tx_frames[1]->len);
assert(memcmp(rx_frames[1]->bytes, tx_frames[1]->bytes,
tx_frames[1]->len) == 0);
sktu_frames_free(rx_frames, n_rx_frames);
sktu_frames_free(tx_frames, n_tx_frames);
}
size_t
bad_fraglen_build(uint8_t *buf)
{
size_t i, len = 0;
size_t plen = 35;
uint32_t address_family = htonl(AF_INET6);
bcopy(&address_family, buf, sizeof(uint32_t));
buf += sizeof(uint32_t);
len += sizeof(uint32_t);
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
ip6->ip6_vfc = IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_FRAGMENT;
ip6->ip6_hlim = IPV6_DEFHLIM;
ip6->ip6_plen = htons(sizeof(struct ip6_frag) + plen);
inet_pton(AF_INET6, utun_addr_str, &ip6->ip6_dst);
inet_pton(AF_INET6, peer_addr_str, &ip6->ip6_src);
buf += sizeof(struct ip6_hdr);
len += sizeof(struct ip6_hdr);
struct ip6_frag *ip6f = (struct ip6_frag *)buf;
ip6f->ip6f_ident = 0xee;
ip6f->ip6f_nxt = IPPROTO_UDP;
ip6f->ip6f_offlg = 0;
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
buf += sizeof(struct ip6_frag);
len += sizeof(struct ip6_frag);
for (i = 0; i < plen; i++) {
buf[i] = 'f';
}
buf += plen;
len += plen;
return len;
}
int
bad_fraglen_match(uint8_t *pkt_out, size_t len_out, uint8_t *pkt_in, size_t len_in)
{
uint8_t *scan = pkt_out;
uint32_t af = ntohl(*(uint32_t *)pkt_out);
if (af != AF_INET6) {
T_LOG("%s fails: af != AF_INET6", __func__);
return -1;
}
scan += sizeof(af);
struct ip6_hdr *ip6 = (struct ip6_hdr *)scan;
//TODO check src/dst, etc.
if (ip6->ip6_nxt != IPPROTO_ICMPV6) {
T_LOG("%s fails: ip6_nxt != IPPROTO_ICMPV6", __func__);
return -1;
}
scan += sizeof(struct ip6_hdr);
struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)scan;
assert(icmp6->icmp6_type == ICMP6_PARAM_PROB);
assert(icmp6->icmp6_code == ICMP6_PARAMPROB_HEADER);
assert(icmp6->icmp6_pptr == htonl(__builtin_offsetof(struct ip6_hdr,
ip6_plen)));
return 0;
}
size_t
timeout_build(uint8_t *buf)
{
size_t i, len = 0;
size_t plen = 128;
uint32_t address_family = htonl(AF_INET6);
bcopy(&address_family, buf, sizeof(uint32_t));
buf += sizeof(uint32_t);
len += sizeof(uint32_t);
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
ip6->ip6_vfc = IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_FRAGMENT;
ip6->ip6_hlim = IPV6_DEFHLIM;
ip6->ip6_plen = htons(sizeof(struct ip6_frag) + plen);
inet_pton(AF_INET6, utun_addr_str, &ip6->ip6_dst);
inet_pton(AF_INET6, peer_addr_str, &ip6->ip6_src);
buf += sizeof(struct ip6_hdr);
len += sizeof(struct ip6_hdr);
struct ip6_frag *ip6f = (struct ip6_frag *)buf;
ip6f->ip6f_ident = 0xee;
ip6f->ip6f_nxt = IPPROTO_UDP;
ip6f->ip6f_offlg = 0;
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
buf += sizeof(struct ip6_frag);
len += sizeof(struct ip6_frag);
for (i = 0; i < plen; i++) {
buf[i] = 'f';
}
buf += plen;
len += plen;
return len;
}
int
timeout_match(uint8_t *pkt_out, size_t len_out, uint8_t *pkt_in, size_t len_in)
{
uint8_t *scan = pkt_out;
uint32_t af = ntohl(*(uint32_t *)pkt_out);
if (af != AF_INET6) {
T_LOG("%s fails: af != AF_INET6", __func__);
return -1;
}
scan += sizeof(af);
struct ip6_hdr *ip6 = (struct ip6_hdr *)scan;
//TODO check src/dst, etc.
if (ip6->ip6_nxt != IPPROTO_ICMPV6) {
T_LOG("%s fails: ip6_nxt != IPPROTO_ICMPV6", __func__);
return -1;
}
scan += sizeof(struct ip6_hdr);
struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)scan;
assert(icmp6->icmp6_type == ICMP6_TIME_EXCEEDED);
assert(icmp6->icmp6_code == ICMP6_TIME_EXCEED_REASSEMBLY);
assert(icmp6->icmp6_pptr == 0);
return 0;
}
#define ADDCARRY(_x) do { \
while (((_x) >> 16) != 0) \
(_x) = ((_x) >> 16) + ((_x) & 0xffff); \
} while (0)
size_t
atomic_build(uint8_t *buf)
{
size_t i, len = 0;
size_t plen, dlen = 16;
struct in6_addr src, dst;
uint32_t address_family = htonl(AF_INET6);
bzero(buf, BUF_SIZE);
bcopy(&address_family, buf, sizeof(uint32_t));
buf += sizeof(uint32_t);
len += sizeof(uint32_t);
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
ip6->ip6_vfc = IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_FRAGMENT;
ip6->ip6_hlim = IPV6_DEFHLIM;
plen = sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr) + dlen;
ip6->ip6_plen = htons(plen);
inet_pton(AF_INET6, peer_addr_str, &src);
bcopy(&src, &ip6->ip6_src, sizeof(src));
inet_pton(AF_INET6, utun_addr_str, &dst);
bcopy(&dst, &ip6->ip6_dst, sizeof(dst));
buf += sizeof(struct ip6_hdr);
len += sizeof(struct ip6_hdr);
struct ip6_frag *ip6f = (struct ip6_frag *)buf;
ip6f->ip6f_ident = 0xee;
ip6f->ip6f_nxt = IPPROTO_ICMPV6;
ip6f->ip6f_offlg = 0;
buf += sizeof(struct ip6_frag);
len += sizeof(struct ip6_frag);
struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)buf;
icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
icmp6->icmp6_code = 0;
icmp6->icmp6_cksum = 0;
buf += sizeof(struct icmp6_hdr);
len += sizeof(struct icmp6_hdr);
for (i = 0; i < dlen; i++) {
buf[i] = 'f';
}
uint16_t csum;
icmp6->icmp6_cksum = in6_pseudo(&src, &dst,
htonl(IPPROTO_ICMPV6 + sizeof(struct icmp6_hdr) + dlen));
csum = os_inet_checksum(icmp6, sizeof(struct icmp6_hdr) + dlen, 0);
csum = ~csum;
if (csum == 0) {
csum = 0xffff;
}
icmp6->icmp6_cksum = csum;
buf += dlen;
len += dlen;
return len;
}
int
atomic_match(uint8_t *pkt_out, size_t len_out, uint8_t *pkt_in, size_t len_in)
{
uint8_t *scan = pkt_out;
uint32_t af = ntohl(*(uint32_t *)pkt_out);
if (af != AF_INET6) {
T_LOG("%s fails: af != AF_INET6", __func__);
return -1;
}
scan += sizeof(af);
struct ip6_hdr *ip6 = (struct ip6_hdr *)scan;
//TODO check src/dst, etc.
if (ip6->ip6_nxt != IPPROTO_ICMPV6) {
T_LOG("%s fails: ip6_nxt != IPPROTO_ICMPV6", __func__);
return -1;
}
scan += sizeof(struct ip6_hdr);
struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)scan;
assert(icmp6->icmp6_type == ICMP6_ECHO_REPLY);
assert(icmp6->icmp6_code == 0);
return 0;
}
size_t
queue_limit_build(uint8_t *buf)
{
size_t len = 0;
struct in6_addr src, dst;
uint32_t address_family = htonl(AF_INET6);
bzero(buf, BUF_SIZE);
bcopy(&address_family, buf, sizeof(uint32_t));
buf += sizeof(uint32_t);
len += sizeof(uint32_t);
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
ip6->ip6_vfc = IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_FRAGMENT;
ip6->ip6_hlim = IPV6_DEFHLIM;
ip6->ip6_plen = htons(sizeof(struct ip6_frag));
inet_pton(AF_INET6, peer_addr_str, &src);
bcopy(&src, &ip6->ip6_src, sizeof(src));
inet_pton(AF_INET6, utun_addr_str, &dst);
bcopy(&dst, &ip6->ip6_dst, sizeof(dst));
buf += sizeof(struct ip6_hdr);
len += sizeof(struct ip6_hdr);
struct ip6_frag *ip6f = (struct ip6_frag *)buf;
ip6f->ip6f_ident = 0xee;
ip6f->ip6f_nxt = IPPROTO_NONE;
ip6f->ip6f_offlg = htons((u_short)((2048) & ~7));
buf += sizeof(struct ip6_frag);
len += sizeof(struct ip6_frag);
return len;
}
void
reass_lower_timeout(int *old_timeout, int new_timeout)
{
size_t old_size = sizeof(*old_timeout);
int error;
error = sysctlbyname("kern.skywalk.flowswitch.ipfm_frag_ttl",
old_timeout, &old_size, &new_timeout, sizeof(int));
if (error) {
die_perror("kern.skywalk.flowswitch.ipfm_frag_ttl");
}
}
void
reass_restore_timeout(int old_timeout)
{
int error;
error = sysctlbyname("kern.skywalk.flowswitch.ipfm_frag_ttl",
NULL, NULL, &old_timeout, sizeof(int));
if (error) {
die_perror("kern.skywalk.flowswitch.ipfm_frag_ttl");
}
}
int
skt_reass_main(int argc, char *argv[])
{
int error;
// setup full interface
utun_fd = sktu_create_interface(SKTU_IFT_UTUN,
SKTU_IFF_ENABLE_NETIF | SKTU_IFF_NO_ATTACH_FSW);
sktu_get_interface_name(SKTU_IFT_UTUN, utun_fd, utun_ifname);
struct in_addr our_ip, mask, broad_ip, dst_ip;
struct in6_addr our_ip_v6, dst_ip_v6;
inet_pton(AF_INET, our_ip_str, &our_ip);
inet_pton(AF_INET, dst_ip_str, &dst_ip);
inet_pton(AF_INET, broad_ip_str, &broad_ip);
mask = sktc_make_in_addr(IN_CLASSC_NET);
sktc_config_fsw_rx_agg_tcp(0);
if (sktc_ifnet_add_addr(utun_ifname, &our_ip, &mask, &broad_ip) != 0) {
err(EX_OSERR, "Failed to add address for %s", utun_ifname);
}
inet_pton(AF_INET6, utun_global_addr_str, &our_ip_v6);
inet_pton(AF_INET6, peer_global_addr_str, &dst_ip_v6);
error = sktc_ifnet_add_addr6(utun_ifname, &our_ip_v6, &dst_ip_v6,
addr_prefix_length, 0);
if (sktc_ifnet_add_scoped_default_route(utun_ifname, our_ip) != 0) {
err(EX_OSERR, "Failed to add default route: %s\n", utun_ifname);
}
bzero(&nexus, sizeof(nexus));
strlcpy(nexus.netif_ifname, utun_ifname, sizeof(nexus.netif_ifname));
nexus.netif_addr = our_ip;
nexus.netif_mask = mask;
sktc_create_flowswitch_no_address(&nexus, -1, -1, -1, -1, 0);
error = os_nexus_controller_bind_provider_instance(nexus.controller,
nexus.fsw_nx_uuid, NX_PORT, getpid(), NULL, NULL, 0,
NEXUS_BIND_PID);
SKTC_ASSERT_ERR(error == 0);
struct sktu_flow *flow_ipv4, *flow_ipv6;
flow_ipv4 = sktu_create_nexus_flow_with_nx_port(&nexus, NX_PORT,
AF_INET, &our_ip, &dst_ip, IPPROTO_UDP, 0, 1234);
assert(flow_ipv4);
flow_ipv6 = sktu_create_nexus_flow_with_nx_port(&nexus, NX_PORT,
AF_INET6, &our_ip_v6, &dst_ip_v6, IPPROTO_UDP, 0, 1234);
assert(flow_ipv4);
assert(flow_ipv4->nfr.nfr_nx_port == flow_ipv6->nfr.nfr_nx_port);
sktu_channel_port_init(&port, nexus.fsw_nx_uuid,
flow_ipv4->nfr.nfr_nx_port, true, false, false);
assert(port.chan != NULL);
uint8_t buf[8192];
// test both 8-byte-multiple and non 8-byte-multple sizes
reass_common(&port, flow_ipv4, buf, 2000);
reass_common(&port, flow_ipv4, buf, 2001);
reass_common(&port, flow_ipv4, buf, 8000);
reass_common(&port, flow_ipv4, buf, 8001);
reass_common(&port, flow_ipv6, buf, 2000);
reass_common(&port, flow_ipv6, buf, 2001);
reass_common(&port, flow_ipv6, buf, 8000);
reass_common(&port, flow_ipv6, buf, 8001);
sktu_destroy_nexus_flow(flow_ipv4);
sktu_destroy_nexus_flow(flow_ipv6);
reass_fini();
return 0;
}
int
skt_reass_main_default_setting(int argc, char *argv[])
{
if (!sktc_is_netagent_enabled()) {
T_LOG("netagent not enabled on this platform, skip\n");
return 0;
}
if (!sktc_is_ip_reass_enabled()) {
T_LOG("ip reass not enabled on this platform, skip\n");
return 0;
}
return skt_reass_main(argc, argv);
}
#define REASS_TEST_GLOBAL(builder, matcher, timeout) \
utun_addr_str = utun_global_addr_str; \
peer_addr_str = peer_global_addr_str; \
reass_init(); \
reass_interface_send_rece(builder, matcher, &timeout); \
reass_fini();
#define REASS_TEST_LINKLOCAL(builder, matcher, timeout) \
utun_addr_str = utun_linklocal_addr_str; \
peer_addr_str = peer_linklocal_addr_str; \
reass_init(); \
reass_interface_send_rece(builder, matcher, &timeout); \
reass_fini();
#define REASS_TEST_ALL(builder, matcher, timeout) \
REASS_TEST_GLOBAL(builder, matcher, timeout) \
sleep(1); \
REASS_TEST_LINKLOCAL(builder, matcher, timeout)
#define REASS_FUZZ_GLOBAL(builder) \
utun_addr_str = utun_global_addr_str; \
peer_addr_str = peer_global_addr_str; \
reass_init(); \
reass_interface_send(builder); \
reass_fini();
#define REASS_FUZZ_LINKLOCAL(builder) \
utun_addr_str = utun_linklocal_addr_str; \
peer_addr_str = peer_linklocal_addr_str; \
reass_init(); \
reass_interface_send(builder); \
reass_fini();
#define REASS_FUZZ_ALL(builder) \
REASS_FUZZ_GLOBAL(builder) \
sleep(1); \
REASS_FUZZ_LINKLOCAL(builder)
int
skt_reass_timeout_main(int argc, char *argv[])
{
int old_timeout;
int new_timeout = 5;
reass_lower_timeout(&old_timeout, new_timeout);
REASS_TEST_ALL(timeout_build, timeout_match, timeout);
reass_restore_timeout(old_timeout);
return 0;
}
int
skt_reass_bad_fraglen_main(int argc, char *argv[])
{
REASS_TEST_ALL(bad_fraglen_build, bad_fraglen_match, timeout);
return 0;
}
int
skt_reass_atomic_main(int argc, char *argv[])
{
REASS_TEST_ALL(atomic_build, atomic_match, timeout);
return 0;
}
int
skt_reass_fuzz_queue_limit_main(int argc, char *argv[])
{
REASS_FUZZ_ALL(queue_limit_build);
return 0;
}
struct skywalk_test skt_reass_default_setting = {
"reass_default_setting",
"UDP fragmentation reassembly (channel flow Rx) (without forcing ip_reass sysctl)",
SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
skt_reass_main_default_setting, { NULL },
NULL, NULL,
};
struct skywalk_test skt_reass = {
"reass",
"UDP fragmentation reassembly (channel flow Rx)",
SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
skt_reass_main, { NULL },
sktc_enable_ip_reass, sktc_restore_ip_reass,
};
struct skywalk_test skt_reass_timeout = {
"reass_timeout",
"send partial fragment to flowswitch and check for ICMPv6 time exceeded reply",
SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
skt_reass_timeout_main, { NULL },
sktc_enable_ip_reass, sktc_restore_ip_reass,
};
struct skywalk_test skt_reass_bad_fraglen = {
"reass_bad_fraglen",
"send fragment with bad fragment length (!= 8*) to flowswitch and check for ICMPv6 param header reply",
SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
skt_reass_bad_fraglen_main, { NULL },
sktc_enable_ip_reass, sktc_restore_ip_reass,
};
struct skywalk_test skt_reass_atomic = {
"reass_atomic",
"send atomic ICMP echo fragment to flowswitch and check for reply",
SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
skt_reass_atomic_main, { NULL },
sktc_enable_ip_reass, sktc_restore_ip_reass,
};
struct skywalk_test skt_reass_fuzz_queue_limit = {
"reass_fuzz_queue_limit",
"fuzz flowswitch to hit fragment limit",
SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
skt_reass_fuzz_queue_limit_main, { NULL },
sktc_enable_ip_reass, sktc_restore_ip_reass,
};