1 /*
2 * Copyright (c) 2017-2024 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <TargetConditionals.h>
30 #include <arpa/inet.h>
31 #include <assert.h>
32 #include <err.h>
33 #include <net/if_utun.h>
34 #include <netinet/icmp6.h>
35 #include <netinet/in.h>
36 #include <netinet/in.h>
37 #include <netinet/ip.h>
38 #include <netinet/ip6.h>
39 #include <netinet/tcp.h>
40 #include <netinet/udp.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sysexits.h>
45 #include <sys/event.h>
46 #include <sys/fcntl.h>
47 #include <sys/ioctl.h>
48 #include <sys/kern_control.h>
49 #include <sys/sys_domain.h>
50 #include <sys/sysctl.h>
51 #include <sys/time.h>
52 #include <unistd.h>
53 #include <darwintest.h>
54
55 #include "skywalk_test_common.h"
56 #include "skywalk_test_driver.h"
57 #include "skywalk_test_utils.h"
58
59 #define NX_PORT 3
60 #define BUF_SIZE 8192
61 #define MAX_FRAMES 8
62
63 typedef size_t (*reass_packet_builder_fn)(uint8_t *buf);
64 typedef int (*reass_packet_matcher_fn)(uint8_t *pkt_out, size_t len_out,
65 uint8_t *pkt_in, size_t len_in);
66
67 static int utun_fd;
68 static struct sktc_nexus_handles nexus;
69 static channel_port port;
70
71 static char utun_ifname[IFNAMSIZ + 1];
72
73 // to select one of the following global/linklocal addr
74 static char *utun_addr_str = NULL;
75 static char *peer_addr_str = NULL;
76
77 static char *our_ip_str = "192.168.255.2";
78 static char *dst_ip_str = "10.0.0.1";
79 static char *broad_ip_str = "192.168.255.255";
80
81 static char *utun_global_addr_str = "2607:1111::1111";
82 static char *peer_global_addr_str = "2607:2222::2222";
83
84 static char *utun_linklocal_addr_str = "fe80::1111";
85 static char *peer_linklocal_addr_str = "fe80::2222";
86
87 static int addr_prefix_length = 128; // 128 for POINTOPOINT UTUN
88
89 struct timeval timeout = {
90 .tv_sec = 10,
91 .tv_usec = 0,
92 };
93
94 static void
die_perror(const char * str)95 die_perror(const char *str)
96 {
97 perror(str);
98 assert(0);
99 }
100
101 void
reass_init()102 reass_init()
103 {
104 int error;
105
106 utun_fd = sktu_create_interface(SKTU_IFT_UTUN, SKTU_IFF_ENABLE_NETIF);
107
108 sktu_get_interface_name(SKTU_IFT_UTUN, utun_fd, utun_ifname);
109
110 error = fcntl(utun_fd, F_SETFD, FD_CLOEXEC);
111 if (error != 0) {
112 die_perror("FD_CLOEXEC");
113 }
114
115 struct in6_addr utun_addr, dst_addr;
116 inet_pton(AF_INET6, utun_addr_str, &utun_addr);
117 inet_pton(AF_INET6, peer_addr_str, &dst_addr);
118 error = sktc_ifnet_add_addr6(utun_ifname, &utun_addr, &dst_addr,
119 addr_prefix_length, 0);
120 assert(error == 0);
121 }
122
123 void
reass_fini(void)124 reass_fini(void)
125 {
126 close(utun_fd);
127 }
128
129 void
reass_interface_send(reass_packet_builder_fn builder)130 reass_interface_send(reass_packet_builder_fn builder)
131 {
132 uint8_t pkt_in[BUF_SIZE];
133
134 size_t len_in = builder(pkt_in);
135
136 T_LOG("sending to utun, len %ld\n", len_in);
137 sktu_dump_buffer(stderr, NULL, pkt_in, len_in);
138 int i = 0;
139 while (i++ < 1000) {
140 write(utun_fd, pkt_in, len_in);
141 }
142 }
143
144 void
reass_interface_send_rece(reass_packet_builder_fn builder,reass_packet_matcher_fn matcher,struct timeval * allowed)145 reass_interface_send_rece(reass_packet_builder_fn builder,
146 reass_packet_matcher_fn matcher, struct timeval *allowed)
147 {
148 struct timeval start, now, elapsed, left;
149 fd_set readfds, errorfds;
150 uint8_t pkt_in[BUF_SIZE];
151 uint8_t pkt_out[BUF_SIZE];
152 size_t len_in, len_out;
153 int retval;
154
155 len_in = builder(pkt_in);
156
157 T_LOG("sending to utun, len %ld\n", len_in);
158 sktu_dump_buffer(stderr, NULL, pkt_in, len_in);
159 write(utun_fd, pkt_in, len_in);
160
161 if (gettimeofday(&start, NULL) != 0) {
162 die_perror("gettimeofday");
163 }
164 left = *allowed;
165
166 while (1) {
167 FD_ZERO(&readfds);
168 FD_ZERO(&errorfds);
169 FD_SET(utun_fd, &readfds);
170 FD_SET(utun_fd, &errorfds);
171
172 retval = select(utun_fd + 1, &readfds, NULL, &errorfds, &left);
173 if (retval == -1) {
174 die_perror("select()");
175 }
176
177 if (!FD_ISSET(utun_fd, &readfds) && retval == 0) { // timeout
178 T_LOG("recv timeout\n");
179 assert(0);
180 }
181
182 assert(!FD_ISSET(utun_fd, &errorfds));
183 assert(retval == 1);
184
185 if (FD_ISSET(utun_fd, &readfds)) {
186 len_out = read(utun_fd, pkt_out, BUF_SIZE);
187 if (len_out < 1) {
188 T_LOG("utun read error\n");
189 assert(0);
190 }
191 }
192
193 T_LOG("read from utun, len %ld\n", len_out);
194 sktu_dump_buffer(stderr, NULL, pkt_out, len_out);
195
196 if (matcher(pkt_out, len_out, pkt_in, len_in) == 0) {
197 break;
198 }
199
200 if (gettimeofday(&now, NULL) != 0) {
201 die_perror("gettimeofday");
202 }
203
204 timersub(&now, &start, &elapsed);
205 timersub(allowed, &elapsed, &left);
206 }
207 }
208
209 void
reass_common(channel_port * ch_port,struct sktu_flow * flow,void * data,size_t data_len)210 reass_common(channel_port *ch_port, struct sktu_flow *flow, void *data,
211 size_t data_len)
212 {
213 struct sktu_frame *rx_frames[MAX_FRAMES];
214 struct sktu_frame *tx_frames[MAX_FRAMES];
215 size_t n_rx_frames;
216 size_t n_tx_frames;
217
218 n_tx_frames = flow->create_input_frames(flow, tx_frames, MAX_FRAMES,
219 data, data_len);
220
221 sktu_utun_fd_tx_burst(utun_fd, tx_frames, n_tx_frames);
222
223 n_rx_frames = sktu_channel_port_rx_burst(ch_port, rx_frames, MAX_FRAMES);
224
225 // verify rx_frames == tx_frames
226 assert(n_rx_frames == n_tx_frames);
227 assert(rx_frames[0]->len == tx_frames[0]->len);
228 assert(memcmp(rx_frames[0]->bytes, tx_frames[0]->bytes,
229 tx_frames[0]->len) == 0);
230 assert(rx_frames[1]->len == tx_frames[1]->len);
231 assert(memcmp(rx_frames[1]->bytes, tx_frames[1]->bytes,
232 tx_frames[1]->len) == 0);
233
234 sktu_frames_free(rx_frames, n_rx_frames);
235 sktu_frames_free(tx_frames, n_tx_frames);
236 }
237
238 size_t
bad_fraglen_build(uint8_t * buf)239 bad_fraglen_build(uint8_t *buf)
240 {
241 size_t i, len = 0;
242 size_t plen = 35;
243 uint32_t address_family = htonl(AF_INET6);
244
245 bcopy(&address_family, buf, sizeof(uint32_t));
246 buf += sizeof(uint32_t);
247 len += sizeof(uint32_t);
248
249 struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
250 ip6->ip6_vfc = IPV6_VERSION;
251 ip6->ip6_nxt = IPPROTO_FRAGMENT;
252 ip6->ip6_hlim = IPV6_DEFHLIM;
253 ip6->ip6_plen = htons(sizeof(struct ip6_frag) + plen);
254
255 inet_pton(AF_INET6, utun_addr_str, &ip6->ip6_dst);
256 inet_pton(AF_INET6, peer_addr_str, &ip6->ip6_src);
257
258 buf += sizeof(struct ip6_hdr);
259 len += sizeof(struct ip6_hdr);
260
261 struct ip6_frag *ip6f = (struct ip6_frag *)buf;
262 ip6f->ip6f_ident = 0xee;
263 ip6f->ip6f_nxt = IPPROTO_UDP;
264 ip6f->ip6f_offlg = 0;
265 ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
266
267 buf += sizeof(struct ip6_frag);
268 len += sizeof(struct ip6_frag);
269
270 for (i = 0; i < plen; i++) {
271 buf[i] = 'f';
272 }
273
274 buf += plen;
275 len += plen;
276
277 return len;
278 }
279
280 int
bad_fraglen_match(uint8_t * pkt_out,size_t len_out,uint8_t * pkt_in,size_t len_in)281 bad_fraglen_match(uint8_t *pkt_out, size_t len_out, uint8_t *pkt_in, size_t len_in)
282 {
283 uint8_t *scan = pkt_out;
284 uint32_t af = ntohl(*(uint32_t *)pkt_out);
285
286 if (af != AF_INET6) {
287 T_LOG("%s fails: af != AF_INET6", __func__);
288 return -1;
289 }
290
291 scan += sizeof(af);
292 struct ip6_hdr *ip6 = (struct ip6_hdr *)scan;
293
294 //TODO check src/dst, etc.
295
296 if (ip6->ip6_nxt != IPPROTO_ICMPV6) {
297 T_LOG("%s fails: ip6_nxt != IPPROTO_ICMPV6", __func__);
298 return -1;
299 }
300
301 scan += sizeof(struct ip6_hdr);
302 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)scan;
303
304 assert(icmp6->icmp6_type == ICMP6_PARAM_PROB);
305 assert(icmp6->icmp6_code == ICMP6_PARAMPROB_HEADER);
306 assert(icmp6->icmp6_pptr == htonl(__builtin_offsetof(struct ip6_hdr,
307 ip6_plen)));
308
309 return 0;
310 }
311
312 size_t
timeout_build(uint8_t * buf)313 timeout_build(uint8_t *buf)
314 {
315 size_t i, len = 0;
316 size_t plen = 128;
317 uint32_t address_family = htonl(AF_INET6);
318
319 bcopy(&address_family, buf, sizeof(uint32_t));
320 buf += sizeof(uint32_t);
321 len += sizeof(uint32_t);
322
323 struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
324 ip6->ip6_vfc = IPV6_VERSION;
325 ip6->ip6_nxt = IPPROTO_FRAGMENT;
326 ip6->ip6_hlim = IPV6_DEFHLIM;
327 ip6->ip6_plen = htons(sizeof(struct ip6_frag) + plen);
328
329 inet_pton(AF_INET6, utun_addr_str, &ip6->ip6_dst);
330 inet_pton(AF_INET6, peer_addr_str, &ip6->ip6_src);
331
332 buf += sizeof(struct ip6_hdr);
333 len += sizeof(struct ip6_hdr);
334
335 struct ip6_frag *ip6f = (struct ip6_frag *)buf;
336 ip6f->ip6f_ident = 0xee;
337 ip6f->ip6f_nxt = IPPROTO_UDP;
338 ip6f->ip6f_offlg = 0;
339 ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
340
341 buf += sizeof(struct ip6_frag);
342 len += sizeof(struct ip6_frag);
343
344 for (i = 0; i < plen; i++) {
345 buf[i] = 'f';
346 }
347
348 buf += plen;
349 len += plen;
350
351 return len;
352 }
353
354 int
timeout_match(uint8_t * pkt_out,size_t len_out,uint8_t * pkt_in,size_t len_in)355 timeout_match(uint8_t *pkt_out, size_t len_out, uint8_t *pkt_in, size_t len_in)
356 {
357 uint8_t *scan = pkt_out;
358 uint32_t af = ntohl(*(uint32_t *)pkt_out);
359
360 if (af != AF_INET6) {
361 T_LOG("%s fails: af != AF_INET6", __func__);
362 return -1;
363 }
364
365 scan += sizeof(af);
366 struct ip6_hdr *ip6 = (struct ip6_hdr *)scan;
367
368 //TODO check src/dst, etc.
369
370 if (ip6->ip6_nxt != IPPROTO_ICMPV6) {
371 T_LOG("%s fails: ip6_nxt != IPPROTO_ICMPV6", __func__);
372 return -1;
373 }
374
375 scan += sizeof(struct ip6_hdr);
376 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)scan;
377
378 assert(icmp6->icmp6_type == ICMP6_TIME_EXCEEDED);
379 assert(icmp6->icmp6_code == ICMP6_TIME_EXCEED_REASSEMBLY);
380 assert(icmp6->icmp6_pptr == 0);
381
382 return 0;
383 }
384
385 #define ADDCARRY(_x) do { \
386 while (((_x) >> 16) != 0) \
387 (_x) = ((_x) >> 16) + ((_x) & 0xffff); \
388 } while (0)
389
390 size_t
atomic_build(uint8_t * buf)391 atomic_build(uint8_t *buf)
392 {
393 size_t i, len = 0;
394 size_t plen, dlen = 16;
395 struct in6_addr src, dst;
396 uint32_t address_family = htonl(AF_INET6);
397
398 bzero(buf, BUF_SIZE);
399
400 bcopy(&address_family, buf, sizeof(uint32_t));
401 buf += sizeof(uint32_t);
402 len += sizeof(uint32_t);
403
404 struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
405 ip6->ip6_vfc = IPV6_VERSION;
406 ip6->ip6_nxt = IPPROTO_FRAGMENT;
407 ip6->ip6_hlim = IPV6_DEFHLIM;
408 plen = sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr) + dlen;
409 ip6->ip6_plen = htons(plen);
410
411 inet_pton(AF_INET6, peer_addr_str, &src);
412 bcopy(&src, &ip6->ip6_src, sizeof(src));
413 inet_pton(AF_INET6, utun_addr_str, &dst);
414 bcopy(&dst, &ip6->ip6_dst, sizeof(dst));
415
416 buf += sizeof(struct ip6_hdr);
417 len += sizeof(struct ip6_hdr);
418
419 struct ip6_frag *ip6f = (struct ip6_frag *)buf;
420 ip6f->ip6f_ident = 0xee;
421 ip6f->ip6f_nxt = IPPROTO_ICMPV6;
422 ip6f->ip6f_offlg = 0;
423
424 buf += sizeof(struct ip6_frag);
425 len += sizeof(struct ip6_frag);
426
427 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)buf;
428 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
429 icmp6->icmp6_code = 0;
430 icmp6->icmp6_cksum = 0;
431
432 buf += sizeof(struct icmp6_hdr);
433 len += sizeof(struct icmp6_hdr);
434
435 for (i = 0; i < dlen; i++) {
436 buf[i] = 'f';
437 }
438
439 uint16_t csum;
440 icmp6->icmp6_cksum = in6_pseudo(&src, &dst,
441 htonl(IPPROTO_ICMPV6 + sizeof(struct icmp6_hdr) + dlen));
442 csum = os_inet_checksum(icmp6, sizeof(struct icmp6_hdr) + dlen, 0);
443 csum = ~csum;
444 if (csum == 0) {
445 csum = 0xffff;
446 }
447 icmp6->icmp6_cksum = csum;
448
449 buf += dlen;
450 len += dlen;
451
452 return len;
453 }
454
455 int
atomic_match(uint8_t * pkt_out,size_t len_out,uint8_t * pkt_in,size_t len_in)456 atomic_match(uint8_t *pkt_out, size_t len_out, uint8_t *pkt_in, size_t len_in)
457 {
458 uint8_t *scan = pkt_out;
459 uint32_t af = ntohl(*(uint32_t *)pkt_out);
460
461 if (af != AF_INET6) {
462 T_LOG("%s fails: af != AF_INET6", __func__);
463 return -1;
464 }
465
466 scan += sizeof(af);
467 struct ip6_hdr *ip6 = (struct ip6_hdr *)scan;
468
469 //TODO check src/dst, etc.
470
471 if (ip6->ip6_nxt != IPPROTO_ICMPV6) {
472 T_LOG("%s fails: ip6_nxt != IPPROTO_ICMPV6", __func__);
473 return -1;
474 }
475
476 scan += sizeof(struct ip6_hdr);
477 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)scan;
478
479 assert(icmp6->icmp6_type == ICMP6_ECHO_REPLY);
480 assert(icmp6->icmp6_code == 0);
481
482 return 0;
483 }
484
485 size_t
queue_limit_build(uint8_t * buf)486 queue_limit_build(uint8_t *buf)
487 {
488 size_t len = 0;
489 struct in6_addr src, dst;
490 uint32_t address_family = htonl(AF_INET6);
491
492 bzero(buf, BUF_SIZE);
493
494 bcopy(&address_family, buf, sizeof(uint32_t));
495 buf += sizeof(uint32_t);
496 len += sizeof(uint32_t);
497
498 struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
499 ip6->ip6_vfc = IPV6_VERSION;
500 ip6->ip6_nxt = IPPROTO_FRAGMENT;
501 ip6->ip6_hlim = IPV6_DEFHLIM;
502 ip6->ip6_plen = htons(sizeof(struct ip6_frag));
503
504 inet_pton(AF_INET6, peer_addr_str, &src);
505 bcopy(&src, &ip6->ip6_src, sizeof(src));
506 inet_pton(AF_INET6, utun_addr_str, &dst);
507 bcopy(&dst, &ip6->ip6_dst, sizeof(dst));
508
509 buf += sizeof(struct ip6_hdr);
510 len += sizeof(struct ip6_hdr);
511
512 struct ip6_frag *ip6f = (struct ip6_frag *)buf;
513 ip6f->ip6f_ident = 0xee;
514 ip6f->ip6f_nxt = IPPROTO_NONE;
515 ip6f->ip6f_offlg = htons((u_short)((2048) & ~7));
516
517 buf += sizeof(struct ip6_frag);
518 len += sizeof(struct ip6_frag);
519
520 return len;
521 }
522
523 void
reass_lower_timeout(int * old_timeout,int new_timeout)524 reass_lower_timeout(int *old_timeout, int new_timeout)
525 {
526 size_t old_size = sizeof(*old_timeout);
527 int error;
528
529 error = sysctlbyname("kern.skywalk.flowswitch.ipfm_frag_ttl",
530 old_timeout, &old_size, &new_timeout, sizeof(int));
531 if (error) {
532 die_perror("kern.skywalk.flowswitch.ipfm_frag_ttl");
533 }
534 }
535
536 void
reass_restore_timeout(int old_timeout)537 reass_restore_timeout(int old_timeout)
538 {
539 int error;
540
541 error = sysctlbyname("kern.skywalk.flowswitch.ipfm_frag_ttl",
542 NULL, NULL, &old_timeout, sizeof(int));
543 if (error) {
544 die_perror("kern.skywalk.flowswitch.ipfm_frag_ttl");
545 }
546 }
547
548 int
skt_reass_main(int argc,char * argv[])549 skt_reass_main(int argc, char *argv[])
550 {
551 int error;
552
553 // setup full interface
554 utun_fd = sktu_create_interface(SKTU_IFT_UTUN,
555 SKTU_IFF_ENABLE_NETIF | SKTU_IFF_NO_ATTACH_FSW);
556
557 sktu_get_interface_name(SKTU_IFT_UTUN, utun_fd, utun_ifname);
558
559 struct in_addr our_ip, mask, broad_ip, dst_ip;
560 struct in6_addr our_ip_v6, dst_ip_v6;
561
562 inet_pton(AF_INET, our_ip_str, &our_ip);
563 inet_pton(AF_INET, dst_ip_str, &dst_ip);
564 inet_pton(AF_INET, broad_ip_str, &broad_ip);
565 mask = sktc_make_in_addr(IN_CLASSC_NET);
566 sktc_config_fsw_rx_agg_tcp(0);
567
568 if (sktc_ifnet_add_addr(utun_ifname, &our_ip, &mask, &broad_ip) != 0) {
569 err(EX_OSERR, "Failed to add address for %s", utun_ifname);
570 }
571
572 inet_pton(AF_INET6, utun_global_addr_str, &our_ip_v6);
573 inet_pton(AF_INET6, peer_global_addr_str, &dst_ip_v6);
574 error = sktc_ifnet_add_addr6(utun_ifname, &our_ip_v6, &dst_ip_v6,
575 addr_prefix_length, 0);
576
577 if (sktc_ifnet_add_scoped_default_route(utun_ifname, our_ip) != 0) {
578 err(EX_OSERR, "Failed to add default route: %s\n", utun_ifname);
579 }
580
581 bzero(&nexus, sizeof(nexus));
582 strlcpy(nexus.netif_ifname, utun_ifname, sizeof(nexus.netif_ifname));
583 nexus.netif_addr = our_ip;
584 nexus.netif_mask = mask;
585 sktc_create_flowswitch_no_address(&nexus, -1, -1, -1, -1, 0);
586
587 error = os_nexus_controller_bind_provider_instance(nexus.controller,
588 nexus.fsw_nx_uuid, NX_PORT, getpid(), NULL, NULL, 0,
589 NEXUS_BIND_PID);
590 SKTC_ASSERT_ERR(error == 0);
591
592 struct sktu_flow *flow_ipv4, *flow_ipv6;
593
594 flow_ipv4 = sktu_create_nexus_flow_with_nx_port(&nexus, NX_PORT,
595 AF_INET, &our_ip, &dst_ip, IPPROTO_UDP, 0, 1234);
596 assert(flow_ipv4);
597
598 flow_ipv6 = sktu_create_nexus_flow_with_nx_port(&nexus, NX_PORT,
599 AF_INET6, &our_ip_v6, &dst_ip_v6, IPPROTO_UDP, 0, 1234);
600 assert(flow_ipv4);
601
602 assert(flow_ipv4->nfr.nfr_nx_port == flow_ipv6->nfr.nfr_nx_port);
603
604 sktu_channel_port_init(&port, nexus.fsw_nx_uuid,
605 flow_ipv4->nfr.nfr_nx_port, true, false, false);
606 assert(port.chan != NULL);
607
608 uint8_t buf[8192];
609 // test both 8-byte-multiple and non 8-byte-multple sizes
610 reass_common(&port, flow_ipv4, buf, 2000);
611 reass_common(&port, flow_ipv4, buf, 2001);
612 reass_common(&port, flow_ipv4, buf, 8000);
613 reass_common(&port, flow_ipv4, buf, 8001);
614 reass_common(&port, flow_ipv6, buf, 2000);
615 reass_common(&port, flow_ipv6, buf, 2001);
616 reass_common(&port, flow_ipv6, buf, 8000);
617 reass_common(&port, flow_ipv6, buf, 8001);
618
619 sktu_destroy_nexus_flow(flow_ipv4);
620 sktu_destroy_nexus_flow(flow_ipv6);
621
622 reass_fini();
623
624 return 0;
625 }
626
627 int
skt_reass_main_default_setting(int argc,char * argv[])628 skt_reass_main_default_setting(int argc, char *argv[])
629 {
630 if (!sktc_is_netagent_enabled()) {
631 T_LOG("netagent not enabled on this platform, skip\n");
632 return 0;
633 }
634
635 if (!sktc_is_ip_reass_enabled()) {
636 T_LOG("ip reass not enabled on this platform, skip\n");
637 return 0;
638 }
639
640 return skt_reass_main(argc, argv);
641 }
642
643 #define REASS_TEST_GLOBAL(builder, matcher, timeout) \
644 utun_addr_str = utun_global_addr_str; \
645 peer_addr_str = peer_global_addr_str; \
646 reass_init(); \
647 reass_interface_send_rece(builder, matcher, &timeout); \
648 reass_fini();
649
650 #define REASS_TEST_LINKLOCAL(builder, matcher, timeout) \
651 utun_addr_str = utun_linklocal_addr_str; \
652 peer_addr_str = peer_linklocal_addr_str; \
653 reass_init(); \
654 reass_interface_send_rece(builder, matcher, &timeout); \
655 reass_fini();
656
657 #define REASS_TEST_ALL(builder, matcher, timeout) \
658 REASS_TEST_GLOBAL(builder, matcher, timeout) \
659 sleep(1); \
660 REASS_TEST_LINKLOCAL(builder, matcher, timeout)
661
662
663 #define REASS_FUZZ_GLOBAL(builder) \
664 utun_addr_str = utun_global_addr_str; \
665 peer_addr_str = peer_global_addr_str; \
666 reass_init(); \
667 reass_interface_send(builder); \
668 reass_fini();
669
670 #define REASS_FUZZ_LINKLOCAL(builder) \
671 utun_addr_str = utun_linklocal_addr_str; \
672 peer_addr_str = peer_linklocal_addr_str; \
673 reass_init(); \
674 reass_interface_send(builder); \
675 reass_fini();
676
677 #define REASS_FUZZ_ALL(builder) \
678 REASS_FUZZ_GLOBAL(builder) \
679 sleep(1); \
680 REASS_FUZZ_LINKLOCAL(builder)
681
682 int
skt_reass_timeout_main(int argc,char * argv[])683 skt_reass_timeout_main(int argc, char *argv[])
684 {
685 int old_timeout;
686 int new_timeout = 5;
687
688 reass_lower_timeout(&old_timeout, new_timeout);
689
690 REASS_TEST_ALL(timeout_build, timeout_match, timeout);
691
692 reass_restore_timeout(old_timeout);
693
694 return 0;
695 }
696
697 int
skt_reass_bad_fraglen_main(int argc,char * argv[])698 skt_reass_bad_fraglen_main(int argc, char *argv[])
699 {
700 REASS_TEST_ALL(bad_fraglen_build, bad_fraglen_match, timeout);
701 return 0;
702 }
703
704 int
skt_reass_atomic_main(int argc,char * argv[])705 skt_reass_atomic_main(int argc, char *argv[])
706 {
707 REASS_TEST_ALL(atomic_build, atomic_match, timeout);
708 return 0;
709 }
710
711 int
skt_reass_fuzz_queue_limit_main(int argc,char * argv[])712 skt_reass_fuzz_queue_limit_main(int argc, char *argv[])
713 {
714 REASS_FUZZ_ALL(queue_limit_build);
715 return 0;
716 }
717
718 struct skywalk_test skt_reass_default_setting = {
719 "reass_default_setting",
720 "UDP fragmentation reassembly (channel flow Rx) (without forcing ip_reass sysctl)",
721 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
722 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
723 skt_reass_main_default_setting, { NULL },
724 NULL, NULL,
725 };
726
727 struct skywalk_test skt_reass = {
728 "reass",
729 "UDP fragmentation reassembly (channel flow Rx)",
730 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
731 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
732 skt_reass_main, { NULL },
733 sktc_enable_ip_reass, sktc_restore_ip_reass,
734 };
735
736 struct skywalk_test skt_reass_timeout = {
737 "reass_timeout",
738 "send partial fragment to flowswitch and check for ICMPv6 time exceeded reply",
739 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
740 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
741 skt_reass_timeout_main, { NULL },
742 sktc_enable_ip_reass, sktc_restore_ip_reass,
743 };
744
745 struct skywalk_test skt_reass_bad_fraglen = {
746 "reass_bad_fraglen",
747 "send fragment with bad fragment length (!= 8*) to flowswitch and check for ICMPv6 param header reply",
748 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
749 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
750 skt_reass_bad_fraglen_main, { NULL },
751 sktc_enable_ip_reass, sktc_restore_ip_reass,
752 };
753
754 struct skywalk_test skt_reass_atomic = {
755 "reass_atomic",
756 "send atomic ICMP echo fragment to flowswitch and check for reply",
757 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
758 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
759 skt_reass_atomic_main, { NULL },
760 sktc_enable_ip_reass, sktc_restore_ip_reass,
761 };
762
763 struct skywalk_test skt_reass_fuzz_queue_limit = {
764 "reass_fuzz_queue_limit",
765 "fuzz flowswitch to hit fragment limit",
766 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
767 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
768 skt_reass_fuzz_queue_limit_main, { NULL },
769 sktc_enable_ip_reass, sktc_restore_ip_reass,
770 };
771