This is xnu-11215.1.10. See this file in:
/*
 * Copyright (c) 2016-2024 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

/* This test sets up a complicated topology and then tears it down,
 * but allows us to completely permute the teardown sequence
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <darwintest.h>

#include "skywalk_test_common.h"
#include "skywalk_test_driver.h"
#include "skywalk_test_utils.h"

static int check_failures;
static int print_failures;
static int print_permutation;

/* this could share same logic as SKTC_ASSERT_ERR() */
#define checkerr() do { \
	        if (print_failures && error) {                                                                                                                                                  \
	                SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno); \
	        }                                                                                                                                                                                                                                                                               \
	        if (check_failures) {                                                                                                                                                                                           \
	                assert(!error);                                                                                                                                                                                                         \
	        }                                                                                                                                                                                                                                                                               \
	} while (0)

static void
skt_teardown_pass(int count, int *permute)
{
	int error;
	nexus_controller_t ncd;
	uuid_t feth0_attach, feth1_attach;
	uuid_t ms_provider, ms_instance;
	uuid_t nf_provider, nf_instance0, nf_attach0, nf_instance1, nf_attach1;
	channel_t channel;
	uuid_t flow_id;
	struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();

	if (print_permutation) {
		static int p = 0;
		T_LOG("permute = {");
		for (int i = 0; i < count; i++) {
			T_LOG(" %d,", permute[i]);
		}
		T_LOG("} (%d)\n", p++);
	}

	uuid_clear(feth0_attach);
	uuid_clear(feth1_attach);
	uuid_clear(ms_provider);
	uuid_clear(ms_instance);
	uuid_clear(nf_provider);
	uuid_clear(nf_instance0);
	uuid_clear(nf_attach0);
	uuid_clear(nf_instance1);
	uuid_clear(nf_attach1);

	ncd = os_nexus_controller_create();
	assert(ncd);

	strncpy((char *)attr.name, "skt_teardown_netif",
	    sizeof(nexus_name_t) - 1);
	attr.type = NEXUS_TYPE_NET_IF;
	attr.anonymous = 1;
	sktc_build_nexus(ncd, &attr, &nf_provider, &nf_instance0);

	uuid_clear(feth0_attach);
	error = __os_nexus_ifattach(ncd, nf_instance0, FETH0_NAME, NULL, false, &feth0_attach);
	//T_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);
	assert(!uuid_is_null(feth0_attach));

	uuid_clear(nf_instance1);
	error = os_nexus_controller_alloc_provider_instance(ncd,
	    nf_provider, &nf_instance1);
	SKTC_ASSERT_ERR(!error);
	assert(!uuid_is_null(nf_instance1));

	uuid_clear(feth1_attach);
	error = __os_nexus_ifattach(ncd, nf_instance1, FETH1_NAME, NULL, false, &feth1_attach);
	SKTC_ASSERT_ERR(!error);
	assert(!uuid_is_null(feth1_attach));

	strncpy((char *)attr.name, "skt_teardown_flowswitch",
	    sizeof(nexus_name_t) - 1);
	attr.type = NEXUS_TYPE_FLOW_SWITCH;
	sktc_build_nexus(ncd, &attr, &ms_provider, &ms_instance);

	uuid_clear(nf_attach0);
	error = __os_nexus_ifattach(ncd, ms_instance, NULL, nf_instance0, false, &nf_attach0);
	//T_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);
	assert(!uuid_is_null(nf_attach0));

	/*
	 * flowswitch doesn't allow opening a channel without a flow bound
	 * to the port.
	 */
	uuid_generate(flow_id);
	error = sktc_bind_tcp4_flow(ncd, ms_instance, 0,
	    NEXUS_PORT_FLOW_SWITCH_CLIENT, flow_id);
	SKTC_ASSERT_ERR(error == 0);

	/* must fail without user packet pool set (flow switch) */
	assert(sktu_channel_create_extended(ms_instance,
	    NEXUS_PORT_FLOW_SWITCH_CLIENT, CHANNEL_DIR_TX_RX,
	    CHANNEL_RING_ID_ANY, NULL, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1) == NULL);

	channel = sktu_channel_create_extended(ms_instance,
	    NEXUS_PORT_FLOW_SWITCH_CLIENT, CHANNEL_DIR_TX_RX,
	    CHANNEL_RING_ID_ANY, NULL, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1);
	assert(channel);

	/* Allow us to permute teardown steps */
	for (int i = 0; i < count; i++) {
		//T_LOG("Count %d step %d\n", i, permute[i]);
		switch (permute[i]) {
		case 8: {
			if (channel) {
				os_channel_destroy(channel);
				channel = NULL;
			}
		} break;
		case 7: {
			error = __os_nexus_ifdetach(ncd, ms_instance, nf_attach0);
			checkerr();
		} break;
		case 6: {
			error = os_nexus_controller_free_provider_instance(ncd, ms_instance);
			checkerr();
		} break;
		case 5: {
			error = os_nexus_controller_deregister_provider(ncd, ms_provider);
			checkerr();
		} break;
		case 4: {
			error = __os_nexus_ifdetach(ncd, nf_instance1, feth1_attach);
			checkerr();
		} break;
		case 3: {
			error = os_nexus_controller_free_provider_instance(ncd, nf_instance1);
			checkerr();
		} break;
		case 2: {
			error = __os_nexus_ifdetach(ncd, nf_instance0, feth0_attach);
			checkerr();
		} break;
		case 1: {
			error = os_nexus_controller_free_provider_instance(ncd, nf_instance0);
			checkerr();
		} break;
		case 0: {
			error = os_nexus_controller_deregister_provider(ncd, nf_provider);
			checkerr();
		} break;
		default:
			assert(0);
		}
	}

	os_nexus_controller_destroy(ncd);
}

static int
skt_teardown_main(int argc, char *argv[])
{
	int permute[9];
	for (int i = 0; i < 9; i++) {
		permute[i] = 8 - i;
	}
	check_failures = 1;
	print_permutation = 1;
	skt_teardown_pass(9, permute);
	return 0;
}

static int
skt_teardownb_main(int argc, char *argv[])
{
	int permute[9];
	for (int i = 0; i < 9; i++) {
		permute[i] = i;
	}
	print_permutation = 1;
	skt_teardown_pass(9, permute);
	return 0;
}

static int
skt_teardownr_main(int argc, char *argv[])
{
	int permute[9];
	for (int i = 0; i < 9; i++) {
		permute[i] = 8 - i;
	}
	//print_permutation = 1;
	permutefuncR(9, permute, skt_teardown_pass, 1000, 0);
	return 0;
}

static int
skt_teardownz_main(int argc, char *argv[])
{
	int permute[9];
	for (int i = 0; i < 9; i++) {
		permute[i] = 8 - i;
	}
	//print_permutation = 1;
	//print_failures = 1;
	permutefuncZ(9, permute, skt_teardown_pass);
	return 0;
}

struct skywalk_test skt_teardown = {
	"teardown", "setup complicated topology tear it down",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
	SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
	skt_teardown_main, { NULL },
	sktc_ifnet_feth0_1_create, sktc_ifnet_feth0_1_destroy,
};

struct skywalk_test skt_teardownb = {
	"teardownb", "setup complicated topology tear it down backwards",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
	SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
	skt_teardownb_main, { NULL },
	sktc_ifnet_feth0_1_create, sktc_ifnet_feth0_1_destroy,
};

struct skywalk_test skt_teardownr = {
	"teardownr", "setup complicated topology tear it down randomly (1000 iterations)",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
	SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
	skt_teardownr_main, { NULL },
	sktc_ifnet_feth0_1_create, sktc_ifnet_feth0_1_destroy,
};

struct skywalk_test skt_teardownz = {
	"teardownz", "setup complicated topology tear it down with each stage in an out of order position",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
	SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
	skt_teardownz_main, { NULL },
	sktc_ifnet_feth0_1_create, sktc_ifnet_feth0_1_destroy,
};