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@
 */

#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 channel_t channel;
static uuid_t if_uuid;

static void
skt_netifcompat_common(void)
{
	int error;
	struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();

	strncpy((char *)attr.name, "skywalk_test_net_if",
	    sizeof(nexus_name_t) - 1);
	attr.type = NEXUS_TYPE_NET_IF;
	attr.anonymous = 1;
	attr.userchannel = 1;

	sktc_setup_nexus(&attr);

	channel = sktu_channel_create_extended(sktc_instance_uuid, NEXUS_PORT_NET_IF_HOST,
	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
	    -1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
	assert(!channel);

	channel = sktu_channel_create_extended(sktc_instance_uuid, NEXUS_PORT_NET_IF_DEV,
	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
	    -1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
	assert(!channel);

	uuid_generate_random(if_uuid);
	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    sktc_instance_uuid, if_uuid);
	SKTC_ASSERT_ERR(error == -1);
	SKT_LOG("error %d errno %d\n", error, errno);
	SKTC_ASSERT_ERR(errno == ESRCH);

	uuid_clear(if_uuid);
	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    sktc_instance_uuid, if_uuid);
	SKTC_ASSERT_ERR(error == -1);
	SKTC_ASSERT_ERR(errno == EINVAL);

	error = __os_nexus_ifattach(sktc_nexus_controller,
	    sktc_instance_uuid, FETH0_NAME, NULL, false, &if_uuid);
	SKTC_ASSERT_ERR(!error);

	channel = sktu_channel_create_extended(sktc_instance_uuid, NEXUS_PORT_NET_IF_DEV,
	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
	    -1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
	if (channel != NULL) {
		error = __os_nexus_ifdetach(sktc_nexus_controller,
		    sktc_instance_uuid, if_uuid);
		SKTC_ASSERT_ERR(error == -1);
		SKTC_ASSERT_ERR(errno == EBUSY);
	}
}

static int
skt_netifcompata_main(int argc, char *argv[])
{
	int error;

	skt_netifcompat_common();
	if (channel != NULL) {
		os_channel_destroy(channel);
	}

	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    sktc_instance_uuid, if_uuid);
	SKTC_ASSERT_ERR(!error);

	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    sktc_instance_uuid, if_uuid);
	SKTC_ASSERT_ERR(error == -1);
	SKTC_ASSERT_ERR(errno == ESRCH);

	sktc_cleanup_nexus();

	return 0;
}

static int
skt_netifcompatb_main(int argc, char *argv[])
{
	skt_netifcompat_common();

	sktc_cleanup_nexus();

	/* Skip detach since controller is closed */
	if (channel != NULL) {
		os_channel_destroy(channel);
	}

	return 0;
}

static int
skt_netifcompatc_main(int argc, char *argv[])
{
	int error;
	skt_netifcompat_common();

	/* This is the guts of sktc_cleanup_nexus() expanded here
	 * so that we can detach and close after we've freed the instance
	 */
	assert(sktc_nexus_controller);
	assert(!uuid_is_null(sktc_provider_uuid));
	assert(!uuid_is_null(sktc_instance_uuid));

	error = os_nexus_controller_free_provider_instance(sktc_nexus_controller,
	    sktc_instance_uuid);
	SKTC_ASSERT_ERR(!error);

	/* We've freed the provider, but there's a channel still open to it.
	 * We can then no longer detach it, is that correct?
	 */
	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    sktc_instance_uuid, if_uuid);
	if (channel != NULL) {
		SKTC_ASSERT_ERR(error == -1);
		SKTC_ASSERT_ERR(errno == ENOENT);
	}
	error = os_nexus_controller_deregister_provider(sktc_nexus_controller,
	    sktc_provider_uuid);
	SKTC_ASSERT_ERR(!error);

	os_nexus_controller_destroy(sktc_nexus_controller);
	sktc_nexus_controller = NULL;
	if (channel != NULL) {
		os_channel_destroy(channel);
	}

	return 0;
}

struct skywalk_test skt_netifcompata = {
	"netifcompata", "setup and teardown netifcompat on feth0",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF,
	skt_netifcompata_main, { NULL },
	sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
};

struct skywalk_test skt_netifcompatb = {
	"netifcompatb", "setup and teardown netifcompat on feth0 with deferred close channel",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF,
	skt_netifcompatb_main, { NULL },
	sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
};

