#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2025-2026 Chester A. Unal <chester.a.unal@arinc9.com>

if [ $# -ne 2 ] || { [ "$1" != "l2" ] && [ "$1" != "l3" ]; }; then
	echo "Usage: $0 l2|l3 <interface>"
	exit 1
fi

SEC="tc"
if [ "$1" = "l3" ]; then
	SEC="tc_l3"
fi

IFACE="$2"
PROGRAMME=/usr/lib/bpf/tcp_in_udp_tc.o

CLIENT_LIMIT=32768

# Mark rule matches a packet if ((mark & MARK_MASK) == (BASE_MARK & MARK_MASK))
# is true. Mark is a 32-bit value.
# Value of bit 15 in hex.
BASE_MARK=0x8000
# Set all bits except the client range so that a mark with only the BASE_MARK
# bit and any bits of the client range matches the rule.
MARK_MASK=$(printf '0x%x' $((0xffffffff - CLIENT_LIMIT + 1)))

# Port rule matches a packet if ((port & PORT_MASK) == (BASE_PORT & PORT_MASK))
# is true. Port is a 16-bit value.
# Value of bit 15 in hex.
BASE_PORT=0x8000
# Set all bits except the client range so that a port with only the BASE_PORT
# bit and any bits of the client range matches the rule.
PORT_MASK=$(printf '0x%x' $((0xffff - CLIENT_LIMIT + 1)))

ethtool -K "$IFACE" gro off 2>/dev/null && \
ip link set "$IFACE" gso_max_segs 0 && \
tc qdisc del dev "$IFACE" clsact 2>/dev/null ; \
tc qdisc replace dev "$IFACE" clsact && \
tc filter add dev "$IFACE" egress u32 match mark "$BASE_MARK" "$MARK_MASK" action goto chain 1 && \
tc filter add dev "$IFACE" egress chain 1 bpf object-file "$PROGRAMME" section "$SEC" action csum udp && \
tc filter add dev "$IFACE" ingress u32 match ip dport "$BASE_PORT" "$PORT_MASK" action goto chain 1 && \
tc filter add dev "$IFACE" ingress chain 1 bpf object-file "$PROGRAMME" section "$SEC" direct-action
