<commit_before>/* Copyright (c) 2017, Nokia
 * Copyright (c) 2017, ENEA Software AB
 * All rights reserved.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 */

#include <getopt.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <odp_api.h>
#include <ofp.h>
#include <ofpi.h>

/*
 * IPv4 UDP, destination port 65000.
 */
uint8_t frame[64] = {
0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00,
0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x45, 0x00,
0x00, 0x32, 0xb9, 0x12, 0x40, 0x00, 0x40, 0x11,
0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x0a, 0x00,
0x00, 0x02, 0xb7, 0x8a, 0xfd, 0xe8, 0x00, 0x1e,
0x2e, 0xe6, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x0a,
};

struct ODP_ALIGNED_CACHE tstate_s {
	volatile uint64_t packets;
	volatile odp_time_t time;
	volatile int stop;
} tstate[OFP_MAX_NUM_CPU];

#define STR(x) #x
#define ASSERT(x)						\
	do {							\
		if (!(x)) {					\
			printf(__FILE__ "(%d): assert failed: "	\
			       STR(x) "\n", __LINE__);		\
			exit(1);				\
		}						\
	} while (0)

odp_instance_t instance;
struct ofp_ifnet *ifnet;
odp_queue_t dummyq;
odp_pool_t pool;
odp_spinlock_t lock;

#define C_PORT 0
#define C_VLAN 0
#define C_VRF 0
#define C_TTL 64
#define C_L_ADDR 0x7d000000
#define C_GW_ADDR 0x7e000000
#define C_SRC_ADDR 0x7c000000
#define C_DST_ADDR 0x1000000

const uint8_t ether_dhost[OFP_ETHER_ADDR_LEN] = {0xa, 0xb, 0, 0, 0, 0};

struct arg_s {
	volatile uint32_t batch, dispw, interval, ivals, loglevel, masklen,
		neighbor_bits, route_bits, tx_burst, verify, warmup, workers;
} arg, default_arg = {
	.batch = 64,
	.dispw = 0,
	.interval = 5000,
	.ivals = 1,
	.loglevel = OFP_LOG_ERROR,
	.masklen = 24,
	.neighbor_bits = 0,
	.route_bits = 0,
	.tx_burst = 8,
	.verify = 0,
	.warmup = 5,
	.workers = 1,
};



uint32_t addr_mask = ~0U;
__thread unsigned int seedp;

static inline uint32_t dst_addr(void)
{
	return odp_cpu_to_be_32(C_DST_ADDR + ((uint32_t)rand_r(&seedp) & addr_mask));
}



static void *worker(void *p)
{
	(void)p;

	ASSERT(!odp_init_local(instance, ODP_THREAD_WORKER));
	ASSERT(!ofp_init_local());

	int cpuid = odp_cpu_id(), res;
	odp_packet_t burst[arg.batch];
	odp_event_t ev[arg.batch];
	uint32_t c;
	uint16_t cksum_base = 0;

	seedp = cpuid + 1;

	/*
	 * Use a lock around packet allocation so that each thread
	 * gets consecutive packets from the pool.
	 */
	odp_spinlock_lock(&lock);

	for (c = 0; c < arg.batch; c++) {
		odp_packet_t pkt = odp_packet_alloc(pool, sizeof(frame));
		ASSERT(pkt != ODP_PACKET_INVALID);

		uint8_t *buf = odp_packet_data(pkt);
		memcpy(buf, frame, sizeof(frame));

		struct ofp_ip *ip = (struct ofp_ip *)(buf + OFP_ETHER_HDR_LEN);
		ip->ip_src.s_addr = C_SRC_ADDR;
		ip->ip_ttl = C_TTL;
		ip->ip_sum = 0;
		if (!c) {
			ip->ip_dst.s_addr = 0;
			cksum_base = ofp_cksum_buffer((uint16_t *)ip, ip->ip_hl<<2);
		}
		ip->ip_dst.s_addr = dst_addr();
		ip->ip_sum = ofp_cksum_buffer((uint16_t *)ip, ip->ip_hl<<2);
		odp_packet_has_eth_set(pkt, 1);
		odp_packet_has_ipv4_set(pkt, 1);
		odp_packet_l2_offset_set(pkt, 0);
		odp_packet_l3_offset_set(pkt, OFP_ETHER_HDR_LEN);
		odp_packet_l4_offset_set(pkt, OFP_ETHER_HDR_LEN + (ip->ip_hl<<2));

		ASSERT(ofp_packet_input(pkt, dummyq, ofp_eth_vlan_processing) == OFP_PKT_PROCESSED);

		tstate[cpuid].packets++;
	}

	odp_spinlock_unlock(&lock);

	res = ofp_send_pending_pkt();
	/*
	 * In order to get packets back on the same worker, the
	 * following must match the queue selection in
	 * ofp_send_pkt_multi().
	 */
	odp_queue_t outq = ifnet->out_queue_queue[cpuid % ifnet->out_queue_num];

	while (1) {
		uint32_t num = 0;

		while (num < arg.batch) {
			res = odp_queue_deq_multi(outq, &ev[num], arg.batch-num);
			if (res < 0) break;
			num += res;
		}

		if (arg.verify) {
			for (c = 0; c < num; c++) {
				odp_packet_t pkt = odp_packet_from_event(ev[c]);
				struct ofp_ether_header *eth =
					(struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);
				struct ofp_ip *ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL);

				ASSERT(ip->ip_ttl == C_TTL-1);
				ASSERT(eth->ether_dhost[0] == ether_dhost[0] &&
				       eth->ether_dhost[1] == ether_dhost[1] &&
				       eth->ether_dhost[2] == (C_GW_ADDR>>24));
			}
		}

		for (c = 0; c < num; c++) {
			odp_packet_t pkt = burst[c] = odp_packet_from_event(ev[c]);
			uint8_t *buf = odp_packet_data(pkt);
			struct ofp_ether_header *eth =
				(struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);
			struct ofp_ip *ip = (struct ofp_ip *)(buf + OFP_ETHER_HDR_LEN);

			memset(eth->ether_dhost, 0, sizeof(eth->ether_dhost));
			ip->ip_ttl = C_TTL;
			ip->ip_dst.s_addr = dst_addr();
			uint32_t cksum = odp_be_to_cpu_16(~cksum_base);
			cksum += odp_be_to_cpu_16(ip->ip_dst.s_addr&0xffff);
			cksum += odp_be_to_cpu_16(ip->ip_dst.s_addr>>16);
			cksum = (cksum & 0xffff) + (cksum >> 16);
			ip->ip_sum = odp_cpu_to_be_16(~cksum);
		}

		if (tstate[cpuid].stop) {
			for (c = 0; c < num; c++)
				odp_packet_free(burst[c]);
			break;
		}

		odp_time_t start = odp_time_global();

		for (c = 0; c < num; c++)
			ASSERT(ofp_packet_input(burst[c], dummyq, ofp_eth_vlan_processing) == OFP_PKT_PROCESSED);

		res = ofp_send_pending_pkt();

		tstate[cpuid].time = odp_time_sum(tstate[cpuid].time, odp_time_diff(odp_time_global(), start));
		tstate[cpuid].packets += num;
	}

	return NULL;
}



