Skip to content

Commit 9c7e942

Browse files
committed
refactor: nat4 v3 dynamic state handling
1 parent bb2dca5 commit 9c7e942

File tree

8 files changed

+668
-375
lines changed

8 files changed

+668
-375
lines changed

landscape-ebpf/src/bpf/land_nat4_v3.h

Lines changed: 161 additions & 174 deletions
Large diffs are not rendered by default.

landscape-ebpf/src/bpf/land_nat_v3.bpf.c

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ int nat_v4_egress(struct __sk_buff *skb) {
6161
#define BPF_LOG_TOPIC "nat_v4_egress_v3 <<<"
6262
struct packet_offset_info pkg_offset = {0};
6363
struct inet4_pair ip_pair = {0};
64-
struct nat4_lookup_result_v3 lookup = {0};
64+
struct nat_mapping_value_v4_v3 *nat_egress_value = NULL;
65+
struct nat_mapping_value_v4_v3 *nat_ingress_value = NULL;
66+
struct nat4_port_queue_value_v3 alloc_item = {0};
67+
bool created = false;
6568
int ret = 0;
6669

6770
ret = scan_packet(skb, current_l3_offset, &pkg_offset);
@@ -78,29 +81,34 @@ int nat_v4_egress(struct __sk_buff *skb) {
7881
bool is_icmpx_error = is_icmp_error_pkt(&pkg_offset);
7982
bool allow_create_mapping = !is_icmpx_error && pkt_allow_initiating_ct(pkg_offset.pkt_type);
8083

81-
ret = nat4_v3_egress_lookup_or_new_mapping(skb, pkg_offset.l4_protocol, allow_create_mapping,
82-
&ip_pair, &lookup);
83-
if (ret != TC_ACT_OK || !lookup.egress) {
84+
ret = nat4_v3_egress_lookup_or_new_mapping_v4(
85+
skb, pkg_offset.l4_protocol, allow_create_mapping, &ip_pair, &nat_egress_value,
86+
&nat_ingress_value, &alloc_item, &created);
87+
if (ret != TC_ACT_OK || !nat_egress_value || !nat_ingress_value) {
8488
return TC_ACT_SHOT;
8589
}
8690

87-
if (!lookup.is_static && lookup.egress->is_allow_reuse == 0 &&
88-
pkg_offset.l4_protocol != IPPROTO_ICMP) {
89-
if (ip_pair.dst_addr.addr != lookup.egress->trigger_addr ||
90-
ip_pair.dst_port != lookup.egress->trigger_port) {
91+
bool is_dynamic = nat_egress_value->is_static == 0;
92+
bool is_ancestor = ip_pair.dst_addr.addr == nat_egress_value->trigger_addr &&
93+
ip_pair.dst_port == nat_egress_value->trigger_port;
94+
95+
if (is_dynamic && nat_egress_value->is_allow_reuse == 0 && pkg_offset.l4_protocol != IPPROTO_ICMP) {
96+
if (!is_ancestor) {
9197
return TC_ACT_SHOT;
9298
}
9399
}
94100

95-
if (!lookup.is_static && ip_pair.dst_addr.addr == lookup.egress->trigger_addr &&
96-
ip_pair.dst_port == lookup.egress->trigger_port) {
101+
if (is_dynamic && is_ancestor) {
97102
u8 allow = get_flow_allow_reuse_port(skb->mark) ? 1 : 0;
98-
lookup.egress->is_allow_reuse = allow;
99-
if (lookup.ingress) lookup.ingress->is_allow_reuse = allow;
103+
nat_egress_value->is_allow_reuse = allow;
104+
nat_ingress_value->is_allow_reuse = allow;
100105
}
101106

102-
struct inet4_addr nat_addr = {0};
103-
if (lookup.is_static) {
107+
struct inet4_addr nat_addr = {
108+
.addr = nat_egress_value->addr,
109+
};
110+
__be16 nat_port = nat_egress_value->port;
111+
if (!is_dynamic) {
104112
struct wan_ip_info_key wan_search_key = {
105113
.ifindex = skb->ifindex,
106114
.l3_protocol = LANDSCAPE_IPV4_TYPE,
@@ -109,37 +117,33 @@ int nat_v4_egress(struct __sk_buff *skb) {
109117
bpf_map_lookup_elem(&wan_ip_binding, &wan_search_key);
110118
if (!wan_ip_info) return TC_ACT_SHOT;
111119
nat_addr.addr = wan_ip_info->addr.ip;
112-
} else {
113-
nat_addr.addr = lookup.egress->addr;
114120
}
115121

116122
struct inet4_pair server_nat_pair = {
117123
.src_addr = ip_pair.dst_addr,
118124
.src_port = ip_pair.dst_port,
119125
.dst_addr = nat_addr,
120-
.dst_port = lookup.egress->port,
126+
.dst_port = nat_port,
121127
};
122128
if (pkg_offset.l4_protocol == IPPROTO_ICMP) {
123-
server_nat_pair.src_port = lookup.egress->port;
129+
server_nat_pair.src_port = nat_port;
124130
}
125131

126132
struct nat_timer_value_v4_v3 *ct_value = NULL;
127-
u16 generation = lookup.state ? lookup.state->generation : 0;
128133
ret = nat4_v3_lookup_or_new_ct(skb, pkg_offset.l4_protocol, allow_create_mapping,
129134
&server_nat_pair, &ip_pair.src_addr, ip_pair.src_port,
130-
NAT_MAPPING_EGRESS, generation,
131-
lookup.created || lookup.is_static, lookup.state, &ct_value);
135+
NAT_MAPPING_EGRESS, nat_ingress_value, &ct_value);
132136
if (ret == TIMER_NOT_FOUND || ret == TIMER_ERROR) {
133-
if (lookup.created && !lookup.is_static) {
134-
nat4_v3_delete_mapping_and_state(pkg_offset.l4_protocol, nat_addr.addr,
135-
lookup.egress->port, ip_pair.src_addr.addr,
136-
ip_pair.src_port);
137-
(void)nat4_v3_queue_push(pkg_offset.l4_protocol, &lookup.alloc_item);
137+
if (created && is_dynamic &&
138+
nat_ingress_value->state_ref == nat4_v3_state_make(NAT4_V3_STATE_ACTIVE, 0)) {
139+
nat4_v3_delete_mapping_pair(pkg_offset.l4_protocol, nat_addr.addr, nat_port,
140+
ip_pair.src_addr.addr, ip_pair.src_port);
141+
(void)nat4_v3_queue_push(pkg_offset.l4_protocol, &alloc_item);
138142
}
139143
return TC_ACT_SHOT;
140144
}
141145

142-
if (!is_icmpx_error || ct_value != NULL) {
146+
if (!is_icmpx_error) {
143147
ct_state_transition(pkg_offset.pkt_type, NAT_MAPPING_EGRESS, nat4_v3_timer_base(ct_value));
144148
nat_metric_accumulate(skb, false, nat4_v3_timer_base(ct_value));
145149
}
@@ -148,7 +152,7 @@ int nat_v4_egress(struct __sk_buff *skb) {
148152
.from_addr = ip_pair.src_addr,
149153
.from_port = ip_pair.src_port,
150154
.to_addr = nat_addr,
151-
.to_port = lookup.egress->port,
155+
.to_port = nat_port,
152156
};
153157

154158
ret = modify_headers_v4(skb, is_icmpx_error, pkg_offset.l4_protocol, current_l3_offset,
@@ -163,8 +167,7 @@ int nat_v4_ingress(struct __sk_buff *skb) {
163167
#define BPF_LOG_TOPIC "nat_v4_ingress_v3 >>>"
164168
struct packet_offset_info pkg_offset = {0};
165169
struct inet4_pair ip_pair = {0};
166-
struct nat_mapping_value_v4 *nat_ingress_value = NULL;
167-
struct nat4_mapping_state_v3 *state = NULL;
170+
struct nat_mapping_value_v4_v3 *nat_ingress_value = NULL;
168171
int ret = 0;
169172

170173
ret = scan_packet(skb, current_l3_offset, &pkg_offset);
@@ -180,32 +183,36 @@ int nat_v4_ingress(struct __sk_buff *skb) {
180183

181184
bool is_icmpx_error = is_icmp_error_pkt(&pkg_offset);
182185

183-
ret = nat4_v3_ingress_lookup_mapping(skb, pkg_offset.l4_protocol, &ip_pair, &nat_ingress_value,
184-
&state);
186+
ret = nat4_v3_ingress_lookup_or_new_mapping4(pkg_offset.l4_protocol, &ip_pair,
187+
&nat_ingress_value);
185188
if (ret != TC_ACT_OK || !nat_ingress_value) {
186189
return TC_ACT_SHOT;
187190
}
188191

189-
if (!nat_ingress_value->is_static && nat_ingress_value->is_allow_reuse == 0 &&
192+
bool is_static = nat_ingress_value->is_static != 0;
193+
194+
if (!is_static && nat_ingress_value->is_allow_reuse == 0 &&
190195
pkg_offset.l4_protocol != IPPROTO_ICMP) {
191196
if (ip_pair.src_addr.addr != nat_ingress_value->trigger_addr ||
192197
ip_pair.src_port != nat_ingress_value->trigger_port) {
193198
return TC_ACT_SHOT;
194199
}
195200
}
196201

197-
if (nat_ingress_value->is_static) {
202+
if (is_static) {
198203
u32 mark = skb->mark;
199204
barrier_var(mark);
200205
skb->mark = replace_cache_mask(mark, INGRESS_STATIC_MARK);
201206
}
202207

203208
struct inet4_addr lan_ip = {0};
204-
if (nat_ingress_value->is_static && nat_ingress_value->addr == 0) {
209+
__be16 lan_port = 0;
210+
if (is_static && nat_ingress_value->addr == 0) {
205211
lan_ip.addr = ip_pair.dst_addr.addr;
206212
} else {
207213
lan_ip.addr = nat_ingress_value->addr;
208214
}
215+
lan_port = nat_ingress_value->port;
209216

210217
struct inet4_pair server_nat_pair = {
211218
.src_addr = ip_pair.src_addr,
@@ -214,21 +221,23 @@ int nat_v4_ingress(struct __sk_buff *skb) {
214221
.dst_port = ip_pair.dst_port,
215222
};
216223

217-
bool do_new_ct = nat_ingress_value->is_static
224+
u64 ingress_state_ref = nat_ingress_value->state_ref;
225+
bool do_new_ct = is_static
218226
? (!is_icmpx_error && pkt_allow_initiating_ct(pkg_offset.pkt_type))
219-
: (nat_ingress_value->is_allow_reuse && !is_icmpx_error &&
227+
: (nat_ingress_value->is_allow_reuse &&
228+
nat4_v3_state_get(ingress_state_ref) == NAT4_V3_STATE_ACTIVE &&
229+
nat4_v3_ref_get(ingress_state_ref) > 0 && !is_icmpx_error &&
220230
pkt_allow_initiating_ct(pkg_offset.pkt_type));
221231

222232
struct nat_timer_value_v4_v3 *ct_value = NULL;
223-
u16 generation = state ? state->generation : 0;
224233
ret = nat4_v3_lookup_or_new_ct(skb, pkg_offset.l4_protocol, do_new_ct, &server_nat_pair,
225-
&lan_ip, nat_ingress_value->port, NAT_MAPPING_INGRESS,
226-
generation, nat_ingress_value->is_static, state, &ct_value);
234+
&lan_ip, lan_port, NAT_MAPPING_INGRESS, nat_ingress_value,
235+
&ct_value);
227236
if (ret == TIMER_NOT_FOUND || ret == TIMER_ERROR) {
228237
return TC_ACT_SHOT;
229238
}
230239

231-
if (!is_icmpx_error || ct_value != NULL) {
240+
if (!is_icmpx_error) {
232241
ct_state_transition(pkg_offset.pkt_type, NAT_MAPPING_INGRESS, nat4_v3_timer_base(ct_value));
233242
nat_metric_accumulate(skb, true, nat4_v3_timer_base(ct_value));
234243
}
@@ -237,7 +246,7 @@ int nat_v4_ingress(struct __sk_buff *skb) {
237246
.from_addr = ip_pair.dst_addr,
238247
.from_port = ip_pair.dst_port,
239248
.to_addr = lan_ip,
240-
.to_port = nat_ingress_value->port,
249+
.to_port = lan_port,
241250
};
242251

243252
ret = modify_headers_v4(skb, is_icmpx_error, pkg_offset.l4_protocol, current_l3_offset,

landscape-ebpf/src/bpf/nat/nat_maps.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ struct nat_mapping_value_v4 {
4848
u64 active_time;
4949
};
5050

51+
struct nat_mapping_value_v4_v3 {
52+
u64 state_ref;
53+
__be32 addr;
54+
__be32 trigger_addr;
55+
__be16 port;
56+
__be16 trigger_port;
57+
u16 generation;
58+
u8 is_static;
59+
u8 is_allow_reuse;
60+
};
61+
5162
struct {
5263
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
5364
__type(key, struct static_nat_mapping_key_v6);
@@ -60,7 +71,7 @@ struct {
6071
struct {
6172
__uint(type, BPF_MAP_TYPE_HASH);
6273
__type(key, struct nat_mapping_key_v4);
63-
__type(value, struct nat_mapping_value_v4);
74+
__type(value, struct nat_mapping_value_v4_v3);
6475
__uint(max_entries, NAT_MAPPING_CACHE_SIZE);
6576
__uint(pinning, LIBBPF_PIN_BY_NAME);
6677
} nat4_st_map SEC(".maps");

landscape-ebpf/src/bpf/nat/nat_v3_maps.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include "../land_nat_common.h"
99
#include "nat_maps.h"
1010

11-
#define NAT4_V3_DYNAMIC_STATE_SIZE NAT_MAPPING_CACHE_SIZE
1211
#define NAT4_V3_TIMER_SIZE NAT_MAPPING_TIMER_SIZE
1312
#define NAT4_V3_PORT_QUEUE_SIZE 65536
1413

@@ -17,13 +16,6 @@ struct nat4_port_queue_value_v3 {
1716
u16 last_generation;
1817
};
1918

20-
struct nat4_mapping_state_v3 {
21-
u64 state_ref;
22-
u16 generation;
23-
u16 _pad0;
24-
u32 _pad1;
25-
};
26-
2719
struct nat_timer_value_v4_v3 {
2820
u64 server_status;
2921
u64 client_status;
@@ -48,17 +40,10 @@ struct nat_timer_value_v4_v3 {
4840
struct {
4941
__uint(type, BPF_MAP_TYPE_HASH);
5042
__type(key, struct nat_mapping_key_v4);
51-
__type(value, struct nat_mapping_value_v4);
43+
__type(value, struct nat_mapping_value_v4_v3);
5244
__uint(max_entries, NAT_MAPPING_CACHE_SIZE);
5345
} nat4_dyn_map SEC(".maps");
5446

55-
struct {
56-
__uint(type, BPF_MAP_TYPE_HASH);
57-
__type(key, struct nat_mapping_key_v4);
58-
__type(value, struct nat4_mapping_state_v3);
59-
__uint(max_entries, NAT4_V3_DYNAMIC_STATE_SIZE);
60-
} nat4_dynamic_state_v3 SEC(".maps");
61-
6247
struct {
6348
__uint(type, BPF_MAP_TYPE_HASH);
6449
__type(key, struct nat_timer_key_v4);

landscape-ebpf/src/bpf/test_nat_v3_timer.bpf.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ int nat_v4_timer_step_test(struct __sk_buff *skb) {
9292
result->ingress_mapping_exists = bpf_map_lookup_elem(&nat4_dyn_map, &ingress_key) ? 1 : 0;
9393
result->egress_mapping_exists = bpf_map_lookup_elem(&nat4_dyn_map, &egress_key) ? 1 : 0;
9494

95-
struct nat4_mapping_state_v3 *state = bpf_map_lookup_elem(&nat4_dynamic_state_v3, &ingress_key);
96-
result->state_exists = state ? 1 : 0;
97-
if (state) {
98-
result->state_ref = state->state_ref;
99-
result->generation = state->generation;
95+
struct nat_mapping_value_v4_v3 *ingress_value = bpf_map_lookup_elem(&nat4_dyn_map, &ingress_key);
96+
result->state_exists = ingress_value ? 1 : 0;
97+
if (ingress_value) {
98+
result->state_ref = ingress_value->state_ref;
99+
result->generation = ingress_value->generation;
100100
}
101101

102102
return TC_ACT_OK;

landscape-ebpf/src/map_setting/nat.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use libbpf_rs::{MapCore, MapFlags};
55

66
use crate::{
77
map_setting::share_map::types::{
8-
nat_mapping_value_v4, static_nat_mapping_key_v6, static_nat_mapping_value_v6,
8+
nat_mapping_value_v4, nat_mapping_value_v4_v3, static_nat_mapping_key_v6,
9+
static_nat_mapping_value_v6,
910
},
1011
LANDSCAPE_IPV6_TYPE, MAP_PATHS, NAT_MAPPING_EGRESS, NAT_MAPPING_INGRESS,
1112
};
@@ -96,6 +97,62 @@ where
9697
}
9798
}
9899

100+
pub(crate) fn add_static_nat4_mapping_v3<'obj, T, I>(nat4_st_map: &T, mappings: I)
101+
where
102+
T: MapCore,
103+
I: IntoIterator<Item = StaticNatMappingV4Item>,
104+
I::IntoIter: ExactSizeIterator,
105+
{
106+
let mapping_iter = mappings.into_iter();
107+
if mapping_iter.len() == 0 {
108+
return;
109+
}
110+
111+
let mut keys = vec![];
112+
let mut values = vec![];
113+
let counts = (mapping_iter.len() * 2) as u32;
114+
115+
for static_mapping in mapping_iter {
116+
let ingress_mapping_key = NatMappingKeyV4 {
117+
gress: NAT_MAPPING_INGRESS,
118+
l4proto: static_mapping.l4_protocol,
119+
from_port: static_mapping.wan_port.to_be(),
120+
from_addr: 0,
121+
};
122+
123+
let egress_mapping_key = NatMappingKeyV4 {
124+
gress: NAT_MAPPING_EGRESS,
125+
l4proto: static_mapping.l4_protocol,
126+
from_port: static_mapping.lan_port.to_be(),
127+
from_addr: static_mapping.lan_ip.to_bits().to_be(),
128+
};
129+
130+
let mut ingress_mapping_value = nat_mapping_value_v4_v3::default();
131+
let mut egress_mapping_value = nat_mapping_value_v4_v3::default();
132+
133+
ingress_mapping_value.port = static_mapping.lan_port.to_be();
134+
ingress_mapping_value.addr = static_mapping.lan_ip.to_bits().to_be();
135+
ingress_mapping_value.is_static = 1;
136+
137+
egress_mapping_value.port = static_mapping.wan_port.to_be();
138+
egress_mapping_value.is_static = 1;
139+
140+
keys.extend_from_slice(unsafe { plain::as_bytes(&ingress_mapping_key) });
141+
values.extend_from_slice(unsafe { plain::as_bytes(&ingress_mapping_value) });
142+
143+
keys.extend_from_slice(unsafe { plain::as_bytes(&egress_mapping_key) });
144+
values.extend_from_slice(unsafe { plain::as_bytes(&egress_mapping_value) });
145+
}
146+
147+
if counts == 0 {
148+
return;
149+
}
150+
151+
if let Err(e) = nat4_st_map.update_batch(&keys, &values, counts, MapFlags::ANY, MapFlags::ANY) {
152+
tracing::error!("counts: {counts:?}, update nat4_st_map(v3) error:{e:?}");
153+
}
154+
}
155+
99156
pub(crate) fn add_static_nat6_mapping<'obj, T, I>(static_nat_mappings: &T, mappings: I)
100157
where
101158
T: MapCore,
@@ -190,7 +247,7 @@ where
190247
}
191248

192249
let nat4_st_map = libbpf_rs::MapHandle::from_pinned_path(&MAP_PATHS.nat4_st_map).unwrap();
193-
add_static_nat4_mapping(&nat4_st_map, v4_rules.iter().copied());
250+
add_static_nat4_mapping_v3(&nat4_st_map, v4_rules.iter().copied());
194251
let nat4_mappings = libbpf_rs::MapHandle::from_pinned_path(&MAP_PATHS.nat4_mappings).unwrap();
195252
add_static_nat4_mapping(&nat4_mappings, v4_rules);
196253
let static_nat_mappings =

0 commit comments

Comments
 (0)