This is xnu-11215.1.10. See this file in:
/*
 * Copyright (c) 2019-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 <err.h>
#include <assert.h>
#include <errno.h>
#include <semaphore.h>
#include <stdio.h>
#include <spawn.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <sys/socket.h>
#include <uuid/uuid.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <darwintest.h>
#include "skywalk_test_driver.h"
#include "skywalk_test_utils.h"
#include "skywalk_test_common.h"

static const char * ifname;
static struct in_addr our_ip, dst_ip, zero_ip, nowhere_ip;
static struct in_addr our_mask;
static struct sktc_nexus_handles handles;

#define SEM_1ST_FLOW_CREATED "/skt_mpprotons_1FC"
#define SEM_2ND_FLOW_FAILED "/skt_mpprotons_2FF"

static void
skt_flow_req_should_succeed(sa_family_t af, void *src, void *dst,
    uint8_t protocol, uint16_t sport, uint16_t dport)
{
	struct sktu_flow *flow;

	flow = sktu_create_nexus_flow(&handles, af, src, dst, protocol, sport, dport);
	assert(flow);
}

static void
skt_flow_req_should_fail(sa_family_t af, void *src, void *dst,
    uint8_t protocol, uint16_t sport, uint16_t dport)
{
	struct sktu_flow *flow;

	flow = sktu_create_nexus_flow(&handles, af, src, dst, protocol, sport, dport);
	assert(!flow);
}

static int
skt_protons_main(int argc, char *argv[])
{
	ifname = FETH0_NAME;
	our_mask = sktc_make_in_addr(IN_CLASSC_NET);
	our_ip = sktc_feth0_in_addr();
	dst_ip = sktc_feth1_in_addr();
	zero_ip = (struct in_addr){.s_addr = htonl(INADDR_ANY)};
	nowhere_ip = sktc_nowhere_in_addr();

	bzero(&handles, sizeof(handles));
	strlcpy(handles.netif_ifname, ifname, sizeof(handles.netif_ifname));
	handles.netif_addr = our_ip;
	handles.netif_mask = our_mask;
	sktc_create_flowswitch_no_address(&handles, -1, -1, -1, -1, 0);

	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TCP, 0, 0);
	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_UDP, 0, 0);
	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 1, 0);
	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 0, 1);
	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 1, 1);
	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_RAW, 0, 0);

	skt_flow_req_should_succeed(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 0, 0);
	skt_flow_req_should_succeed(AF_INET, &our_ip, &nowhere_ip, IPPROTO_TTP, 0, 0);
	skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_TTP, 0, 0);

	sktc_cleanup_flowswitch(&handles);

	return 0;
}

static void
skt_protons_net_init(void)
{
	sktc_ifnet_feth_pair_create(FETH_FLAGS_TXSTART);
}

static void
skt_protons_net_fini(void)
{
	sktc_ifnet_feth_pair_destroy();

	// cleanup any leftovers
	sem_unlink(SEM_1ST_FLOW_CREATED);
	sem_unlink(SEM_2ND_FLOW_FAILED);
}

struct skywalk_test skt_protons = {
	.skt_testname = "protons",
	.skt_testdesc = "test skywalk protocol namespace",
	.skt_required_features = SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
	.skt_main = skt_protons_main,
	.skt_argv = { NULL },
	.skt_init = skt_protons_net_init,
	.skt_fini = skt_protons_net_fini,
};

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

static int
skt_mpprotons_main(int argc, char *argv[])
{
	char buf[1] = { 0 };
	const char * ifname;
	struct in_addr our_ip, peer_ip;
	struct in_addr our_mask;
	ssize_t ret;

	assert(!strcmp(argv[3], "--child"));
	int child = atoi(argv[4]);
	T_LOG("in child %d\n", child);

	if (child == 0) {
		ifname = FETH0_NAME;
		our_ip = sktc_feth0_in_addr();
		peer_ip = sktc_feth1_in_addr();
	} else {
		child = 1;
		ifname = FETH1_NAME;
		our_ip = sktc_feth1_in_addr();
		peer_ip = sktc_feth0_in_addr();
	}
	our_mask = sktc_make_in_addr(IN_CLASSC_NET);

	bzero(&handles, sizeof(handles));
	strlcpy(handles.netif_ifname, ifname, sizeof(handles.netif_ifname));
	handles.netif_addr = our_ip;
	handles.netif_mask = our_mask;
	sktc_create_flowswitch_no_address(&handles, -1, -1, -1, -1, 0);

	sem_t *sem_flow_created = sem_open(SEM_1ST_FLOW_CREATED, O_CREAT, 0660, 0);
	sem_t *sem_dup_flow_failed = sem_open(SEM_2ND_FLOW_FAILED, O_CREAT, 0660, 0);
	if (sem_flow_created == SEM_FAILED || sem_dup_flow_failed == SEM_FAILED) {
		err(EX_OSERR, "sem open failed");
	}

	if ((ret = write(MPTEST_SEQ_FILENO, buf, sizeof(buf))) == -1) {
		SKT_LOG("write fail: %s\n", strerror(errno));
		return 1;
	}
	assert(ret == 1);

	/* Wait for go signal */
	if ((ret = read(MPTEST_SEQ_FILENO, buf, sizeof(buf))) == -1) {
		SKT_LOG("read fail: %s\n", strerror(errno));
		return 1;
	}
	assert(ret == 1);

	if (child == 0) {
		skt_flow_req_should_succeed(AF_INET, &our_ip, &dst_ip, IPPROTO_IPEIP, 0, 0);
		sem_post(sem_flow_created);
		sem_wait(sem_dup_flow_failed);
		sem_post(sem_dup_flow_failed);
	}

	if (child == 1) {
		sem_wait(sem_flow_created);
		skt_flow_req_should_fail(AF_INET, &our_ip, &dst_ip, IPPROTO_IPEIP, 0, 0);
		sem_post(sem_flow_created);
		sem_post(sem_dup_flow_failed);
	}

	sem_close(sem_flow_created);
	sem_close(sem_dup_flow_failed);

	return 0;
}

struct skywalk_mptest skt_mpprotons = {
	.skt_testname = "mpprotons",
	.skt_testdesc = "test skywalk protocol namespace with two process doing conflicting reservation",
	.skt_required_features = SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NEXUS_FLOWSWITCH,
	.skt_nchildren = 2,
	.skt_main = skt_mpprotons_main,
	.skt_init = skt_protons_net_init,
	.skt_fini = skt_protons_net_fini,
};