static void usage(const char *prog)
{
	printf("\nUsage: %s [options]\n\n"<commit_msg>test/benchmark/ipv4_fwd: Call odp_be_to_cpu_16(~cksum) only once.<commit_after>/* Copyright (c) 2017, Nokia
 * Copyright (c) 2017, ENEA Software AB
 * All rights reserved.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 */

#include <getopt.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <odp_api.h>
#include <ofp.h>
#include <ofpi.h>

/*
 * IPv4 UDP, destination port 65000.
 */
uint8_t frame[64] = {
0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00,
0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x45, 0x00,
0x00, 0x32, 0xb9, 0x12, 0x40, 0x00, 0x40, 0x11,
0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x0a, 0x00,
0x00, 0x02, 0xb7, 0x8a, 0xfd, 0xe8, 0x00, 0x1e,
0x2e, 0xe6, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x0a,
};

struct ODP_ALIGNED_CACHE tstate_s {
	volatile uint64_t packets;
	volatile odp_time_t time;
	volatile int stop;
} tstate[OFP_MAX_NUM_CPU];

#define STR(x) #x
#define ASSERT(x)						\
	do {							\
		if (!(x)) {					\
			printf(__FILE__ "(%d): assert failed: "	\
			       STR(x) "\n", __LINE__);		\
			exit(1);				\
		}						\
	} while (0)

odp_instance_t instance;
struct ofp_ifnet *ifnet;
odp_queue_t dummyq;
odp_pool_t pool;
odp_spinlock_t lock;

#define C_PORT 0
#define C_VLAN 0
#define C_VRF 0
#define C_TTL 64
#define C_L_ADDR 0x7d000000
#define C_GW_ADDR 0x7e000000
#define C_SRC_ADDR 0x7c000000
#define C_DST_ADDR 0x1000000

const uint8_t ether_dhost[OFP_ETHER_ADDR_LEN] = {0xa, 0xb, 0, 0, 0, 0};

struct arg_s {
	volatile uint32_t batch, dispw, interval, ivals, loglevel, masklen,
		neighbor_bits, route_bits, tx_burst, verify, warmup, workers;
} arg, default_arg = {
	.batch = 64,
	.dispw = 0,
	.interval = 5000,
	.ivals = 1,
	.loglevel = OFP_LOG_ERROR,
	.masklen = 24,
	.neighbor_bits = 0,
	.route_bits = 0,
	.tx_burst = 8,
	.verify = 0,
	.warmup = 5,
	.workers = 1,
};



uint32_t addr_mask = ~0U;
__thread unsigned int seedp;

static inline uint32_t dst_addr(void)
{
	return odp_cpu_to_be_32(C_DST_ADDR + ((uint32_t)rand_r(&seedp) & addr_mask));
}



static void *worker(void *p)
{
	(void)p;

	ASSERT(!odp_init_local(instance, ODP_THREAD_WORKER));
	ASSERT(!ofp_init_local());

	int cpuid = odp_cpu_id(), res;
	odp_packet_t burst[arg.batch];
	odp_event_t ev[arg.batch];
	uint32_t c;
	uint16_t cksum_base = 0;

	seedp = cpuid + 1;

	/*
	 * Use a lock around packet allocation so that each thread
	 * gets consecutive packets from the pool.
	 */
	odp_spinlock_lock(&lock);

	for (c = 0; c < arg.batch; c++) {
		odp_packet_t pkt = odp_packet_alloc(pool, sizeof(frame));
		ASSERT(pkt != ODP_PACKET_INVALID);

		uint8_t *buf = odp_packet_data(pkt);
		memcpy(buf, frame, sizeof(frame));

		struct ofp_ip *ip = (struct ofp_ip *)(buf + OFP_ETHER_HDR_LEN);
		ip->ip_src.s_addr = C_SRC_ADDR;
		ip->ip_ttl = C_TTL;
		ip->ip_sum = 0;
		if (!c) {
			ip->ip_dst.s_addr = 0;
			cksum_base = odp_be_to_cpu_16(~ofp_cksum_buffer((uint16_t *)ip, ip->ip_hl<<2));
		}
		ip->ip_dst.s_addr = dst_addr();
		ip->ip_sum = ofp_cksum_buffer((uint16_t *)ip, ip->ip_hl<<2);
		odp_packet_has_eth_set(pkt, 1);
		odp_packet_has_ipv4_set(pkt, 1);
		odp_packet_l2_offset_set(pkt, 0);
		odp_packet_l3_offset_set(pkt, OFP_ETHER_HDR_LEN);
		odp_packet_l4_offset_set(pkt, OFP_ETHER_HDR_LEN + (ip->ip_hl<<2));

		ASSERT(ofp_packet_input(pkt, dummyq, ofp_eth_vlan_processing) == OFP_PKT_PROCESSED);

		tstate[cpuid].packets++;
	}

	odp_spinlock_unlock(&lock);

	res = ofp_send_pending_pkt();
	/*
	 * In order to get packets back on the same worker, the
	 * following must match the queue selection in
	 * ofp_send_pkt_multi().
	 */
	odp_queue_t outq = ifnet->out_queue_queue[cpuid % ifnet->out_queue_num];

	while (1) {
		uint32_t num = 0;

		while (num < arg.batch) {
			res = odp_queue_deq_multi(outq, &ev[num], arg.batch-num);
			if (res < 0) break;
			num += res;
		}

		if (arg.verify) {
			for (c = 0; c < num; c++) {
				odp_packet_t pkt = odp_packet_from_event(ev[c]);
				struct ofp_ether_header *eth =
					(struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);
				struct ofp_ip *ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL);

				ASSERT(ip->ip_ttl == C_TTL-1);
				ASSERT(eth->ether_dhost[0] == ether_dhost[0] &&
				       eth->ether_dhost[1] == ether_dhost[1] &&
				       eth->ether_dhost[2] == (C_GW_ADDR>>24));
			}
		}

		for (c = 0; c < num; c++) {
			odp_packet_t pkt = burst[c] = odp_packet_from_event(ev[c]);
			uint8_t *buf = odp_packet_data(pkt);
			struct ofp_ether_header *eth =
				(struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);
			struct ofp_ip *ip = (struct ofp_ip *)(buf + OFP_ETHER_HDR_LEN);

			memset(eth->ether_dhost, 0, sizeof(eth->ether_dhost));
			ip->ip_ttl = C_TTL;
			ip->ip_dst.s_addr = dst_addr();
			uint32_t cksum = cksum_base;
			cksum += odp_be_to_cpu_16(ip->ip_dst.s_addr&0xffff);
			cksum += odp_be_to_cpu_16(ip->ip_dst.s_addr>>16);
			cksum = (cksum & 0xffff) + (cksum >> 16);
			ip->ip_sum = odp_cpu_to_be_16(~cksum);
		}

		if (tstate[cpuid].stop) {
			for (c = 0; c < num; c++)
				odp_packet_free(burst[c]);
			break;
		}

		odp_time_t start = odp_time_global();

		for (c = 0; c < num; c++)
			ASSERT(ofp_packet_input(burst[c], dummyq, ofp_eth_vlan_processing) == OFP_PKT_PROCESSED);

		res = ofp_send_pending_pkt();

		tstate[cpuid].time = odp_time_sum(tstate[cpuid].time, odp_time_diff(odp_time_global(), start));
		tstate[cpuid].packets += num;
	}

	return NULL;
}



static void usage(const char *prog)
{
	printf("\nUsage: %s [options]\n\n"
{'fraction_non_alphanumeric': 0.14748005801305294, 'fraction_numerical': 0.060641769398114574, 'mean_word_length': 4.112604263206673, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1650964', 'n_tokens_mistral': 5813, 'n_tokens_neox': 5054, 'n_words': 1013}