xref: /xnu-12377.1.9/tests/skywalk/skt_fullupipe.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
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