Skip to content

Commit 31a01b9

Browse files
committed
bpf/nat: Move ipv6_nat_entry to map
This commit moves the ipv6_nat_entry local variable of snat_v6_nat_handle_mapping from the stack to a per-cpu array map. This function (or rather its caller) has a very large stack because ipv6_nat_entry is huge and we manipulate several variables of that type. We're currently close to the limit and few changes are often enough to get us above the 512B stack size limit. This is currently blocking ongoing work on complexity issues and BPF Host Routing in other pull requests. This commit therefore implements the strategy tried by Aditi before and extends it to the tmp variable. We're moving the rstate and tmp variables of type ipv6_nat_entry to a map. We can use the same map for both variables because (1) they are not used at the same time and (2) they are always cleared before being used anyway. The following two tables show the impact on the stack size of tail_handle_snat_fwd_ipv6 of moving the two variables to the map. Config 1 corresponds to the config generated by "make build_all". Config 2 corresponds to the config generated by "make". Impact on tail_handle_snat_fwd_ipv6 after moving rstate to the map: | Program | Config 1 | Config 2 | |---------------|----------|----------| | bpf_host | -0 | -0 | | bpf_overlay | -0 | -0 | | bpf_wireguard | -56 | -0 | Impact on tail_handle_snat_fwd_ipv6 after moving tmp to the map: | Program | Config 1 | Config 2 | |---------------|----------|----------| | bpf_host | -64 | -48 | | bpf_overlay | -40 | -48 | | bpf_wireguard | -56 | -56 | Co-developed-by: Aditi Ghag <aditi@cilium.io> Signed-off-by: Aditi Ghag <aditi@cilium.io> Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
1 parent 899bab8 commit 31a01b9

1 file changed

Lines changed: 26 additions & 12 deletions

File tree

bpf/lib/nat.h

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,18 +1373,26 @@ static __always_inline int snat_v6_new_mapping(struct __ctx_buff *ctx,
13731373
return ret;
13741374
}
13751375

1376+
/* Store struct ipv6_nat_entry objects in map to optimize stack usage. */
1377+
struct {
1378+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
1379+
__uint(max_entries, 1);
1380+
__type(key, int);
1381+
__type(value, struct ipv6_nat_entry);
1382+
} ipv6_nat_entry_storage __section_maps_btf;
1383+
13761384
static __always_inline int
13771385
snat_v6_nat_handle_mapping(struct __ctx_buff *ctx,
13781386
struct ipv6_ct_tuple *tuple,
13791387
fraginfo_t fraginfo,
13801388
struct ipv6_nat_entry **state,
1381-
struct ipv6_nat_entry *tmp,
13821389
__u32 off,
13831390
const struct ipv6_nat_target *target,
13841391
struct trace_ctx *trace,
13851392
__s8 *ext_err)
13861393
{
13871394
bool needs_ct = target->needs_ct;
1395+
int zero = 0;
13881396

13891397
*state = snat_v6_lookup(tuple);
13901398

@@ -1422,17 +1430,21 @@ snat_v6_nat_handle_mapping(struct __ctx_buff *ctx,
14221430
/* Check for the reverse SNAT entry. If it is missing (e.g. due to LRU
14231431
* eviction), it must be restored before returning.
14241432
*/
1425-
struct ipv6_nat_entry rstate;
1433+
struct ipv6_nat_entry *rstate;
14261434
struct ipv6_nat_entry *lookup_result;
14271435

14281436
lookup_result = snat_v6_lookup(&rtuple);
14291437
if (!lookup_result) {
1430-
memset(&rstate, 0, sizeof(rstate));
1431-
rstate.to_daddr = tuple->saddr;
1432-
rstate.to_dport = tuple->sport;
1433-
rstate.common.needs_ct = needs_ct;
1434-
rstate.common.created = bpf_mono_now();
1435-
ret = __snat_create(&cilium_snat_v6_external, &rtuple, &rstate,
1438+
rstate = map_lookup_elem(&ipv6_nat_entry_storage, &zero);
1439+
if (!rstate)
1440+
return DROP_INVALID;
1441+
1442+
memset(rstate, 0, sizeof(*rstate));
1443+
rstate->to_daddr = tuple->saddr;
1444+
rstate->to_dport = tuple->sport;
1445+
rstate->common.needs_ct = needs_ct;
1446+
rstate->common.created = bpf_mono_now();
1447+
ret = __snat_create(&cilium_snat_v6_external, &rtuple, rstate,
14361448
false);
14371449
if (ret < 0) {
14381450
if (ext_err)
@@ -1454,8 +1466,10 @@ snat_v6_nat_handle_mapping(struct __ctx_buff *ctx,
14541466
__snat_delete(&cilium_snat_v6_external, &rtuple);
14551467
}
14561468

1457-
*state = tmp;
1458-
return snat_v6_new_mapping(ctx, tuple, tmp, target, needs_ct, ext_err);
1469+
*state = map_lookup_elem(&ipv6_nat_entry_storage, &zero);
1470+
if (!*state)
1471+
return DROP_INVALID;
1472+
return snat_v6_new_mapping(ctx, tuple, *state, target, needs_ct, ext_err);
14591473
}
14601474

14611475
static __always_inline int
@@ -1847,10 +1861,10 @@ __snat_v6_nat(struct __ctx_buff *ctx, struct ipv6_ct_tuple *tuple, fraginfo_t fr
18471861
int l4_off, bool update_tuple, const struct ipv6_nat_target *target,
18481862
__u16 port_off, struct trace_ctx *trace, __s8 *ext_err)
18491863
{
1850-
struct ipv6_nat_entry *state, tmp;
1864+
struct ipv6_nat_entry *state;
18511865
int ret;
18521866

1853-
ret = snat_v6_nat_handle_mapping(ctx, tuple, fraginfo, &state, &tmp,
1867+
ret = snat_v6_nat_handle_mapping(ctx, tuple, fraginfo, &state,
18541868
l4_off, target, trace, ext_err);
18551869
if (ret < 0)
18561870
return ret;

0 commit comments

Comments
 (0)