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 /* Attempts to manually fill a upipe to force an a tx sync from rx
30 * Both end of upipe are in the child process.
31 */
32
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <uuid/uuid.h>
39 #include <darwintest.h>
40 #include "skywalk_test_driver.h"
41 #include "skywalk_test_common.h"
42 #include "skywalk_test_utils.h"
43
44 #define NSLOTS 100
45
46 void
skt_fullupipe_init(void)47 skt_fullupipe_init(void)
48 {
49 struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();
50
51 strncpy((char *)attr.name, "skywalk_test_fullupipe",
52 sizeof(nexus_name_t) - 1);
53 attr.type = NEXUS_TYPE_USER_PIPE;
54 attr.ntxrings = 1;
55 attr.nrxrings = 1;
56 attr.ntxslots = NSLOTS;
57 attr.nrxslots = NSLOTS;
58 attr.anonymous = 1;
59 attr.rejectonclose = 1;
60
61 sktc_setup_nexus(&attr);
62 }
63
64 void
skt_fullupipe_fini(void)65 skt_fullupipe_fini(void)
66 {
67 sktc_cleanup_nexus();
68 }
69
70 int
skt_fullupipe_main(int argc,char * argv[])71 skt_fullupipe_main(int argc, char *argv[])
72 {
73 int error;
74 uuid_t instance_uuid;
75 channel_t channel0, channel1;
76 channel_ring_t txring0, rxring1;
77 channel_slot_t txslot0, rxslot1;
78 uint32_t txavail0, rxavail1;
79 error = uuid_parse(argv[3], instance_uuid);
80 SKTC_ASSERT_ERR(!error);
81
82 channel0 = sktu_channel_create_extended(instance_uuid, 0,
83 CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
84 -1, -1, -1, -1, -1, -1, 1, -1, -1);
85 assert(channel0);
86 channel1 = sktu_channel_create_extended(instance_uuid, 1,
87 CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
88 -1, -1, -1, -1, -1, -1, 1, -1, -1);
89 assert(channel1);
90
91 txring0 = os_channel_tx_ring(channel0, os_channel_ring_id(channel0, CHANNEL_FIRST_TX_RING));
92 assert(txring0);
93 rxring1 = os_channel_rx_ring(channel1, os_channel_ring_id(channel1, CHANNEL_FIRST_RX_RING));
94 assert(rxring1);
95
96 /* Iterate through the tx slots */
97 txavail0 = os_channel_available_slot_count(txring0);
98 assert(txavail0 == NSLOTS - 1);
99 txslot0 = NULL;
100 while (txavail0--) {
101 slot_prop_t props;
102 txslot0 = os_channel_get_next_slot(txring0, txslot0, &props);
103 assert(txslot0);
104 os_channel_set_slot_properties(txring0, txslot0, &props);
105 }
106 assert(!os_channel_get_next_slot(txring0, txslot0, NULL));
107
108 /* Verify there are no rx slots */
109 rxavail1 = os_channel_available_slot_count(rxring1);
110 assert(rxavail1 == 0);
111 rxslot1 = NULL;
112 assert(!os_channel_get_next_slot(rxring1, rxslot1, NULL));
113
114 error = os_channel_advance_slot(txring0, txslot0);
115 SKTC_ASSERT_ERR(!error);
116
117 /* Double check that the tx queue is full and the rx queue is empty */
118 txavail0 = os_channel_available_slot_count(txring0);
119 assert(txavail0 == 0);
120 rxavail1 = os_channel_available_slot_count(rxring1);
121 assert(rxavail1 == 0);
122
123 /*
124 * Now try an rx sync, this shouldn't do anything since
125 * no packets have been synced to tx yet.
126 */
127 error = os_channel_sync(channel1, CHANNEL_SYNC_RX);
128 SKTC_ASSERT_ERR(!error);
129
130 /* The txqueue is still full and the rx queue is still empty */
131 txavail0 = os_channel_available_slot_count(txring0);
132 assert(txavail0 == 0);
133 rxavail1 = os_channel_available_slot_count(rxring1);
134 assert(rxavail1 == 0);
135
136 /*
137 * Now try a tx sync, this push slots into the rx queue
138 */
139 error = os_channel_sync(channel0, CHANNEL_SYNC_TX);
140 SKTC_ASSERT_ERR(!error);
141
142 /* The txqueue is now empty and the rx queue is full */
143 txavail0 = os_channel_available_slot_count(txring0);
144 assert(txavail0 == NSLOTS - 1);
145 rxavail1 = os_channel_available_slot_count(rxring1);
146 assert(rxavail1 == 0);
147
148 /* Now fill up the tx slots again */
149 txavail0 = os_channel_available_slot_count(txring0);
150 assert(txavail0 == NSLOTS - 1);
151 txslot0 = NULL;
152 while (txavail0--) {
153 slot_prop_t props;
154 txslot0 = os_channel_get_next_slot(txring0, txslot0, &props);
155 assert(txslot0);
156 os_channel_set_slot_properties(txring0, txslot0, &props);
157 }
158 assert(!os_channel_get_next_slot(txring0, txslot0, NULL));
159
160 /* Verify there are no rx slots because
161 * we haven't done an rx sync yet
162 */
163 rxavail1 = os_channel_available_slot_count(rxring1);
164 assert(rxavail1 == 0);
165 rxslot1 = NULL;
166 assert(!os_channel_get_next_slot(rxring1, rxslot1, NULL));
167
168 error = os_channel_advance_slot(txring0, txslot0);
169 SKTC_ASSERT_ERR(!error);
170
171 /* Both the tx and rx queues are now full, but we can't
172 * see the slots until we do an rx sync
173 */
174 txavail0 = os_channel_available_slot_count(txring0);
175 assert(txavail0 == 0);
176 rxavail1 = os_channel_available_slot_count(rxring1);
177 assert(rxavail1 == 0);
178
179 /*
180 * Now try a tx sync, there's no room in the rx queue
181 * so this won't move any slots, but it will make them
182 * visible to the kernel
183 */
184 error = os_channel_sync(channel0, CHANNEL_SYNC_TX);
185 SKTC_ASSERT_ERR(!error);
186
187 /* Still can't see any slots without an rx sync */
188 txavail0 = os_channel_available_slot_count(txring0);
189 assert(txavail0 == 0);
190 rxavail1 = os_channel_available_slot_count(rxring1);
191 assert(rxavail1 == 0);
192
193 error = os_channel_sync(channel1, CHANNEL_SYNC_RX);
194 SKTC_ASSERT_ERR(!error);
195
196 /* Now we should see all the slots on rx */
197 txavail0 = os_channel_available_slot_count(txring0);
198 assert(txavail0 == 0);
199 rxavail1 = os_channel_available_slot_count(rxring1);
200 assert(rxavail1 == NSLOTS - 1);
201
202 /* Now chew up some rx slots */
203 rxavail1 = os_channel_available_slot_count(rxring1);
204 assert(rxavail1 == NSLOTS - 1);
205 rxslot1 = NULL;
206 while (rxavail1--) {
207 rxslot1 = os_channel_get_next_slot(rxring1, rxslot1, NULL);
208 assert(rxslot1);
209 }
210 assert(!os_channel_get_next_slot(rxring1, rxslot1, NULL));
211
212 error = os_channel_advance_slot(rxring1, rxslot1);
213 SKTC_ASSERT_ERR(!error);
214
215 /* No more slots available until we sync */
216 txavail0 = os_channel_available_slot_count(txring0);
217 assert(txavail0 == 0);
218 rxavail1 = os_channel_available_slot_count(rxring1);
219 assert(rxavail1 == 0);
220
221 error = os_channel_sync(channel1, CHANNEL_SYNC_RX);
222 SKTC_ASSERT_ERR(!error);
223
224 /* Now we should see all the slots on rx because it will
225 * reach over and get slots from the tx
226 */
227 txavail0 = os_channel_available_slot_count(txring0);
228 assert(txavail0 == 0);
229 rxavail1 = os_channel_available_slot_count(rxring1);
230 assert(rxavail1 == NSLOTS - 1);
231
232 /* Now chew up some rx slots */
233 rxavail1 = os_channel_available_slot_count(rxring1);
234 assert(rxavail1 == NSLOTS - 1);
235 rxslot1 = NULL;
236 while (rxavail1--) {
237 rxslot1 = os_channel_get_next_slot(rxring1, rxslot1, NULL);
238 assert(rxslot1);
239 }
240 assert(!os_channel_get_next_slot(rxring1, rxslot1, NULL));
241
242 error = os_channel_advance_slot(rxring1, rxslot1);
243 SKTC_ASSERT_ERR(!error);
244
245 /* We haven't seen the new tx slots until we do a tx sync */
246 txavail0 = os_channel_available_slot_count(txring0);
247 assert(txavail0 == 0);
248 rxavail1 = os_channel_available_slot_count(rxring1);
249 assert(rxavail1 == 0);
250
251 error = os_channel_sync(channel0, CHANNEL_SYNC_TX);
252 SKTC_ASSERT_ERR(!error);
253
254 /* We now see the new slots because of the tx sync */
255 txavail0 = os_channel_available_slot_count(txring0);
256 assert(txavail0 == NSLOTS - 1);
257 rxavail1 = os_channel_available_slot_count(rxring1);
258 assert(rxavail1 == 0);
259
260 os_channel_destroy(channel0);
261 os_channel_destroy(channel1);
262
263 return 0;
264 }
265
266 int
skt_upipepeerclosure_main(int argc,char * argv[])267 skt_upipepeerclosure_main(int argc, char *argv[])
268 {
269 int error;
270 uuid_t instance_uuid;
271 channel_t channel0, channel1;
272 channel_ring_t txring0, rxring1;
273 channel_slot_t txslot0, rxslot1;
274 uint32_t txavail0, rxavail1;
275 error = uuid_parse(argv[3], instance_uuid);
276 SKTC_ASSERT_ERR(!error);
277
278 channel0 = sktu_channel_create_extended(instance_uuid, 0,
279 CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
280 -1, -1, -1, -1, -1, -1, 1, -1, -1);
281 assert(channel0);
282 channel1 = sktu_channel_create_extended(instance_uuid, 1,
283 CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
284 -1, -1, -1, -1, -1, -1, 1, -1, -1);
285 assert(channel1);
286
287 txring0 = os_channel_tx_ring(channel0, os_channel_ring_id(channel0,
288 CHANNEL_FIRST_TX_RING));
289 assert(txring0);
290 rxring1 = os_channel_rx_ring(channel1, os_channel_ring_id(channel1,
291 CHANNEL_FIRST_RX_RING));
292 assert(rxring1);
293
294 /* Iterate through all the tx slots */
295 txavail0 = os_channel_available_slot_count(txring0);
296 assert(txavail0 == NSLOTS - 1);
297 txslot0 = NULL;
298 while (txavail0--) {
299 slot_prop_t props;
300 txslot0 = os_channel_get_next_slot(txring0, txslot0, &props);
301 assert(txslot0);
302 os_channel_set_slot_properties(txring0, txslot0, &props);
303 }
304 assert(!os_channel_get_next_slot(txring0, txslot0, NULL));
305 error = os_channel_advance_slot(txring0, txslot0);
306 SKTC_ASSERT_ERR(!error);
307
308 error = os_channel_sync(channel0, CHANNEL_SYNC_TX);
309 SKTC_ASSERT_ERR(!error);
310
311 error = os_channel_sync(channel1, CHANNEL_SYNC_RX);
312 SKTC_ASSERT_ERR(!error);
313
314 /* Now we should see all the slots on rx */
315 rxavail1 = os_channel_available_slot_count(rxring1);
316 assert(rxavail1 == NSLOTS - 1);
317
318 /* Now chew up all rx slots */
319 rxavail1 = os_channel_available_slot_count(rxring1);
320 assert(rxavail1 == NSLOTS - 1);
321 rxslot1 = NULL;
322 while (rxavail1--) {
323 rxslot1 = os_channel_get_next_slot(rxring1, rxslot1, NULL);
324 assert(rxslot1);
325 }
326 assert(!os_channel_get_next_slot(rxring1, rxslot1, NULL));
327 error = os_channel_advance_slot(rxring1, rxslot1);
328 SKTC_ASSERT_ERR(!error);
329 error = os_channel_sync(channel1, CHANNEL_SYNC_RX);
330 SKTC_ASSERT_ERR(!error);
331
332 /* close channel1 */
333 os_channel_destroy(channel1);
334
335 /* this should throw an error as the peer channel is closed */
336 error = os_channel_sync(channel0, CHANNEL_SYNC_TX);
337 if (error == 0) {
338 T_LOG("unexpected success\n");
339 assert(0);
340 } else if (errno != ENXIO) {
341 SKT_LOG("unexpected errno: error %d "
342 "errno %d: %s\n", error, errno, strerror(errno));
343 assert(0);
344 }
345 os_channel_destroy(channel0);
346 return 0;
347 }
348
349 struct skywalk_test skt_fullupipe = {
350 "fullupipe", "test rx on full tx pipe",
351 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
352 skt_fullupipe_main, SKTC_GENERIC_UPIPE_ARGV,
353 skt_fullupipe_init, skt_fullupipe_fini,
354 };
355
356 struct skywalk_test skt_upipepeerclosure = {
357 "upipepeerclosure", "test channel operations on upipe with no peer",
358 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
359 skt_upipepeerclosure_main, SKTC_GENERIC_UPIPE_ARGV,
360 skt_fullupipe_init, skt_fullupipe_fini,
361 };
362