xref: /xnu-11417.121.6/tests/skywalk/skt_filter.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1 /*
2  * Copyright (c) 2019-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 #include <sys/types.h>
29 #include <sys/sysctl.h>
30 #include <sys/ioctl.h>
31 #include <net/ethernet.h>
32 #include <net/if.h>
33 #include <net/if_vlan_var.h>
34 #include <libkern/OSAtomic.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <pthread.h>
39 #include "skywalk_test_driver.h"
40 #include "skywalk_test_utils.h"
41 #include "skywalk_test_common.h"
42 
43 /*
44  ****************************************************************
45  *                 Start of common section                      *
46  ****************************************************************
47  */
48 #define FILTER_RECV_PORT                20000
49 #define FILTER_SEND_PORT                20001
50 
51 #define CMD_RECV_SOCKET_READY           0x11
52 #define CMD_RECV_CHANNEL_READY          0x12
53 #define CMD_RECV_ALL_DONE               0x13
54 #define CLIENT_CMD_SEND_SOCKET_START    0x21
55 #define CLIENT_CMD_SEND_CHANNEL_START   0x22
56 
57 #define SOCKET_THREADS                  16
58 #define SOCKET_BYTES                    10000000
59 #define SOCKET_LISTENER_PORT            30000
60 
61 #define CUSTOM_ETHER_THREADS            16
62 #define CUSTOM_ETHER_ETHERTYPE_BASE     3000
63 #define CUSTOM_ETHER_ITERATIONS         10000
64 #define CUSTOM_ETHER_PKT_LEN            512
65 
66 #define SEPARATOR(opts) \
67     (*(opts) != '\0' ? ", " : "")
68 #define SKTDBG(name, opts, fmt, ...) \
69     SKD1("%s: %s%s" fmt, (name), (opts), SEPARATOR((opts)), \
70     ##__VA_ARGS__)
71 
72 typedef struct {
73 	int             fd;
74 	uint64_t        bytes;
75 } socket_args_t;
76 
77 typedef struct {
78 	bool            is_sender;
79 	bool            is_tagged;
80 	uint16_t        ethertype;
81 	uint8_t         priority;
82 	uint64_t        sent;
83 	uint64_t        received;
84 	channel_t       ch;
85 	nexus_controller_t nx_ncd;
86 } custom_ether_args_t;
87 
88 static char databuf[2048];
89 static socket_args_t socket_thread_args[SOCKET_THREADS];
90 static int socket_ready = 0;
91 static int socket_done = 0;
92 
93 static uuid_t if_uuid;
94 static int custom_ether_ready = 0;
95 static int custom_ether_done = 0;
96 static ether_addr_t src_mac_addr, dst_mac_addr;
97 static custom_ether_args_t custom_ether_thread_args[CUSTOM_ETHER_THREADS];
98 
99 static void
connect_to_server(uint16_t port,int * client_fd)100 connect_to_server(uint16_t port, int *client_fd)
101 {
102 	struct sockaddr_in sin;
103 	int fd, error = 0, retries = 0;
104 	char *client;
105 
106 	client = (port == FILTER_RECV_PORT) ? "receiver" : "sender";
107 	for (;;) {
108 		SKD1("%s: connecting to server\n", client);
109 		fd = socket(AF_INET, SOCK_STREAM, 0);
110 		SKTC_ASSERT_ERR(fd != -1);
111 
112 		sin.sin_family = AF_INET;
113 		sin.sin_addr.s_addr = inet_addr("127.0.0.1");
114 		sin.sin_port = htons(port);
115 		error = connect(fd, (struct sockaddr *)&sin,
116 		    sizeof(sin));
117 		if (error == -1) {
118 			if (errno == ECONNREFUSED) {
119 				if (retries == 10) {
120 					SKD0("%s: giving up\n", client);
121 					exit(1);
122 				}
123 				(void) close(fd);
124 				SKD0("%s: server not ready, retrying...\n",
125 				    client);
126 				retries++;
127 				sleep(1);
128 				continue;
129 			} else {
130 				SKD0("%s: got unexpected error: %d\n",
131 				    client, errno);
132 				exit(1);
133 			}
134 		}
135 		SKD1("%s: connected to server\n", client);
136 		SKTC_ASSERT_ERR(error == 0);
137 		break;
138 	}
139 	*client_fd = fd;
140 }
141 
142 static uint8_t
read_cmd(int fd)143 read_cmd(int fd)
144 {
145 	int r, error = 0;
146 	uint8_t cmd;
147 
148 	r = read(fd, &cmd, sizeof(cmd));
149 	SKTC_ASSERT_ERR(r == 1);
150 	return cmd;
151 }
152 
153 static void
write_cmd(int fd,uint8_t cmd)154 write_cmd(int fd, uint8_t cmd)
155 {
156 	int w, error = 0;
157 
158 	w = write(fd, &cmd, sizeof(cmd));
159 	SKTC_ASSERT_ERR(w == 1);
160 }
161 
162 static void
wait_for_start(void)163 wait_for_start(void)
164 {
165 	write_cmd(MPTEST_SEQ_FILENO, 0);
166 	(void) read_cmd(MPTEST_SEQ_FILENO);
167 }
168 
169 static void
socket_test_status(char * name)170 socket_test_status(char *name)
171 {
172 	int i;
173 	double total_bytes = 0, total_expected;
174 
175 	total_expected = SOCKET_THREADS * SOCKET_BYTES;
176 	for (i = 0; i < SOCKET_THREADS; i++) {
177 		total_bytes += socket_thread_args[i].bytes;
178 	}
179 	SKD1("%s: %.2f%% complete\n", name,
180 	    (total_bytes * 100) / total_expected);
181 }
182 
183 static void
put_packet(channel_t ch,ring_id_t ring_id,packet_t pkt)184 put_packet(channel_t ch, ring_id_t ring_id, packet_t pkt)
185 {
186 	channel_ring_t tx_ring;
187 	channel_slot_t tx_slot = NULL;
188 	slot_prop_t prop;
189 	int error = 0;
190 
191 	tx_ring = os_channel_tx_ring(ch, ring_id);
192 	SKTC_ASSERT_ERR(tx_ring != NULL);
193 
194 	tx_slot = os_channel_get_next_slot(tx_ring, NULL, &prop);
195 	SKTC_ASSERT_ERR(tx_slot != NULL);
196 
197 	error = os_channel_slot_attach_packet(tx_ring, tx_slot, pkt);
198 	SKTC_ASSERT_ERR(error == 0);
199 
200 	error = os_channel_advance_slot(tx_ring, tx_slot);
201 	SKTC_ASSERT_ERR(error == 0);
202 }
203 
204 static int
get_packet(channel_t ch,ring_id_t r,packet_t * pktp)205 get_packet(channel_t ch, ring_id_t r, packet_t *pktp)
206 {
207 	int error = 0;
208 	slot_prop_t prop;
209 	channel_slot_t rx_slot, last_rx_slot = NULL;
210 	packet_t pkt;
211 	void *buf;
212 	buflet_t buflet;
213 	channel_ring_t rx_ring;
214 
215 	rx_ring = os_channel_rx_ring(ch, r);
216 	SKTC_ASSERT_ERR(rx_ring != NULL);
217 
218 	rx_slot = os_channel_get_next_slot(rx_ring, last_rx_slot, &prop);
219 	if (rx_slot == NULL) {
220 		return ENOENT;
221 	}
222 	SKTC_ASSERT_ERR(prop.sp_buf_ptr != 0);
223 
224 	pkt = os_channel_slot_get_packet(rx_ring, rx_slot);
225 	SKTC_ASSERT_ERR(pkt != 0);
226 
227 	error = os_channel_slot_detach_packet(rx_ring, rx_slot, pkt);
228 	SKTC_ASSERT_ERR(error == 0);
229 
230 	buflet = os_packet_get_next_buflet(pkt, NULL);
231 	SKTC_ASSERT_ERR(buflet != NULL);
232 
233 	buf = os_buflet_get_object_address(buflet);
234 	SKTC_ASSERT_ERR(buf != NULL);
235 
236 	last_rx_slot = rx_slot;
237 	error = os_channel_advance_slot(rx_ring, last_rx_slot);
238 	SKTC_ASSERT_ERR(error == 0);
239 
240 	*pktp = pkt;
241 	return 0;
242 }
243 
244 static void
custom_ether_build_packet(void * buf,custom_ether_args_t * args,size_t * len)245 custom_ether_build_packet(void *buf, custom_ether_args_t *args, size_t *len)
246 {
247 	if (!args->is_tagged) {
248 		ether_header_t *eh = buf;
249 
250 		bcopy(dst_mac_addr.octet, eh->ether_dhost, sizeof(ether_addr_t));
251 		bcopy(src_mac_addr.octet, eh->ether_shost, sizeof(ether_addr_t));
252 		eh->ether_type = htons(args->ethertype);
253 	} else {
254 		struct ether_vlan_header *evh = buf;
255 		uint16_t tag;
256 
257 		bcopy(dst_mac_addr.octet, evh->evl_dhost, sizeof(ether_addr_t));
258 		bcopy(src_mac_addr.octet, evh->evl_shost, sizeof(ether_addr_t));
259 		evh->evl_encap_proto = htons(ETHERTYPE_VLAN);
260 
261 		/* priority tag only */
262 		tag = args->priority << 13 & ~EVL_VLID_MASK;
263 		evh->evl_tag = htons(tag);
264 		evh->evl_proto = htons(args->ethertype);
265 	}
266 
267 	/*
268 	 * TODO:
269 	 * Put contents here to checked by the receiver
270 	 */
271 	*len = CUSTOM_ETHER_PKT_LEN;
272 }
273 
274 static void
custom_ether_send(channel_t ch,custom_ether_args_t * args)275 custom_ether_send(channel_t ch, custom_ether_args_t *args)
276 {
277 	packet_t pkt;
278 	void *buf;
279 	size_t pkt_len;
280 	buflet_t buflet;
281 	int error;
282 
283 	error = os_channel_packet_alloc(ch, &pkt);
284 	SKTC_ASSERT_ERR(error == 0);
285 
286 	buflet = os_packet_get_next_buflet(pkt, NULL);
287 	SKTC_ASSERT_ERR(buflet != NULL);
288 	buf = os_buflet_get_object_address(buflet);
289 	SKTC_ASSERT_ERR(buf != NULL);
290 
291 	custom_ether_build_packet(buf, args, &pkt_len);
292 
293 	error = os_buflet_set_data_length(buflet, pkt_len);
294 	SKTC_ASSERT_ERR(error == 0);
295 	error = os_packet_finalize(pkt);
296 	SKTC_ASSERT_ERR(error == 0);
297 
298 	put_packet(ch, 0, pkt);
299 
300 	error = os_channel_sync(ch, CHANNEL_SYNC_TX);
301 	SKTC_ASSERT_ERR(error == 0);
302 	args->sent++;
303 }
304 
305 static void
custom_ether_status(char * name,char * options)306 custom_ether_status(char *name, char *options)
307 {
308 	int i;
309 	custom_ether_args_t *args;
310 	double total_sent = 0, total_received = 0, total_expected;
311 
312 	total_expected = CUSTOM_ETHER_THREADS * CUSTOM_ETHER_ITERATIONS;
313 	for (i = 0; i < CUSTOM_ETHER_THREADS; i++) {
314 		args = &custom_ether_thread_args[i];
315 		total_sent += args->sent;
316 		total_received += args->received;
317 	}
318 	SKTDBG(name, options, "%.2f%% sent, %.2f%% received\n",
319 	    (total_sent * 100) / total_expected,
320 	    (total_received * 100) / total_expected);
321 }
322 
323 /*
324  * XXX
325  * This needs to be called outside of per-thread context because
326  * closing a channel could cause a pool flush which causes packet
327  * loss for unfinished threads who still have packets in flight.
328  */
329 static void
custom_ether_cleanup(void)330 custom_ether_cleanup(void)
331 {
332 	int i;
333 	custom_ether_args_t *args;
334 
335 	for (i = 0; i < CUSTOM_ETHER_THREADS; i++) {
336 		args = &custom_ether_thread_args[i];
337 
338 		if (args->ch != NULL) {
339 			os_channel_destroy(args->ch);
340 			args->ch = NULL;
341 		}
342 		if (args->nx_ncd != NULL) {
343 			os_nexus_controller_destroy(args->nx_ncd);
344 			args->nx_ncd = NULL;
345 		}
346 	}
347 	custom_ether_done = 0;
348 	custom_ether_ready = 0;
349 }
350 
351 static bool
custom_ether_verify(packet_t pkt,custom_ether_args_t * args)352 custom_ether_verify(packet_t pkt, custom_ether_args_t *args)
353 {
354 	buflet_t buflet;
355 	size_t len;
356 	void *buf;
357 	int error = 0;
358 
359 	buflet = os_packet_get_next_buflet(pkt, NULL);
360 	SKTC_ASSERT_ERR(buflet != NULL);
361 
362 	len = os_buflet_get_data_length(buflet);
363 	SKTC_ASSERT_ERR(len != 0);
364 
365 	buf = os_buflet_get_object_address(buflet) +
366 	    os_buflet_get_data_offset(buflet);
367 	SKTC_ASSERT_ERR(buf != NULL);
368 
369 	if (len != CUSTOM_ETHER_PKT_LEN) {
370 		SKD1("packet length mismatch: len %ld, expected %d\n",
371 		    len, CUSTOM_ETHER_PKT_LEN);
372 		return FALSE;
373 	}
374 	if (!args->is_tagged) {
375 		ether_header_t *eh = buf;
376 		uint16_t etype;
377 
378 		etype = ntohs(eh->ether_type);
379 		if (args->ethertype != etype) {
380 			SKD1("ethertype mismatch: 0x%x != 0x%x\n",
381 			    args->ethertype, etype);
382 			return FALSE;
383 		}
384 	} else {
385 		struct ether_vlan_header *evh = buf;
386 		boolean_t tag_in_pkt;
387 		uint16_t etype, evl_tag, tag;
388 		int err;
389 
390 		etype = ntohs(evh->evl_encap_proto);
391 		if (etype != ETHERTYPE_VLAN) {
392 			SKD1("received non-vlan packet: 0x%x", etype);
393 			return FALSE;
394 		}
395 		etype = ntohs(evh->evl_proto);
396 		if (args->ethertype != etype) {
397 			SKD1("ethertype mismatch: 0x%x != 0x%x\n",
398 			    args->ethertype, etype);
399 			return FALSE;
400 		}
401 		evl_tag = ntohs(evh->evl_tag);
402 
403 		/* vlan tag metadata is not expected for this test case */
404 		err = os_packet_get_vlan_tag(pkt, &tag, &tag_in_pkt);
405 		if (err == 0) {
406 			SKD1("tag not expected: 0x%x\n", tag);
407 			return FALSE;
408 		}
409 		if (EVL_PRIOFTAG(evl_tag) != args->priority) {
410 			SKD1("priority mismatch: 0x%x != 0x%x\n",
411 			    EVL_PRIOFTAG(evl_tag), args->priority);
412 			return FALSE;
413 		}
414 	}
415 	return TRUE;
416 }
417 
418 static void
custom_ether_receive(channel_t ch,custom_ether_args_t * args,packet_t pkt)419 custom_ether_receive(channel_t ch, custom_ether_args_t *args, packet_t pkt)
420 {
421 	bool valid;
422 
423 	valid = custom_ether_verify(pkt, args);
424 	assert(valid);
425 
426 	os_channel_packet_free(ch, pkt);
427 	args->received++;
428 }
429 
430 static void
custom_ether_setup_args(int index,bool sender,bool tagged)431 custom_ether_setup_args(int index, bool sender, bool tagged)
432 {
433 	custom_ether_args_t *args = &custom_ether_thread_args[index];
434 
435 	args->is_sender = sender;
436 	args->is_tagged = tagged;
437 	if (tagged) {
438 		args->priority = index % 7;
439 	}
440 	args->ethertype = CUSTOM_ETHER_ETHERTYPE_BASE + index;
441 	args->sent = 0;
442 	args->received = 0;
443 }
444 
445 static void
custom_ether_setup_flow(nexus_controller_t ncd,uuid_t uuid,custom_ether_args_t * args,nexus_port_t * nx_port,uuid_t bind_key)446 custom_ether_setup_flow(nexus_controller_t ncd, uuid_t uuid,
447     custom_ether_args_t *args, nexus_port_t *nx_port, uuid_t bind_key)
448 {
449 	struct nx_flow_req nfr;
450 	uuid_t flow_uuid;
451 	uuid_string_t uuidstr;
452 	int error;
453 
454 	uuid_generate(flow_uuid);
455 	bzero(&nfr, sizeof(nfr));
456 	uuid_copy(nfr.nfr_flow_uuid, flow_uuid);
457 	nfr.nfr_nx_port = NEXUS_PORT_ANY;
458 	nfr.nfr_ethertype = args->ethertype;
459 	nfr.nfr_flags |= NXFLOWREQF_CUSTOM_ETHER;
460 
461 	error = __os_nexus_flow_add(ncd, uuid, &nfr);
462 	SKTC_ASSERT_ERR(error == 0);
463 
464 	uuid_unparse(nfr.nfr_bind_key, uuidstr);
465 	uuid_copy(bind_key, nfr.nfr_bind_key);
466 	*nx_port = nfr.nfr_nx_port;
467 }
468 
469 static void
custom_ether_handler(channel_t ch,custom_ether_args_t * args)470 custom_ether_handler(channel_t ch, custom_ether_args_t *args)
471 {
472 	int error;
473 	packet_t pkt = 0;
474 
475 	error = get_packet(ch, 0, &pkt);
476 	assert(error == 0);
477 	custom_ether_receive(ch, args, pkt);
478 	if (args->sent < CUSTOM_ETHER_ITERATIONS) {
479 		custom_ether_send(ch, args);
480 	}
481 }
482 
483 static void
custom_ether_thread(custom_ether_args_t * args)484 custom_ether_thread(custom_ether_args_t *args)
485 {
486 	channel_attr_t ch_attr;
487 	channel_t ch;
488 	struct kevent evlist, kev[1];
489 	nexus_controller_t nx_ncd;
490 	nexus_port_t nx_port;
491 	uuid_t bind_key;
492 	int kq, ch_fd, error = 0;
493 
494 	nx_ncd = os_nexus_controller_create();
495 	SKTC_ASSERT_ERR(nx_ncd != NULL);
496 	args->nx_ncd = nx_ncd;
497 
498 	custom_ether_setup_flow(nx_ncd, if_uuid, args,
499 	    &nx_port, bind_key);
500 
501 	ch_attr = os_channel_attr_create();
502 	error = os_channel_attr_set_key(ch_attr, bind_key, sizeof(bind_key));
503 	SKTC_ASSERT_ERR(error == 0);
504 	error = os_channel_attr_set(ch_attr, CHANNEL_ATTR_USER_PACKET_POOL, 1);
505 	SKTC_ASSERT_ERR(error == 0);
506 
507 	ch = os_channel_create_extended(if_uuid, nx_port, CHANNEL_DIR_TX_RX,
508 	    CHANNEL_RING_ID_ANY, ch_attr);
509 	SKTC_ASSERT_ERR(ch != NULL);
510 	args->ch = ch;
511 
512 	kq = kqueue();
513 	SKTC_ASSERT_ERR(kq != -1);
514 
515 	ch_fd = os_channel_get_fd(ch);
516 	EV_SET(&kev[0], ch_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
517 	error = kevent(kq, kev, 1, NULL, 0, NULL);
518 	SKTC_ASSERT_ERR(error == 0);
519 
520 	/* Increment this count to tell the main thread that we are ready */
521 	if (args->is_sender) {
522 		/* send one packet to start the test */
523 		custom_ether_send(ch, args);
524 	}
525 	(void) OSAtomicIncrement32(&custom_ether_ready);
526 	for (;;) {
527 		/* Wait for RX events */
528 		error = kevent(kq, NULL, 0, &evlist, 1, NULL);
529 		SKTC_ASSERT_ERR(error == 1);
530 		if (evlist.filter == EVFILT_READ) {
531 			custom_ether_handler(ch, args);
532 		}
533 		if (args->sent == CUSTOM_ETHER_ITERATIONS &&
534 		    args->received == CUSTOM_ETHER_ITERATIONS) {
535 			break;
536 		}
537 	}
538 	(void) OSAtomicIncrement32(&custom_ether_done);
539 }
540 
541 /*
542  ****************************************************************
543  *                 End of common section                      *
544  ****************************************************************
545  */
546 
547 /*
548  ****************************************************************
549  *                 Start of filter section                      *
550  ****************************************************************
551  */
552 #define FILTER_THREADS 8
553 static int recv_server_fd = -1;
554 static int send_server_fd = -1;
555 static int recv_client_fd = -1;
556 static int send_client_fd = -1;
557 static int32_t filter_ready = 0;
558 
559 static void
filter_server_setup(uint16_t port,int * server_fd)560 filter_server_setup(uint16_t port, int *server_fd)
561 {
562 	struct sockaddr_in sin;
563 	int fd, flags, error = 0, on = 1;
564 
565 	fd = socket(AF_INET, SOCK_STREAM, 0);
566 	SKTC_ASSERT_ERR(fd != -1);
567 
568 	error = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
569 	SKTC_ASSERT_ERR(error == 0);
570 
571 	sin.sin_family = AF_INET;
572 	sin.sin_addr.s_addr = INADDR_ANY;
573 	sin.sin_port = htons(port);
574 	error = bind(fd, (struct sockaddr *)&sin, sizeof(sin));
575 	SKTC_ASSERT_ERR(error == 0);
576 
577 	error = listen(fd, 1);
578 	SKTC_ASSERT_ERR(error == 0);
579 
580 	flags = fcntl(fd, F_GETFL, 0);
581 	SKTC_ASSERT_ERR(flags != -1);
582 
583 	error = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
584 	SKTC_ASSERT_ERR(error != -1);
585 
586 	*server_fd = fd;
587 }
588 
589 static void
filter_channel_setup(void)590 filter_channel_setup(void)
591 {
592 	bool r;
593 
594 	/* Get the interface uuid we will be adding filters to */
595 	r = sktc_get_netif_nexus(FETH0_NAME, if_uuid);
596 	assert(r);
597 }
598 
599 static void
filter_setup(void)600 filter_setup(void)
601 {
602 	filter_server_setup(FILTER_RECV_PORT, &recv_server_fd);
603 	filter_server_setup(FILTER_SEND_PORT, &send_server_fd);
604 	filter_channel_setup();
605 }
606 
607 static void
filter_wait_for_clients(void)608 filter_wait_for_clients(void)
609 {
610 	fd_set server_fds;
611 	struct sockaddr_in r, s;
612 	socklen_t sz;
613 	int error = 0, maxfd;
614 
615 	SKD1("filter: waiting for clients\n");
616 	assert(recv_server_fd != -1);
617 	assert(send_server_fd != -1);
618 	maxfd = (send_server_fd > recv_server_fd) ? send_server_fd :
619 	    recv_server_fd;
620 
621 	for (;;) {
622 		FD_ZERO(&server_fds);
623 		if (recv_client_fd == -1) {
624 			FD_SET(recv_server_fd, &server_fds);
625 		}
626 		if (send_client_fd == -1) {
627 			FD_SET(send_server_fd, &server_fds);
628 		}
629 
630 		error = select(maxfd + 1, &server_fds, NULL, NULL, NULL);
631 		SKTC_ASSERT_ERR(error != -1);
632 
633 		if (FD_ISSET(recv_server_fd, &server_fds)) {
634 			sz = sizeof(r);
635 			recv_client_fd = accept(recv_server_fd,
636 			    (struct sockaddr *)&r, &sz);
637 			SKTC_ASSERT_ERR(recv_client_fd != -1);
638 			SKD1("filter: accepted receiver connection\n");
639 		} else if (FD_ISSET(send_server_fd, &server_fds)) {
640 			sz = sizeof(s);
641 			send_client_fd = accept(send_server_fd,
642 			    (struct sockaddr *)&s, &sz);
643 			SKTC_ASSERT_ERR(send_client_fd != -1);
644 			SKD1("filter: accepted sender connection\n");
645 		}
646 		if (recv_client_fd != -1 && send_client_fd != -1) {
647 			break;
648 		}
649 	}
650 	(void) close(recv_server_fd);
651 	(void) close(send_server_fd);
652 	recv_server_fd = -1;
653 	send_server_fd = -1;
654 }
655 
656 static void
process_recv_client_cmd(void)657 process_recv_client_cmd(void)
658 {
659 	uint8_t rcmd;
660 
661 	rcmd = read_cmd(recv_client_fd);
662 	switch (rcmd) {
663 	case CMD_RECV_SOCKET_READY: {
664 		SKD1("filter: receiver ready to start socket test\n");
665 
666 		/* Tell sender to start socket test */
667 		write_cmd(send_client_fd, CLIENT_CMD_SEND_SOCKET_START);
668 		break;
669 	}
670 	case CMD_RECV_CHANNEL_READY: {
671 		SKD1("filter: receiver ready to start channel test\n");
672 
673 		/* Tell sender to start channel test */
674 		write_cmd(send_client_fd, CLIENT_CMD_SEND_CHANNEL_START);
675 		break;
676 	}
677 	case CMD_RECV_ALL_DONE: {
678 		SKD1("filter: receiver finished all tests\n");
679 		exit(0);
680 	}
681 	default:
682 		SKD0("unknown command %d\n", rcmd);
683 		exit(1);
684 	}
685 }
686 
687 static void
process_send_client_cmd(void)688 process_send_client_cmd(void)
689 {
690 	/* nothing yet */
691 }
692 
693 static int
process_ring(channel_t ch,ring_id_t r)694 process_ring(channel_t ch, ring_id_t r)
695 {
696 	int error, cnt = 0;
697 	packet_t pkt = 0;
698 
699 	/*
700 	 * To be efficient, we process the full rx ring
701 	 * before calling tx sync.
702 	 */
703 	while ((error = get_packet(ch, r, &pkt)) == 0) {
704 		assert(pkt != 0);
705 		put_packet(ch, r, pkt);
706 		cnt++;
707 	}
708 	SKTC_ASSERT_ERR(error == ENOENT);
709 	if (cnt == 0) {
710 		return 0;
711 	}
712 
713 	error = os_channel_sync(ch, CHANNEL_SYNC_TX);
714 	SKTC_ASSERT_ERR(error == 0);
715 	/* rx sync is done internally next time we call kevent */
716 	return cnt;
717 }
718 
719 static void
filter_handler(channel_t ch)720 filter_handler(channel_t ch)
721 {
722 	int cnt = 0;
723 
724 	/*
725 	 * Filter packets could come in from both inbound/outbound
726 	 * directions. Check both RX rings.
727 	 */
728 	for (ring_id_t r = 0; r < 2; r++) {
729 		cnt += process_ring(ch, r);
730 	}
731 	if (cnt == 0) {
732 		SKD0("filter: spurious wakeup!!\n");
733 	}
734 }
735 
736 static void
filter_setup_flow(nexus_controller_t ncd,uuid_t uuid,nexus_port_t * nx_port,uuid_t bind_key)737 filter_setup_flow(nexus_controller_t ncd, uuid_t uuid,
738     nexus_port_t *nx_port, uuid_t bind_key)
739 {
740 	struct nx_flow_req nfr;
741 	uuid_t flow_uuid;
742 	uuid_string_t uuidstr;
743 	int error;
744 
745 	uuid_generate(flow_uuid);
746 	bzero(&nfr, sizeof(nfr));
747 	uuid_copy(nfr.nfr_flow_uuid, flow_uuid);
748 	nfr.nfr_nx_port = NEXUS_PORT_ANY;
749 	nfr.nfr_flags |= NXFLOWREQF_FILTER;
750 
751 	error = __os_nexus_flow_add(ncd, uuid, &nfr);
752 	SKTC_ASSERT_ERR(error == 0);
753 
754 	uuid_unparse(nfr.nfr_bind_key, uuidstr);
755 	uuid_copy(bind_key, nfr.nfr_bind_key);
756 	*nx_port = nfr.nfr_nx_port;
757 }
758 
759 static void *
filter_thread(void * unused)760 filter_thread(void *unused)
761 {
762 	channel_attr_t ch_attr;
763 	channel_t ch;
764 	struct kevent evlist, kev[1];
765 	nexus_controller_t nx_ncd;
766 	nexus_port_t nx_port;
767 	uuid_t bind_key;
768 	int kq, ch_fd, error = 0;
769 
770 	nx_ncd = os_nexus_controller_create();
771 	SKTC_ASSERT_ERR(nx_ncd != NULL);
772 	filter_setup_flow(nx_ncd, if_uuid, &nx_port, bind_key);
773 
774 	ch_attr = os_channel_attr_create();
775 	error = os_channel_attr_set_key(ch_attr, bind_key, sizeof(bind_key));
776 	SKTC_ASSERT_ERR(error == 0);
777 	error = os_channel_attr_set(ch_attr, CHANNEL_ATTR_USER_PACKET_POOL, 1);
778 	SKTC_ASSERT_ERR(error == 0);
779 	error = os_channel_attr_set(ch_attr, CHANNEL_ATTR_FILTER, 1);
780 	SKTC_ASSERT_ERR(error == 0);
781 
782 	ch = os_channel_create_extended(if_uuid, nx_port, CHANNEL_DIR_TX_RX,
783 	    CHANNEL_RING_ID_ANY, ch_attr);
784 	SKTC_ASSERT_ERR(ch != NULL);
785 
786 	kq = kqueue();
787 	SKTC_ASSERT_ERR(kq != -1);
788 
789 	ch_fd = os_channel_get_fd(ch);
790 	EV_SET(&kev[0], ch_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
791 	error = kevent(kq, kev, 1, NULL, 0, NULL);
792 	SKTC_ASSERT_ERR(error == 0);
793 
794 	/* Increment this count to tell the main thread that we are ready */
795 	(void) OSAtomicIncrement32(&filter_ready);
796 	for (;;) {
797 		/* Wait for RX events */
798 		error = kevent(kq, NULL, 0, &evlist, 1, NULL);
799 		SKTC_ASSERT_ERR(error == 1);
800 		if (evlist.filter == EVFILT_READ) {
801 			filter_handler(ch);
802 		}
803 	}
804 	return NULL;
805 }
806 
807 static void
filter_threads_start(void)808 filter_threads_start(void)
809 {
810 	int error, i;
811 	pthread_t t;
812 
813 	SKD1("filter: spawning filter threads\n");
814 	for (i = 0; i < FILTER_THREADS; i++) {
815 		error = pthread_create(&t, NULL, filter_thread, NULL);
816 		SKTC_ASSERT_ERR(error == 0);
817 	}
818 	for (;;) {
819 		SKD1("filter: %d threads ready\n", filter_ready);
820 		if (filter_ready == FILTER_THREADS) {
821 			break;
822 		} else {
823 			sleep(1);
824 		}
825 	}
826 }
827 
828 static void
filter_loop(void)829 filter_loop(void)
830 {
831 	fd_set client_fds;
832 	int maxfd;
833 
834 	assert(recv_client_fd != -1);
835 	assert(send_client_fd != -1);
836 	maxfd = (send_client_fd > recv_client_fd) ? send_client_fd :
837 	    recv_client_fd;
838 
839 	SKD1("filter: waiting for commands\n");
840 	for (;;) {
841 		FD_ZERO(&client_fds);
842 		FD_SET(recv_client_fd, &client_fds);
843 		FD_SET(send_client_fd, &client_fds);
844 
845 		if (select(maxfd + 1, &client_fds, NULL, NULL, NULL) < 0) {
846 			SKD0("filter: select failed: %d\n", errno);
847 			exit(1);
848 		}
849 		if (FD_ISSET(recv_client_fd, &client_fds)) {
850 			process_recv_client_cmd();
851 		} else if (FD_ISSET(send_client_fd, &client_fds)) {
852 			process_send_client_cmd();
853 		}
854 	}
855 }
856 
857 static void
filter(int testid)858 filter(int testid)
859 {
860 	SKD1("filter: start\n");
861 	filter_setup();
862 	filter_wait_for_clients();
863 	filter_threads_start();
864 	filter_loop();
865 }
866 /*
867  ****************************************************************
868  *                 End of filter section                        *
869  ****************************************************************
870  */
871 
872 /*
873  ****************************************************************
874  *                 Start of receiver section                    *
875  ****************************************************************
876  */
877 
878 /* Used for data transfer for the socket test case */
879 static int receiver_fd = -1;
880 
881 /* Used for sending commands to filter server */
882 static int receiver_client_fd = -1;
883 
884 static void
receiver_socket_setup(void)885 receiver_socket_setup(void)
886 {
887 	struct sockaddr_in sin;
888 	int fd, error = 0, on = 1;
889 
890 	fd = socket(AF_INET, SOCK_STREAM, 0);
891 	SKTC_ASSERT_ERR(fd != -1);
892 
893 	error = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
894 	SKTC_ASSERT_ERR(error == 0);
895 
896 	sin.sin_family = AF_INET;
897 	sin.sin_addr.s_addr = INADDR_ANY;
898 	sin.sin_port = htons(SOCKET_LISTENER_PORT);
899 	error = bind(fd, (struct sockaddr *)&sin, sizeof(sin));
900 	SKTC_ASSERT_ERR(error == 0);
901 
902 	error = listen(fd, SOCKET_THREADS);
903 	SKTC_ASSERT_ERR(error == 0);
904 	receiver_fd = fd;
905 }
906 
907 static void
receiver_channel_setup(void)908 receiver_channel_setup(void)
909 {
910 	int err;
911 	bool found;
912 
913 	/* receiver uses feth0 */
914 	found = sktc_get_netif_nexus(FETH0_NAME, if_uuid);
915 	assert(found);
916 	err = sktc_get_mac_addr(FETH0_NAME, src_mac_addr.octet);
917 	assert(err == 0);
918 	err = sktc_get_mac_addr(FETH1_NAME, dst_mac_addr.octet);
919 	assert(err == 0);
920 }
921 
922 static void
receiver_setup(void)923 receiver_setup(void)
924 {
925 	receiver_socket_setup();
926 	receiver_channel_setup();
927 }
928 
929 static void
receiver_connect_to_server(void)930 receiver_connect_to_server(void)
931 {
932 	connect_to_server(FILTER_RECV_PORT, &receiver_client_fd);
933 }
934 
935 static void *
receiver_socket_thread(void * arg)936 receiver_socket_thread(void *arg)
937 {
938 	socket_args_t *args = arg;
939 	int bytes, error = 0;
940 
941 	(void) OSAtomicIncrement32(&socket_ready);
942 	while (args->bytes < SOCKET_BYTES) {
943 		bytes = read(args->fd, databuf, sizeof(databuf));
944 		SKTC_ASSERT_ERR(bytes != -1);
945 		args->bytes += bytes;
946 	}
947 	(void) close(args->fd);
948 	(void) OSAtomicIncrement32(&socket_done);
949 	return NULL;
950 }
951 
952 static void
receiver_socket_start(void)953 receiver_socket_start(void)
954 {
955 	int i, fd, error = 0;
956 	socket_args_t *args;
957 	socklen_t sz;
958 	struct sockaddr_in sin;
959 	pthread_t t;
960 
961 	/*
962 	 * The sender can connect before we spawn our threads.
963 	 */
964 	write_cmd(receiver_client_fd, CMD_RECV_SOCKET_READY);
965 	SKD1("receiver: spawning socket threads\n");
966 	for (i = 0; i < SOCKET_THREADS; i++) {
967 		sz = sizeof(sin);
968 		fd = accept(receiver_fd, (struct sockaddr *)&sin, &sz);
969 		SKTC_ASSERT_ERR(fd != -1);
970 
971 		args = &socket_thread_args[i];
972 		args->fd = fd;
973 		args->bytes = 0;
974 		error = pthread_create(&t, NULL, receiver_socket_thread, args);
975 		SKTC_ASSERT_ERR(error == 0);
976 	}
977 	for (;;) {
978 		SKD1("receiver: %d socket threads ready\n", socket_ready);
979 		if (socket_ready == SOCKET_THREADS) {
980 			break;
981 		} else {
982 			sleep(1);
983 		}
984 	}
985 }
986 
987 static void
receiver_socket_wait(void)988 receiver_socket_wait(void)
989 {
990 	for (;;) {
991 		socket_test_status("receiver");
992 		if (socket_done == SOCKET_THREADS) {
993 			break;
994 		} else {
995 			sleep(1);
996 		}
997 	}
998 	(void) close(receiver_fd);
999 	receiver_fd = -1;
1000 }
1001 
1002 static void *
receiver_channel_thread(void * args)1003 receiver_channel_thread(void *args)
1004 {
1005 	custom_ether_thread(args);
1006 	return NULL;
1007 }
1008 
1009 static void
receiver_channel_start(char * name,char * options,bool tagged)1010 receiver_channel_start(char *name, char *options, bool tagged)
1011 {
1012 	int error, i;
1013 	pthread_t t;
1014 
1015 	SKTDBG(name, options, "spawning channel threads\n");
1016 	for (i = 0; i < CUSTOM_ETHER_THREADS; i++) {
1017 		custom_ether_setup_args(i, false, tagged);
1018 		error = pthread_create(&t, NULL, receiver_channel_thread,
1019 		    &custom_ether_thread_args[i]);
1020 		SKTC_ASSERT_ERR(error == 0);
1021 	}
1022 	for (;;) {
1023 		SKTDBG(name, options, "%d channel threads ready\n",
1024 		    custom_ether_ready);
1025 		if (custom_ether_ready == CUSTOM_ETHER_THREADS) {
1026 			break;
1027 		} else {
1028 			sleep(1);
1029 		}
1030 	}
1031 	/* Tell sender we're ready */
1032 	write_cmd(receiver_client_fd, CMD_RECV_CHANNEL_READY);
1033 }
1034 
1035 static void
receiver_channel_wait(char * name,char * options)1036 receiver_channel_wait(char *name, char *options)
1037 {
1038 	for (;;) {
1039 		custom_ether_status(name, options);
1040 		if (custom_ether_done == CUSTOM_ETHER_THREADS) {
1041 			break;
1042 		} else {
1043 			sleep(1);
1044 		}
1045 	}
1046 	SKTDBG(name, options, "%d threads done\n", custom_ether_done);
1047 	custom_ether_cleanup();
1048 }
1049 
1050 static void
receiver_custom_ether_test(char * name,char * options,bool tagged)1051 receiver_custom_ether_test(char *name, char *options, bool tagged)
1052 {
1053 	receiver_channel_start(name, options, tagged);
1054 	receiver_channel_wait(name, options);
1055 }
1056 
1057 static void
receiver_done(void)1058 receiver_done(void)
1059 {
1060 	write_cmd(receiver_client_fd, CMD_RECV_ALL_DONE);
1061 }
1062 
1063 static void
receiver_start(void)1064 receiver_start(void)
1065 {
1066 	receiver_socket_start();
1067 	receiver_socket_wait();
1068 	receiver_custom_ether_test("receiver", "", false);
1069 	receiver_custom_ether_test("receiver", "tagged", true);
1070 	receiver_done();
1071 }
1072 
1073 static void
receiver(int testid)1074 receiver(int testid)
1075 {
1076 	SKD1("receiver: start\n");
1077 	receiver_setup();
1078 	receiver_connect_to_server();
1079 	receiver_start();
1080 }
1081 
1082 /*
1083  ****************************************************************
1084  *                 End of receiver section                      *
1085  ****************************************************************
1086  */
1087 
1088 /*
1089  ****************************************************************
1090  *                 Start of sender section                      *
1091  ****************************************************************
1092  */
1093 
1094 /* Used for receiving commands from filter server */
1095 static int sender_client_fd = -1;
1096 
1097 static void
sender_socket_setup(void)1098 sender_socket_setup(void)
1099 {
1100 	/* nothing to do */
1101 }
1102 
1103 static void
sender_channel_setup(void)1104 sender_channel_setup(void)
1105 {
1106 	int err;
1107 	bool found;
1108 
1109 	/* sender uses feth1 */
1110 	found = sktc_get_netif_nexus(FETH1_NAME, if_uuid);
1111 	assert(found);
1112 	err = sktc_get_mac_addr(FETH1_NAME, src_mac_addr.octet);
1113 	assert(err == 0);
1114 	err = sktc_get_mac_addr(FETH0_NAME, dst_mac_addr.octet);
1115 	assert(err == 0);
1116 }
1117 
1118 static void
sender_setup(void)1119 sender_setup(void)
1120 {
1121 	sender_socket_setup();
1122 	sender_channel_setup();
1123 }
1124 
1125 static void
sender_connect_to_server(void)1126 sender_connect_to_server(void)
1127 {
1128 	connect_to_server(FILTER_SEND_PORT, &sender_client_fd);
1129 }
1130 
1131 static void *
sender_socket_thread(void * arg)1132 sender_socket_thread(void *arg)
1133 {
1134 	socket_args_t *args = arg;
1135 	struct sockaddr_in sin;
1136 	int fd, remain, bytes, ifscope, error = 0;
1137 
1138 	(void) OSAtomicIncrement32(&socket_ready);
1139 	fd = socket(AF_INET, SOCK_STREAM, 0);
1140 	SKTC_ASSERT_ERR(fd != -1);
1141 
1142 	/* must use feth1 as outgoing interface */
1143 	ifscope = if_nametoindex(FETH1_NAME);
1144 	assert(ifscope != 0);
1145 	error = setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &ifscope,
1146 	    sizeof(ifscope));
1147 	SKTC_ASSERT_ERR(error == 0);
1148 
1149 	/* connecting from feth1 to feth0 */
1150 	sin.sin_family = AF_INET;
1151 	sin.sin_addr = sktc_feth0_in_addr();
1152 	sin.sin_port = htons(SOCKET_LISTENER_PORT);
1153 	error = connect(fd, (struct sockaddr *)&sin, sizeof(sin));
1154 	SKTC_ASSERT_ERR(error == 0);
1155 
1156 	remain = SOCKET_BYTES;
1157 	while (remain > 0) {
1158 		bytes = MIN(remain, sizeof(databuf));
1159 		bytes = write(fd, databuf, bytes);
1160 		SKTC_ASSERT_ERR(bytes != -1);
1161 		remain -= bytes;
1162 		args->bytes += bytes;
1163 	}
1164 	(void) close(fd);
1165 	(void) OSAtomicIncrement32(&socket_done);
1166 	return NULL;
1167 }
1168 
1169 static void
sender_socket_start(void)1170 sender_socket_start(void)
1171 {
1172 	uint8_t cmd;
1173 	socket_args_t *args;
1174 	int i, error = 0;
1175 	pthread_t t;
1176 
1177 	/* wait for command from filter server */
1178 	SKD1("sender: waiting for socket start command\n");
1179 	cmd = read_cmd(sender_client_fd);
1180 	SKTC_ASSERT_ERR(cmd == CLIENT_CMD_SEND_SOCKET_START);
1181 
1182 	SKD1("sender: spawning socket threads\n");
1183 	for (i = 0; i < SOCKET_THREADS; i++) {
1184 		args = &socket_thread_args[i];
1185 		args->fd = -1;
1186 		args->bytes = 0;
1187 
1188 		error = pthread_create(&t, NULL, sender_socket_thread, args);
1189 		SKTC_ASSERT_ERR(error == 0);
1190 	}
1191 	for (;;) {
1192 		SKD1("sender: %d socket threads ready\n", socket_ready);
1193 		if (socket_ready == SOCKET_THREADS) {
1194 			break;
1195 		} else {
1196 			sleep(1);
1197 		}
1198 	}
1199 }
1200 
1201 static void
sender_socket_wait(void)1202 sender_socket_wait(void)
1203 {
1204 	for (;;) {
1205 		socket_test_status("sender");
1206 		if (socket_done == SOCKET_THREADS) {
1207 			break;
1208 		} else {
1209 			sleep(1);
1210 		}
1211 	}
1212 }
1213 
1214 static void *
sender_channel_thread(void * args)1215 sender_channel_thread(void *args)
1216 {
1217 	custom_ether_thread(args);
1218 	return NULL;
1219 }
1220 
1221 static void
sender_channel_start(char * name,char * options,bool tagged)1222 sender_channel_start(char *name, char *options, bool tagged)
1223 {
1224 	int error = 0, i;
1225 	pthread_t t;
1226 	uint8_t cmd;
1227 
1228 	/* wait for command from filter server */
1229 	SKTDBG(name, options, "waiting for channel start command\n");
1230 	cmd = read_cmd(sender_client_fd);
1231 	SKTC_ASSERT_ERR(cmd == CLIENT_CMD_SEND_CHANNEL_START);
1232 
1233 	SKTDBG(name, options, "spawning channel threads\n");
1234 	for (i = 0; i < CUSTOM_ETHER_THREADS; i++) {
1235 		custom_ether_setup_args(i, true, tagged);
1236 		error = pthread_create(&t, NULL, sender_channel_thread,
1237 		    &custom_ether_thread_args[i]);
1238 		SKTC_ASSERT_ERR(error == 0);
1239 	}
1240 	for (;;) {
1241 		SKTDBG(name, options, "%d channel threads ready\n",
1242 		    custom_ether_ready);
1243 		if (custom_ether_ready == CUSTOM_ETHER_THREADS) {
1244 			break;
1245 		} else {
1246 			sleep(1);
1247 		}
1248 	}
1249 }
1250 
1251 static void
sender_channel_wait(char * name,char * options)1252 sender_channel_wait(char *name, char *options)
1253 {
1254 	for (;;) {
1255 		custom_ether_status(name, options);
1256 		if (custom_ether_done == CUSTOM_ETHER_THREADS) {
1257 			break;
1258 		} else {
1259 			sleep(1);
1260 		}
1261 	}
1262 	SKTDBG(name, options, "%d threads done\n", custom_ether_done);
1263 	custom_ether_cleanup();
1264 }
1265 
1266 static void
sender_custom_ether_test(char * name,char * options,bool tagged)1267 sender_custom_ether_test(char *name, char *options, bool tagged)
1268 {
1269 	sender_channel_start(name, options, tagged);
1270 	sender_channel_wait(name, options);
1271 }
1272 
1273 static void
sender_start(void)1274 sender_start(void)
1275 {
1276 	sender_socket_start();
1277 	sender_socket_wait();
1278 	sender_custom_ether_test("sender", "", false);
1279 	sender_custom_ether_test("sender", "tagged", true);
1280 }
1281 
1282 static void
sender(int testid)1283 sender(int testid)
1284 {
1285 	SKD1("sender: start\n");
1286 	sender_setup();
1287 	sender_connect_to_server();
1288 	sender_start();
1289 }
1290 /*
1291  ****************************************************************
1292  *                 End of sender section                        *
1293  ****************************************************************
1294  */
1295 static int
skt_filter_main(int argc,char * argv[])1296 skt_filter_main(int argc, char *argv[])
1297 {
1298 	int child, test_id;
1299 
1300 	assert(!strcmp(argv[3], "--child"));
1301 	child = atoi(argv[4]);
1302 	test_id = 0;
1303 
1304 	wait_for_start();
1305 	if (child == 0) {
1306 		filter(test_id);
1307 	} else if (child == 1) {
1308 		receiver(test_id);
1309 	} else if (child == 2) {
1310 		sender(test_id);
1311 	}
1312 	return 0;
1313 }
1314 
1315 static bool
skt_filter_supported(void)1316 skt_filter_supported(void)
1317 {
1318 	uint32_t if_attach_nx;
1319 	size_t len = sizeof(if_attach_nx);
1320 	bool supported;
1321 
1322 	assert(sysctlbyname("net.link.generic.system.if_attach_nx",
1323 	    &if_attach_nx, &len, NULL, 0) == 0);
1324 
1325 	/* check for IF_ATTACH_NX_NETIF_NETAGENT */
1326 	supported = ((if_attach_nx & 0x08) != 0);
1327 	SKD1("test%ssupported, if_attach_nx=0x%x\n",
1328 	    supported ? " " : " not ", if_attach_nx);
1329 	return supported;
1330 }
1331 
1332 static uint32_t skt_netif_nxctl_check;
1333 static void
skt_filter_init(uint32_t flags)1334 skt_filter_init(uint32_t flags)
1335 {
1336 	uint32_t nxctl_check = 1;
1337 	size_t len = sizeof(skt_netif_nxctl_check);
1338 
1339 	assert(sysctlbyname("kern.skywalk.disable_nxctl_check",
1340 	    &skt_netif_nxctl_check, &len, &nxctl_check,
1341 	    sizeof(nxctl_check)) == 0);
1342 	sktc_ifnet_feth_pair_create(flags);
1343 }
1344 
1345 static void
skt_filter_fini(void)1346 skt_filter_fini(void)
1347 {
1348 	assert(sysctlbyname("kern.skywalk.disable_nxctl_check",
1349 	    NULL, NULL, &skt_netif_nxctl_check,
1350 	    sizeof(skt_netif_nxctl_check)) == 0);
1351 	sktc_ifnet_feth_pair_destroy();
1352 }
1353 
1354 static void
skt_filter_native_init(void)1355 skt_filter_native_init(void)
1356 {
1357 	skt_filter_init(FETH_FLAGS_NATIVE | FETH_FLAGS_NXATTACH);
1358 }
1359 
1360 static void
skt_filter_native_fini(void)1361 skt_filter_native_fini(void)
1362 {
1363 	skt_filter_fini();
1364 }
1365 
1366 static void
skt_filter_compat_init(void)1367 skt_filter_compat_init(void)
1368 {
1369 	skt_filter_init(FETH_FLAGS_TXSTART | FETH_FLAGS_NXATTACH);
1370 }
1371 
1372 static void
skt_filter_compat_fini(void)1373 skt_filter_compat_fini(void)
1374 {
1375 	skt_filter_fini();
1376 }
1377 
1378 #define NATIVE_TEST "filternative"
1379 #define COMPAT_TEST "filtercompat"
1380 struct skywalk_mptest skt_filternative = {
1381 	NATIVE_TEST,
1382 	"filter native test",
1383 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_DEV_OR_DEBUG,
1384 	3, skt_filter_main,
1385 	{ NULL, NULL, NULL, NULL, NULL, NULL},
1386 	skt_filter_native_init, skt_filter_native_fini, {},
1387 };
1388 
1389 struct skywalk_mptest skt_filtercompat = {
1390 	COMPAT_TEST,
1391 	"filter compat test",
1392 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_DEV_OR_DEBUG,
1393 	3, skt_filter_main,
1394 	{ NULL, NULL, NULL, NULL, NULL, NULL},
1395 	skt_filter_compat_init, skt_filter_compat_fini, {},
1396 };
1397 
1398 struct skywalk_mptest_check skt_filternative_check = {
1399 	NATIVE_TEST, skt_filter_supported,
1400 };
1401 
1402 struct skywalk_mptest_check skt_filtercompat_check = {
1403 	COMPAT_TEST, skt_filter_supported,
1404 };
1405