Skip to content

Mekhanik evgenii/ctx size reducing - #53

Open
EvgeniiMekhanik wants to merge 4 commits into
mainfrom
MekhanikEvgenii/ctx_size_reducing
Open

Mekhanik evgenii/ctx size reducing#53
EvgeniiMekhanik wants to merge 4 commits into
mainfrom
MekhanikEvgenii/ctx_size_reducing

Conversation

@EvgeniiMekhanik

Copy link
Copy Markdown
Contributor

No description provided.

@EvgeniiMekhanik
EvgeniiMekhanik force-pushed the MekhanikEvgenii/ctx_size_reducing branch 2 times, most recently from abd7a61 to fe9ac68 Compare July 25, 2026 16:30
@EvgeniiMekhanik

Copy link
Copy Markdown
Contributor Author

Totally this patch change bpftool btf dump file bpf/BUILD/xdp.o format raw | grep XfwGlobalCtx
from [259] STRUCT 'XfwGlobalCtx' size=112 vlen=14 to [259] STRUCT 'XfwGlobalCtx' size=80 vlen=12
We save 32 bytes! But we add extra check before getting appropriate pointers, because of verifier restrictions.

@consuelo2210

consuelo2210 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

I just started to review code. In debug mode I have:

libbpf: prog 'xfw_tc': failed to load: -13
libbpf: failed to load object '/opt/tempesta/lib/bpf/tc.o'

Don't fix it until the end of the review, please.

@consuelo2210 consuelo2210 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I like the direction of these changes. The refactoring makes the parsing code cleaner and more structured, and I think moving to offsets instead of pointers is the right approach. From the verifier's perspective, it's easier to derive a new pointer from an offset and perform a fresh bounds check than to track an existing pointer. I also believe this approach will make it easier to increase the program's complexity in the future(code complexity is a part of evolution) and to work with specific headers only when needed, as you did in tcp_syncookies.h.

My main concern is that the current code looks like it's only halfway through the refactoring. It already contains parts of the new design, but the overall code structure still follows the old approach. Since we're already making these changes, I think it's much easier to complete the refactoring now than to leave it for later. Otherwise, it will most likely be forgotten.

So, please do an additional self-review on top of my comments and try to identify any remaining inconsistencies or illogical code paths introduced by these changes.

Also, please add const to the pointer parameters you've started passing to functions wherever appropriate.

One more thing: please compile the code in DEBUG mode as well. At the moment, the DEBUG build of tc.o cannot be loaded onto the interface.

Comment thread bpf/ctx.h Outdated
struct udphdr *uh;
uint64_t ts_jiff;
XfwIp ilog_addr;
uint8_t eth_off;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that we need this field. Do we really have cases now when eth_off is greater than 0?

@consuelo2210 consuelo2210 Jul 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove eth_off entirely, we may not need any parameters for parse_ethhdr() besides hdr_cur. In fact, we might not need to advance hdr_cur at all and could instead calculate the required pointer from the base address whenever needed(by the way, may we setup ip_off in parse_ethhdr?).

I also noticed that all offsets stored in the context are uint8_t, but they're computed like uint16_t:

*eth_off = (uint16_t)((void *)eth - data_bgn);
typedef struct XfwGlobalCtx {
	XfwHdrCursor	hdr_cur;
	XfwIp		ilog_addr;
	XfwFilterCfg	*cfg;
	XfwPerCpuStats	*g_stats;
	XfwMd		*ctx;
	uint64_t	ts_jiff;
	uint32_t	pkt_sz;
	uint16_t	ipver;
	**uint8_t		ip_off;
	uint8_t		l4_off;**
	uint8_t		l4_proto;
	**uint8_t		eth_off;**
} XfwGlobalCtx;

I took a quick look at the supported IPv6 extension headers:

  • Hop-by-Hop Options (0)
  • Routing (43)
  • Authentication Header (AH, 51)
  • Destination Options (60)
  • Mobility Header (135)

ip_off and eth_off should always fit into uint8_t, but l4_off may not if an IPv6 packet contains a long chain of extension headers. In that case, uint16_t would be a safer type for l4_off.

Comment thread bpf/parsing_helpers.h Outdated
/* Parse TCP and return the complete TCP header length. */
static __always_inline int
parse_tcphdr(XfwHdrCursor *cur, struct tcphdr **tcphdr)
parse_tcphdr(XfwHdrCursor *cur, void *data_bgn, uint8_t *l4_off)

@consuelo2210 consuelo2210 Jul 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. It seems a bit strange to pass data_bgn and l4_off here. Both values can be calculated outside this function, so we don't need parse_tcphdr() to populate them. We could even initialize l4_off at the L3 parsing stage.
    The same applies to the other parse_* functions from parsing_helpers.h.

  2. We also calculate struct tcphdr *th twice now: once inside parse_tcphdr(), and then immediately afterwards with additional checks:

if (unlikely(parse_tcphdr(&ctx->hdr_cur,
                          XFW_CTX_DATA_BGN(ctx->ctx),
                          &ctx->l4_off) <= 0))
    return XFW_MAKE_CTX_DROP(ctx, XFW_TCP_BADHDR_INGRESS);

struct tcphdr *th =
    XFW_GET_PKT_PTR(ctx, ctx->l4_off, struct tcphdr,
                    XFW_MAKE_CTX_DROP(ctx, XFW_TCP_BADHDR_INGRESS));

@consuelo2210

consuelo2210 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

@EvgeniiMekhanik Could you please take a look at this?

68a6595

The tradeoff is a larger ctx, since it stores pointers instead of offsets, but it should be faster. Overall, after the cleanup, only four boundary checks were added.

@EvgeniiMekhanik
EvgeniiMekhanik force-pushed the MekhanikEvgenii/ctx_size_reducing branch 5 times, most recently from fa52c33 to 5e8bc6b Compare August 8, 2026 19:44
ethernet data offset is always equal to zero, so we can
safely remove ethernet header pointer from XfwGlobalCtx.
Replace stored IPv4/IPv6 header pointers with a common IP header
offset. Restore packet pointers on demand and validate packet bounds
before accessing them.

This reduces verifier pointer state and lowers XDP context overhead.

Using offsets is also required for the planned tail-call based module
architecture, since packet pointers cannot be preserved across tail
calls and may also be invalidated by packet-adjusting helpers.
Remove tcphdr/udphdr pointers from XfwGlobalCtx and store only the L4
header offset in packet metadata.

Resolve TCP and UDP headers locally via XFW_PKT_PTR() at the point of
use instead of keeping packet pointers in the global context. Pass
already parsed L4 header pointers through filter call chains to avoid
repeated packet lookups in hot paths.

This reduces XfwGlobalCtx size, avoids storing transient packet pointers,
and makes context layout consistent with the IP header offset approach.

Using offsets is also required for the planned tail-call based module
architecture, since packet pointers cannot be preserved across tail
calls and may also be invalidated by packet-adjusting helpers.
Reorder XfwGlobalCtx fields to reduce alignment padding and make the
context layout more compact.
@EvgeniiMekhanik
EvgeniiMekhanik force-pushed the MekhanikEvgenii/ctx_size_reducing branch from 5e8bc6b to 38c6208 Compare August 20, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants