tools/testing/selftests/bpf/progs/test_cls_redirect.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/bpf/progs/test_cls_redirect.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/bpf/progs/test_cls_redirect.c
Extension
.c
Size
27384 bytes
Lines
1077
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

if (scratch == NULL) {
			return NULL;
		}

		return buf_copy(buf, scratch, len) ? scratch : NULL;
	}

	void *ptr = buf->head;
	buf->head += len;
	return ptr;
}

static INLINING bool pkt_skip_ipv4_options(buf_t *buf, const struct iphdr *ipv4)
{
	if (ipv4->ihl <= 5) {
		return true;
	}

	return buf_skip(buf, (ipv4->ihl - 5) * 4);
}

static INLINING bool ipv4_is_fragment(const struct iphdr *ip)
{
	uint16_t frag_off = ip->frag_off & bpf_htons(IP_OFFSET_MASK);
	return (ip->frag_off & bpf_htons(IP_MF)) != 0 || frag_off > 0;
}

static __always_inline struct iphdr *pkt_parse_ipv4(buf_t *pkt, struct iphdr *scratch)
{
	struct iphdr *ipv4 = buf_assign(pkt, sizeof(*ipv4), scratch);
	if (ipv4 == NULL) {
		return NULL;
	}

	if (ipv4->ihl < 5) {
		return NULL;
	}

	if (!pkt_skip_ipv4_options(pkt, ipv4)) {
		return NULL;
	}

	return ipv4;
}

/* Parse the L4 ports from a packet, assuming a layout like TCP or UDP. */
static INLINING bool pkt_parse_icmp_l4_ports(buf_t *pkt, flow_ports_t *ports)
{
	if (!buf_copy(pkt, ports, sizeof(*ports))) {
		return false;
	}

	/* Ports in the L4 headers are reversed, since we are parsing an ICMP
	 * payload which is going towards the eyeball.
	 */
	uint16_t dst = ports->src;
	ports->src = ports->dst;
	ports->dst = dst;
	return true;
}

static INLINING uint16_t pkt_checksum_fold(uint32_t csum)
{
	/* The highest reasonable value for an IPv4 header
	 * checksum requires two folds, so we just do that always.
	 */
	csum = (csum & 0xffff) + (csum >> 16);
	csum = (csum & 0xffff) + (csum >> 16);
	return (uint16_t)~csum;
}

static INLINING void pkt_ipv4_checksum(struct iphdr *iph)
{
	iph->check = 0;

	/* An IP header without options is 20 bytes. Two of those
	 * are the checksum, which we always set to zero. Hence,
	 * the maximum accumulated value is 18 / 2 * 0xffff = 0x8fff7,
	 * which fits in 32 bit.
	 */
	_Static_assert(sizeof(struct iphdr) == 20, "iphdr must be 20 bytes");
	uint32_t acc = 0;
	uint16_t *ipw = (uint16_t *)iph;

	__pragma_loop_unroll_full
	for (size_t i = 0; i < sizeof(struct iphdr) / 2; i++) {
		acc += ipw[i];
	}

	iph->check = pkt_checksum_fold(acc);

Annotation

Implementation Notes