tools/testing/selftests/net/lib/gro.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/net/lib/gro.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/net/lib/gro.c
Extension
.c
Size
60130 bytes
Lines
1920
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pppoe_ppp_hdr {
		struct pppoe_hdr eh;
		__be16 proto;
	} *ph = buf;

	payload_len += sizeof(struct tcphdr);
	ph->eh.type = 1;
	ph->eh.ver = 1;
	ph->eh.code = 0;
	ph->eh.sid = htons(sid);
	ph->eh.length = htons(payload_len + sizeof(ph->proto));
	ph->proto = htons(proto == PF_INET ? PPP_IP : PPP_IPV6);
}

static void setup_sock_filter(int fd)
{
	const int dport_off = tcp_offset + offsetof(struct tcphdr, dest);
	const int ethproto_off = offsetof(struct ethhdr, h_proto);
	int optlen = 0;
	int ipproto_off, opt_ipproto_off;

	if (proto == PF_INET)
		ipproto_off = tcp_offset - sizeof(struct iphdr) +
			      offsetof(struct iphdr, protocol);
	else
		ipproto_off = tcp_offset - sizeof(struct ipv6hdr) +
			      offsetof(struct ipv6hdr, nexthdr);

	/* Overridden later if exthdrs are used: */
	opt_ipproto_off = ipproto_off;

	if (strcmp(testname, "ip_opt") == 0) {
		optlen = sizeof(struct ip_timestamp);
	} else if (strcmp(testname, "ip_frag6") == 0 ||
		   strcmp(testname, "ip_v6ext_same") == 0 ||
		   strcmp(testname, "ip_v6ext_diff") == 0) {
		BUILD_BUG_ON(sizeof(struct ip6_hbh) > MIN_EXTHDR_SIZE);
		BUILD_BUG_ON(sizeof(struct ip6_dest) > MIN_EXTHDR_SIZE);
		BUILD_BUG_ON(sizeof(struct ip6_frag) > MIN_EXTHDR_SIZE);

		/* same size for HBH and Fragment extension header types */
		optlen = MIN_EXTHDR_SIZE;
		opt_ipproto_off = ETH_HLEN + sizeof(struct ipv6hdr)
			+ offsetof(struct ip6_ext, ip6e_nxt);
	}

	/* this filter validates the following:
	 *	- packet is IPv4/IPv6 according to the running test.
	 *	- packet is TCP. Also handles the case of one extension header and then TCP.
	 *	- checks the packet tcp dport equals to DPORT. Also handles the case of one
	 *	  extension header and then TCP.
	 */
	struct sock_filter filter[] = {
			BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, ethproto_off),
			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ntohs(ethhdr_proto), 0, 9),
			BPF_STMT(BPF_LD  + BPF_B   + BPF_ABS, ipproto_off),
			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 2, 0),
			BPF_STMT(BPF_LD  + BPF_B   + BPF_ABS, opt_ipproto_off),
			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 0, 5),
			BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, dport_off),
			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 2, 0),
			BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, dport_off + optlen),
			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 0, 1),
			BPF_STMT(BPF_RET + BPF_K, 0xFFFFFFFF),
			BPF_STMT(BPF_RET + BPF_K, 0),
	};

	struct sock_fprog bpf = {
		.len = ARRAY_SIZE(filter),
		.filter = filter,
	};

	if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 0)
		error(1, errno, "error setting filter");
}

static uint32_t checksum_nofold(void *data, size_t len, uint32_t sum)
{
	uint16_t *words = data;
	int i;

	for (i = 0; i < len / 2; i++)
		sum += words[i];
	if (len & 1)
		sum += ((char *)data)[len - 1];
	return sum;
}

static uint16_t checksum_fold(void *data, size_t len, uint32_t sum)
{

Annotation

Implementation Notes