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