struct skywalk_test skt_netifcompatc = {
	"netifcompatc", "setup and teardown netifcompat on feth0 with deferred detach and close channel",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF,
	skt_netifcompatc_main, { NULL },
	sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
};

/****************************************************************/

static void
skt_fsw_common(const char *name)
{
	int error;
	uuid_t ms_provider;
	uuid_t ms_instance;
	uuid_t ms_attach;
	uuid_t scratch;
	struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();

	strncpy((char *)attr.name, name, sizeof(nexus_name_t) - 1);
	attr.type = NEXUS_TYPE_FLOW_SWITCH;
	attr.anonymous = 1;

	skt_netifcompat_common();

	sktc_build_nexus(sktc_nexus_controller, &attr, &ms_provider,
	    &ms_instance);

	if (channel != NULL) {
		/*
		 * There is a channel open to the net-if dev port, so this
		 * attach will fail
		 */
		error = __os_nexus_ifattach(sktc_nexus_controller,
		    ms_instance, NULL, sktc_instance_uuid, false, &ms_attach);
		SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__,
		    error, errno);
		SKTC_ASSERT_ERR(error == -1);
		SKTC_ASSERT_ERR(errno == EBUSY);

		/* Close the channel so the attach will succeed */
		os_channel_destroy(channel);
	}
	error = __os_nexus_ifattach(sktc_nexus_controller,
	    ms_instance, NULL, sktc_instance_uuid, false, &ms_attach);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);

	uuid_clear(scratch);
	error = __os_nexus_ifattach(sktc_nexus_controller,
	    ms_instance, NULL, sktc_instance_uuid, false, &scratch);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(error == -1);
	SKTC_ASSERT_ERR(errno == EEXIST);
	assert(uuid_is_null(scratch));

	/*
	 * flowswitch doesn't allow opening a channel without a flow bound
	 * to the port.
	 */
	uuid_t flow_id;
	uuid_generate(flow_id);
	error = sktc_bind_tcp4_flow(sktc_nexus_controller, 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, 2,
	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
	    -1, -1, -1, -1, -1, -1, -1, 1, -1, -1) == NULL);

	/* Open and close channel to the flow switch */
	channel = sktu_channel_create_extended(ms_instance, 2,
	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
	    -1, -1, -1, -1, -1, -1, 1, 1, -1, -1);
	assert(channel);

	os_channel_destroy(channel);

	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    ms_instance, ms_attach);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);

	error = os_nexus_controller_free_provider_instance(sktc_nexus_controller,
	    ms_instance);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);
	uuid_clear(ms_instance);

	error = os_nexus_controller_deregister_provider(sktc_nexus_controller,
	    ms_provider);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);
	uuid_clear(ms_provider);

	sktc_cleanup_nexus();
}

static int
skt_netifms_main(int argc, char *argv[])
{
	skt_fsw_common("skywalk_test_fsw");
	return 0;
}

struct skywalk_test skt_netiffsw = {
	"netifms", "setup compat netif and attach to flowswitch",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
	SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
	skt_netifms_main, { NULL },
	sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
};

int
skt_netifdelete_main(int argc, char *argv[])
{
	uuid_t attach;
	int error;
	struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();

	strncpy((char *)attr.name, "skt_netifdelete_netif",
	    sizeof(nexus_name_t) - 1);
	attr.type = NEXUS_TYPE_NET_IF;
	attr.anonymous = 1;
	attr.userchannel = 1;

	sktc_ifnet_feth0_create();

	sktc_setup_nexus(&attr);

	error = __os_nexus_ifattach(sktc_nexus_controller,
	    sktc_instance_uuid, FETH0_NAME, NULL, false, &attach);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);

	sktc_ifnet_feth0_destroy();

	error = __os_nexus_ifdetach(sktc_nexus_controller,
	    sktc_instance_uuid, attach);
	SKT_LOG("%s:%d error %d errno %d\n", __func__, __LINE__, error, errno);
	SKTC_ASSERT_ERR(!error);

	sktc_cleanup_nexus();

	return 0;
}

struct skywalk_test skt_netifdelete = {
	"netifdelete", "tear down an ifp while it's attached to a netif",
	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF,
	skt_netifdelete_main,
};