xref: /xnu-11215.1.10/tests/aqm_qdelay_utun.c (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
1*8d741a5dSApple OSS Distributions /*
2*8d741a5dSApple OSS Distributions  * Copyright (c) 2021 Apple Inc. All rights reserved.
3*8d741a5dSApple OSS Distributions  */
4*8d741a5dSApple OSS Distributions 
5*8d741a5dSApple OSS Distributions #include <sys/socket.h>
6*8d741a5dSApple OSS Distributions #include <sys/sockio.h>
7*8d741a5dSApple OSS Distributions #include <sys/ioctl.h>
8*8d741a5dSApple OSS Distributions #include <sys/kern_control.h>
9*8d741a5dSApple OSS Distributions #include <sys/sys_domain.h>
10*8d741a5dSApple OSS Distributions 
11*8d741a5dSApple OSS Distributions #include <net/if.h>
12*8d741a5dSApple OSS Distributions #include <net/if_utun.h>
13*8d741a5dSApple OSS Distributions #include <netinet/in.h>
14*8d741a5dSApple OSS Distributions #include <netinet/in_var.h>
15*8d741a5dSApple OSS Distributions #include <netinet/ip6.h>
16*8d741a5dSApple OSS Distributions #include <arpa/inet.h>
17*8d741a5dSApple OSS Distributions 
18*8d741a5dSApple OSS Distributions #include <err.h>
19*8d741a5dSApple OSS Distributions #include <errno.h>
20*8d741a5dSApple OSS Distributions #include <stdbool.h>
21*8d741a5dSApple OSS Distributions #include <stdint.h>
22*8d741a5dSApple OSS Distributions #include <stdio.h>
23*8d741a5dSApple OSS Distributions #include <stdlib.h>
24*8d741a5dSApple OSS Distributions #include <string.h>
25*8d741a5dSApple OSS Distributions #include <unistd.h>
26*8d741a5dSApple OSS Distributions 
27*8d741a5dSApple OSS Distributions #include <net/pktsched/pktsched.h>
28*8d741a5dSApple OSS Distributions #include <net/classq/if_classq.h>
29*8d741a5dSApple OSS Distributions 
30*8d741a5dSApple OSS Distributions #include <darwintest.h>
31*8d741a5dSApple OSS Distributions #include <darwintest_utils.h>
32*8d741a5dSApple OSS Distributions 
33*8d741a5dSApple OSS Distributions #define MSEC_PER_SEC    1000            /* milliseconds per second */
34*8d741a5dSApple OSS Distributions static void
nsec_to_str(unsigned long long nsec,char * buf)35*8d741a5dSApple OSS Distributions nsec_to_str(unsigned long long nsec, char *buf)
36*8d741a5dSApple OSS Distributions {
37*8d741a5dSApple OSS Distributions 	const char *u;
38*8d741a5dSApple OSS Distributions 	long double n = nsec, t;
39*8d741a5dSApple OSS Distributions 
40*8d741a5dSApple OSS Distributions 	if (nsec >= NSEC_PER_SEC) {
41*8d741a5dSApple OSS Distributions 		t = n / NSEC_PER_SEC;
42*8d741a5dSApple OSS Distributions 		u = "sec ";
43*8d741a5dSApple OSS Distributions 	} else if (n >= USEC_PER_SEC) {
44*8d741a5dSApple OSS Distributions 		t = n / USEC_PER_SEC;
45*8d741a5dSApple OSS Distributions 		u = "msec";
46*8d741a5dSApple OSS Distributions 	} else if (n >= MSEC_PER_SEC) {
47*8d741a5dSApple OSS Distributions 		t = n / MSEC_PER_SEC;
48*8d741a5dSApple OSS Distributions 		u = "usec";
49*8d741a5dSApple OSS Distributions 	} else {
50*8d741a5dSApple OSS Distributions 		t = n;
51*8d741a5dSApple OSS Distributions 		u = "nsec";
52*8d741a5dSApple OSS Distributions 	}
53*8d741a5dSApple OSS Distributions 
54*8d741a5dSApple OSS Distributions 	snprintf(buf, 32, "%-5.2Lf %4s", t, u);
55*8d741a5dSApple OSS Distributions }
56*8d741a5dSApple OSS Distributions 
57*8d741a5dSApple OSS Distributions static int
create_tun()58*8d741a5dSApple OSS Distributions create_tun()
59*8d741a5dSApple OSS Distributions {
60*8d741a5dSApple OSS Distributions 	int tun_fd;
61*8d741a5dSApple OSS Distributions 	struct ctl_info kernctl_info;
62*8d741a5dSApple OSS Distributions 	struct sockaddr_ctl kernctl_addr;
63*8d741a5dSApple OSS Distributions 
64*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(tun_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), NULL);
65*8d741a5dSApple OSS Distributions 
66*8d741a5dSApple OSS Distributions 	memset(&kernctl_info, 0, sizeof(kernctl_info));
67*8d741a5dSApple OSS Distributions 	strlcpy(kernctl_info.ctl_name, UTUN_CONTROL_NAME, sizeof(kernctl_info.ctl_name));
68*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ioctl(tun_fd, CTLIOCGINFO, &kernctl_info), NULL);
69*8d741a5dSApple OSS Distributions 
70*8d741a5dSApple OSS Distributions 	memset(&kernctl_addr, 0, sizeof(kernctl_addr));
71*8d741a5dSApple OSS Distributions 	kernctl_addr.sc_len = sizeof(kernctl_addr);
72*8d741a5dSApple OSS Distributions 	kernctl_addr.sc_family = AF_SYSTEM;
73*8d741a5dSApple OSS Distributions 	kernctl_addr.ss_sysaddr = AF_SYS_CONTROL;
74*8d741a5dSApple OSS Distributions 	kernctl_addr.sc_id = kernctl_info.ctl_id;
75*8d741a5dSApple OSS Distributions 	kernctl_addr.sc_unit = 0;
76*8d741a5dSApple OSS Distributions 
77*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(bind(tun_fd, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr)), NULL);
78*8d741a5dSApple OSS Distributions 
79*8d741a5dSApple OSS Distributions 	const int enable = 1;
80*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(setsockopt(tun_fd, SYSPROTO_CONTROL, UTUN_OPT_ENABLE_NETIF,
81*8d741a5dSApple OSS Distributions 	    &enable, sizeof(enable)), NULL);
82*8d741a5dSApple OSS Distributions 
83*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_FAILURE(setsockopt(tun_fd, SYSPROTO_CONTROL, UTUN_OPT_ENABLE_FLOWSWITCH,
84*8d741a5dSApple OSS Distributions 	    &enable, sizeof(enable)), EINVAL, NULL);
85*8d741a5dSApple OSS Distributions 
86*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(connect(tun_fd, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr)), NULL);;
87*8d741a5dSApple OSS Distributions 
88*8d741a5dSApple OSS Distributions 	return tun_fd;
89*8d741a5dSApple OSS Distributions }
90*8d741a5dSApple OSS Distributions 
91*8d741a5dSApple OSS Distributions static short
ifnet_get_flags(int s,const char ifname[IFNAMSIZ])92*8d741a5dSApple OSS Distributions ifnet_get_flags(int s, const char ifname[IFNAMSIZ])
93*8d741a5dSApple OSS Distributions {
94*8d741a5dSApple OSS Distributions 	struct ifreq    ifr;
95*8d741a5dSApple OSS Distributions 	memset(&ifr, 0, sizeof(ifr));
96*8d741a5dSApple OSS Distributions 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
97*8d741a5dSApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_EXPECT_POSIX_ZERO(ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr), NULL);
98*8d741a5dSApple OSS Distributions 	return ifr.ifr_flags;
99*8d741a5dSApple OSS Distributions }
100*8d741a5dSApple OSS Distributions 
101*8d741a5dSApple OSS Distributions static void
ifnet_add_addr4(const char ifname[IFNAMSIZ],struct in_addr * addr,struct in_addr * mask,struct in_addr * broadaddr)102*8d741a5dSApple OSS Distributions ifnet_add_addr4(const char ifname[IFNAMSIZ], struct in_addr *addr, struct in_addr *mask, struct in_addr *broadaddr)
103*8d741a5dSApple OSS Distributions {
104*8d741a5dSApple OSS Distributions 	struct sockaddr_in *sin;
105*8d741a5dSApple OSS Distributions 	struct in_aliasreq ifra;
106*8d741a5dSApple OSS Distributions 	int s;
107*8d741a5dSApple OSS Distributions 
108*8d741a5dSApple OSS Distributions 	T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), NULL);
109*8d741a5dSApple OSS Distributions 
110*8d741a5dSApple OSS Distributions 	memset(&ifra, 0, sizeof(ifra));
111*8d741a5dSApple OSS Distributions 	strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
112*8d741a5dSApple OSS Distributions 
113*8d741a5dSApple OSS Distributions 	if (addr != NULL) {
114*8d741a5dSApple OSS Distributions 		sin = &ifra.ifra_addr;
115*8d741a5dSApple OSS Distributions 		sin->sin_len = sizeof(*sin);
116*8d741a5dSApple OSS Distributions 		sin->sin_family = AF_INET;
117*8d741a5dSApple OSS Distributions 		sin->sin_addr = *addr;
118*8d741a5dSApple OSS Distributions 	}
119*8d741a5dSApple OSS Distributions 
120*8d741a5dSApple OSS Distributions 	if (mask != NULL) {
121*8d741a5dSApple OSS Distributions 		sin = &ifra.ifra_mask;
122*8d741a5dSApple OSS Distributions 		sin->sin_len = sizeof(*sin);
123*8d741a5dSApple OSS Distributions 		sin->sin_family = AF_INET;
124*8d741a5dSApple OSS Distributions 		sin->sin_addr = *mask;
125*8d741a5dSApple OSS Distributions 	}
126*8d741a5dSApple OSS Distributions 
127*8d741a5dSApple OSS Distributions 	if (broadaddr != NULL || (addr != NULL &&
128*8d741a5dSApple OSS Distributions 	    (ifnet_get_flags(s, ifname) & IFF_POINTOPOINT) != 0)) {
129*8d741a5dSApple OSS Distributions 		sin = &ifra.ifra_broadaddr;
130*8d741a5dSApple OSS Distributions 		sin->sin_len = sizeof(*sin);
131*8d741a5dSApple OSS Distributions 		sin->sin_family = AF_INET;
132*8d741a5dSApple OSS Distributions 		sin->sin_addr = (broadaddr != NULL) ? *broadaddr : *addr;
133*8d741a5dSApple OSS Distributions 	}
134*8d741a5dSApple OSS Distributions 
135*8d741a5dSApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_EXPECT_POSIX_ZERO(ioctl(s, SIOCAIFADDR, &ifra), NULL);
136*8d741a5dSApple OSS Distributions 
137*8d741a5dSApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_EXPECT_POSIX_ZERO(close(s), NULL);
138*8d741a5dSApple OSS Distributions }
139*8d741a5dSApple OSS Distributions 
140*8d741a5dSApple OSS Distributions static struct if_qstatsreq ifqr;
141*8d741a5dSApple OSS Distributions static struct if_ifclassq_stats *ifcqs;
142*8d741a5dSApple OSS Distributions static uint32_t scheduler;
143*8d741a5dSApple OSS Distributions 
144*8d741a5dSApple OSS Distributions #define FQ_IF_BE_INDEX  7
145*8d741a5dSApple OSS Distributions static int
aqmstats_setup(char * iface)146*8d741a5dSApple OSS Distributions aqmstats_setup(char *iface)
147*8d741a5dSApple OSS Distributions {
148*8d741a5dSApple OSS Distributions 	unsigned int ifindex;
149*8d741a5dSApple OSS Distributions 	int s;
150*8d741a5dSApple OSS Distributions 
151*8d741a5dSApple OSS Distributions 	ifindex = if_nametoindex(iface);
152*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(ifindex != 0, "interface index for utun");
153*8d741a5dSApple OSS Distributions 
154*8d741a5dSApple OSS Distributions 	ifcqs = malloc(sizeof(*ifcqs));
155*8d741a5dSApple OSS Distributions 	T_ASSERT_TRUE(ifcqs != 0, "Allocated ifcqs");
156*8d741a5dSApple OSS Distributions 
157*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), NULL);
158*8d741a5dSApple OSS Distributions 
159*8d741a5dSApple OSS Distributions 	bzero(&ifqr, sizeof(ifqr));
160*8d741a5dSApple OSS Distributions 	strlcpy(ifqr.ifqr_name, iface, sizeof(ifqr.ifqr_name));
161*8d741a5dSApple OSS Distributions 	ifqr.ifqr_buf = ifcqs;
162*8d741a5dSApple OSS Distributions 	ifqr.ifqr_len = sizeof(*ifcqs);
163*8d741a5dSApple OSS Distributions 
164*8d741a5dSApple OSS Distributions 	// Get the scheduler
165*8d741a5dSApple OSS Distributions 	ifqr.ifqr_slot = 0;
166*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr), NULL);
167*8d741a5dSApple OSS Distributions 	scheduler = ifcqs->ifqs_scheduler;
168*8d741a5dSApple OSS Distributions 
169*8d741a5dSApple OSS Distributions 	// Update the slot to BE
170*8d741a5dSApple OSS Distributions 	ifqr.ifqr_slot = FQ_IF_BE_INDEX;
171*8d741a5dSApple OSS Distributions 
172*8d741a5dSApple OSS Distributions 	return s;
173*8d741a5dSApple OSS Distributions }
174*8d741a5dSApple OSS Distributions 
175*8d741a5dSApple OSS Distributions static void
aqmstats_cleanup()176*8d741a5dSApple OSS Distributions aqmstats_cleanup()
177*8d741a5dSApple OSS Distributions {
178*8d741a5dSApple OSS Distributions 	free(ifcqs);
179*8d741a5dSApple OSS Distributions }
180*8d741a5dSApple OSS Distributions 
181*8d741a5dSApple OSS Distributions T_DECL(aqm_qdelay, "This test checks the min/max/avg AQM queuing delay", T_META_TAG_VM_PREFERRED)
182*8d741a5dSApple OSS Distributions {
183*8d741a5dSApple OSS Distributions 	T_SETUPBEGIN;
184*8d741a5dSApple OSS Distributions 
185*8d741a5dSApple OSS Distributions 	// Create tun device with IPv4 address
186*8d741a5dSApple OSS Distributions 	int tun_fd = create_tun();
187*8d741a5dSApple OSS Distributions 
188*8d741a5dSApple OSS Distributions 	char ifname[IFXNAMSIZ];
189*8d741a5dSApple OSS Distributions 	socklen_t optlen = IFNAMSIZ;
190*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(getsockopt(tun_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, ifname, &optlen), NULL);
191*8d741a5dSApple OSS Distributions 	T_ASSERT_TRUE(ifname[optlen - 1] == '\0', NULL);
192*8d741a5dSApple OSS Distributions 	T_LOG("Created interface %s", ifname);
193*8d741a5dSApple OSS Distributions 
194*8d741a5dSApple OSS Distributions 	uint32_t ifaddr = (10 << 24) | ((unsigned)getpid() & 0xffff) << 8 | 160;
195*8d741a5dSApple OSS Distributions 	struct in_addr tun_addr1, tun_addr2, mask;
196*8d741a5dSApple OSS Distributions 	tun_addr1.s_addr = htonl(ifaddr);
197*8d741a5dSApple OSS Distributions 	tun_addr2.s_addr = htonl(ifaddr + 1);
198*8d741a5dSApple OSS Distributions 	mask.s_addr = htonl(0xffffffff);
199*8d741a5dSApple OSS Distributions 
200*8d741a5dSApple OSS Distributions 	ifnet_add_addr4(ifname, &tun_addr1, &mask, &tun_addr2);
201*8d741a5dSApple OSS Distributions 
202*8d741a5dSApple OSS Distributions 	// Create UDP socket to send
203*8d741a5dSApple OSS Distributions 	int sock_fd;
204*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sock_fd = socket(AF_INET, SOCK_DGRAM, 0), NULL);
205*8d741a5dSApple OSS Distributions 	struct sockaddr_in sin;
206*8d741a5dSApple OSS Distributions 	memset(&sin, 0, sizeof(sin));
207*8d741a5dSApple OSS Distributions 	sin.sin_len = sizeof(sin);
208*8d741a5dSApple OSS Distributions 	sin.sin_family = AF_INET;
209*8d741a5dSApple OSS Distributions 	sin.sin_addr = tun_addr1;
210*8d741a5dSApple OSS Distributions 
211*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(bind(sock_fd, (struct sockaddr *)&sin, sizeof(sin)), NULL);
212*8d741a5dSApple OSS Distributions 
213*8d741a5dSApple OSS Distributions 	struct sockaddr_in dest;
214*8d741a5dSApple OSS Distributions 	memset(&sin, 0, sizeof(dest));
215*8d741a5dSApple OSS Distributions 	dest.sin_len = sizeof(dest);
216*8d741a5dSApple OSS Distributions 	dest.sin_family = AF_INET;
217*8d741a5dSApple OSS Distributions 	dest.sin_addr = tun_addr2;
218*8d741a5dSApple OSS Distributions 	dest.sin_port = ntohs(12345);
219*8d741a5dSApple OSS Distributions 
220*8d741a5dSApple OSS Distributions 	// Setup the state for AQM stats
221*8d741a5dSApple OSS Distributions 	int stats_fd = aqmstats_setup(ifname);
222*8d741a5dSApple OSS Distributions 
223*8d741a5dSApple OSS Distributions 	T_SETUPEND;
224*8d741a5dSApple OSS Distributions 
225*8d741a5dSApple OSS Distributions 	char min[32], max[32], avg[32];
226*8d741a5dSApple OSS Distributions 	// Get the current value of min/max/avg qdelay
227*8d741a5dSApple OSS Distributions 	if (scheduler == PKTSCHEDT_FQ_CODEL) {
228*8d741a5dSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ioctl(stats_fd, SIOCGIFQUEUESTATS, (char *)&ifqr), NULL);
229*8d741a5dSApple OSS Distributions 		nsec_to_str(ifcqs->ifqs_fq_codel_stats.fcls_min_qdelay, min);
230*8d741a5dSApple OSS Distributions 		nsec_to_str(ifcqs->ifqs_fq_codel_stats.fcls_max_qdelay, max);
231*8d741a5dSApple OSS Distributions 		nsec_to_str(ifcqs->ifqs_fq_codel_stats.fcls_avg_qdelay, avg);
232*8d741a5dSApple OSS Distributions 
233*8d741a5dSApple OSS Distributions 		T_LOG("min/max/avg qdelay %10s    %10s    %10s", min, max, avg);
234*8d741a5dSApple OSS Distributions 	}
235*8d741a5dSApple OSS Distributions 
236*8d741a5dSApple OSS Distributions 	// Send data
237*8d741a5dSApple OSS Distributions 	T_LOG("Sending 10 UDP packets...");
238*8d741a5dSApple OSS Distributions 	uint8_t content[0x578] = {0};
239*8d741a5dSApple OSS Distributions 	for (int i = 0; i < 5; i++) {
240*8d741a5dSApple OSS Distributions 		sendto(sock_fd, content, sizeof(content), 0, (struct sockaddr *)&dest,
241*8d741a5dSApple OSS Distributions 		    (socklen_t) sizeof(dest));
242*8d741a5dSApple OSS Distributions 		usleep(1000);
243*8d741a5dSApple OSS Distributions 	}
244*8d741a5dSApple OSS Distributions 
245*8d741a5dSApple OSS Distributions 	// Get the current value of min/max/avg qdelay
246*8d741a5dSApple OSS Distributions 	if (scheduler == PKTSCHEDT_FQ_CODEL) {
247*8d741a5dSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ioctl(stats_fd, SIOCGIFQUEUESTATS, (char *)&ifqr), NULL);
248*8d741a5dSApple OSS Distributions 		nsec_to_str(ifcqs->ifqs_fq_codel_stats.fcls_min_qdelay, min);
249*8d741a5dSApple OSS Distributions 		nsec_to_str(ifcqs->ifqs_fq_codel_stats.fcls_max_qdelay, max);
250*8d741a5dSApple OSS Distributions 		nsec_to_str(ifcqs->ifqs_fq_codel_stats.fcls_avg_qdelay, avg);
251*8d741a5dSApple OSS Distributions 
252*8d741a5dSApple OSS Distributions 		T_LOG("min/max/avg qdelay %10s    %10s    %10s", min, max, avg);
253*8d741a5dSApple OSS Distributions 		T_ASSERT_TRUE(ifcqs->ifqs_fq_codel_stats.fcls_min_qdelay <= ifcqs->ifqs_fq_codel_stats.fcls_avg_qdelay &&
254*8d741a5dSApple OSS Distributions 		    ifcqs->ifqs_fq_codel_stats.fcls_min_qdelay <= ifcqs->ifqs_fq_codel_stats.fcls_max_qdelay, "min qdelay check");
255*8d741a5dSApple OSS Distributions 		T_ASSERT_TRUE(ifcqs->ifqs_fq_codel_stats.fcls_avg_qdelay <= ifcqs->ifqs_fq_codel_stats.fcls_max_qdelay, "avg qdelay check");
256*8d741a5dSApple OSS Distributions 	}
257*8d741a5dSApple OSS Distributions 
258*8d741a5dSApple OSS Distributions 	aqmstats_cleanup();
259*8d741a5dSApple OSS Distributions 	// Close socket and utun device
260*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(close(sock_fd), NULL);
261*8d741a5dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(close(tun_fd), NULL);
262*8d741a5dSApple OSS Distributions }
263