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