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