Skip to content

Commit 88bfc1e

Browse files
Merge pull request #26 from vpp-dev/nat
NAT bugfixes
2 parents aa37b26 + 70fe9bf commit 88bfc1e

File tree

5 files changed

+185
-32
lines changed

5 files changed

+185
-32
lines changed

src/plugins/nat/in2out.c

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -251,20 +251,41 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node,
251251

252252
static inline int
253253
nat_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip0,
254-
u32 proto0, u16 src_port, u32 thread_index)
254+
u32 proto0, u16 src_port, u16 dst_port,
255+
u32 thread_index, u32 sw_if_index)
255256
{
256257
snat_session_key_t key0;
257258
clib_bihash_kv_8_8_t kv0, value0;
259+
snat_interface_t *i;
258260

261+
/* src NAT check */
259262
key0.addr = ip0->src_address;
260263
key0.port = src_port;
261264
key0.protocol = proto0;
262265
key0.fib_index = sm->outside_fib_index;
263266
kv0.key = key0.as_u64;
264267

265268
if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
266-
&value0))
269+
&value0))
270+
return 1;
271+
272+
/* dst NAT check */
273+
key0.addr = ip0->dst_address;
274+
key0.port = dst_port;
275+
key0.protocol = proto0;
276+
key0.fib_index = sm->inside_fib_index;
277+
kv0.key = key0.as_u64;
278+
if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
279+
&value0))
280+
{
281+
/* hairpinning */
282+
pool_foreach (i, sm->output_feature_interfaces,
283+
({
284+
if ((nat_interface_is_inside(i)) && (sw_if_index == i->sw_if_index))
285+
return 0;
286+
}));
267287
return 1;
288+
}
268289

269290
return 0;
270291
}
@@ -286,6 +307,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
286307
u32 outside_fib_index;
287308
uword * p;
288309
udp_header_t * udp0 = ip4_next_header (ip0);
310+
u8 is_sm = 0;
289311

290312
if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
291313
{
@@ -311,13 +333,6 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
311333
return SNAT_IN2OUT_NEXT_DROP;
312334
}
313335

314-
s = nat_session_alloc_or_recycle (sm, u, thread_index);
315-
if (!s)
316-
{
317-
clib_warning ("create NAT session failed");
318-
return SNAT_IN2OUT_NEXT_DROP;
319-
}
320-
321336
/* First try to match static mapping by local address and port */
322337
if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0))
323338
{
@@ -331,14 +346,20 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
331346
b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
332347
return SNAT_IN2OUT_NEXT_DROP;
333348
}
334-
u->nsessions++;
335349
}
336350
else
351+
is_sm = 1;
352+
353+
s = nat_session_alloc_or_recycle (sm, u, thread_index);
354+
if (!s)
337355
{
338-
u->nstaticsessions++;
339-
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
356+
clib_warning ("create NAT session failed");
357+
return SNAT_IN2OUT_NEXT_DROP;
340358
}
341359

360+
if (is_sm)
361+
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
362+
user_session_increment (sm, u, is_sm);
342363
s->outside_address_index = address_index;
343364
s->in2out = *key0;
344365
s->out2in = key1;
@@ -556,7 +577,7 @@ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node,
556577
if (vnet_buffer(b0)->sw_if_index[VLIB_TX] != ~0)
557578
{
558579
if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
559-
ip0, SNAT_PROTOCOL_ICMP, key0.port, thread_index)))
580+
ip0, SNAT_PROTOCOL_ICMP, key0.port, key0.port, thread_index, sw_if_index0)))
560581
{
561582
dont_translate = 1;
562583
goto out;
@@ -768,6 +789,9 @@ static inline u32 icmp_in2out (snat_main_t *sm,
768789
src_address /* changed member */);
769790
ip0->checksum = ip_csum_fold (sum0);
770791

792+
if (icmp0->checksum == 0)
793+
icmp0->checksum = 0xffff;
794+
771795
if (!icmp_is_error_message (icmp0))
772796
{
773797
new_id0 = sm0.port;
@@ -1236,14 +1260,8 @@ snat_in2out_unknown_proto (snat_main_t *sm,
12361260
s->in2out.fib_index = rx_fib_index;
12371261
s->in2out.port = s->out2in.port = ip->protocol;
12381262
if (is_sm)
1239-
{
1240-
u->nstaticsessions++;
1241-
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1242-
}
1243-
else
1244-
{
1245-
u->nsessions++;
1246-
}
1263+
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1264+
user_session_increment (sm, u, is_sm);
12471265

12481266
/* Add to lookup tables */
12491267
key.l_addr.as_u32 = old_addr;
@@ -1365,7 +1383,7 @@ snat_in2out_lb (snat_main_t *sm,
13651383
s->in2out = l_key;
13661384
s->out2in = e_key;
13671385
s->out2in.protocol = l_key.protocol;
1368-
u->nstaticsessions++;
1386+
user_session_increment (sm, u, 1 /* static */);
13691387

13701388
/* Add to lookup tables */
13711389
s_kv.value = s - tsm->sessions;
@@ -1594,7 +1612,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
15941612
if (is_output_feature)
15951613
{
15961614
if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
1597-
ip0, proto0, udp0->src_port, thread_index)))
1615+
ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0)))
15981616
goto trace00;
15991617
}
16001618
else
@@ -1786,7 +1804,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
17861804
if (is_output_feature)
17871805
{
17881806
if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
1789-
ip1, proto1, udp1->src_port, thread_index)))
1807+
ip1, proto1, udp1->src_port, udp1->dst_port, thread_index, sw_if_index1)))
17901808
goto trace01;
17911809
}
17921810
else
@@ -2014,7 +2032,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
20142032
if (is_output_feature)
20152033
{
20162034
if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
2017-
ip0, proto0, udp0->src_port, thread_index)))
2035+
ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0)))
20182036
goto trace0;
20192037
}
20202038
else

src/plugins/nat/nat.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,11 +1447,22 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
14471447
i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
14481448

14491449
if (sm->num_workers > 1 && !sm->deterministic)
1450-
del_feature_name = "nat44-handoff-classify";
1450+
{
1451+
del_feature_name = "nat44-handoff-classify";
1452+
feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1453+
"nat44-out2in-worker-handoff";
1454+
}
14511455
else if (sm->deterministic)
1452-
del_feature_name = "nat44-det-classify";
1456+
{
1457+
del_feature_name = "nat44-det-classify";
1458+
feature_name = !is_inside ? "nat44-det-in2out" :
1459+
"nat44-det-out2in";
1460+
}
14531461
else
1454-
del_feature_name = "nat44-classify";
1462+
{
1463+
del_feature_name = "nat44-classify";
1464+
feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1465+
}
14551466

14561467
vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
14571468
sw_if_index, 0, 0, 0);

src/plugins/nat/nat.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,4 +650,16 @@ nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector,
650650
}
651651
}
652652

653+
always_inline void
654+
user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
655+
{
656+
if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user)
657+
{
658+
if (is_static)
659+
u->nstaticsessions++;
660+
else
661+
u->nsessions++;
662+
}
663+
}
664+
653665
#endif /* __included_snat_h__ */

src/plugins/nat/out2in.c

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ typedef enum {
133133
SNAT_OUT2IN_NEXT_LOOKUP,
134134
SNAT_OUT2IN_NEXT_ICMP_ERROR,
135135
SNAT_OUT2IN_NEXT_REASS,
136+
SNAT_OUT2IN_NEXT_IN2OUT,
136137
SNAT_OUT2IN_N_NEXT,
137138
} snat_out2in_next_t;
138139

@@ -191,7 +192,7 @@ create_session_for_static_mapping (snat_main_t *sm,
191192
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
192193
s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
193194
s->ext_host_port = udp0->src_port;
194-
u->nstaticsessions++;
195+
user_session_increment (sm, u, 1 /* static */);
195196
s->in2out = in2out;
196197
s->out2in = out2in;
197198
s->in2out.protocol = out2in.protocol;
@@ -311,6 +312,26 @@ icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
311312
return 0;
312313
}
313314

315+
static int
316+
next_src_nat (snat_main_t * sm, ip4_header_t * ip, u32 proto, u16 src_port,
317+
u32 thread_index)
318+
{
319+
snat_session_key_t key;
320+
clib_bihash_kv_8_8_t kv, value;
321+
322+
key.addr = ip->src_address;
323+
key.port = src_port;
324+
key.protocol = proto;
325+
key.fib_index = sm->inside_fib_index;
326+
kv.key = key.as_u64;
327+
328+
if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv,
329+
&value))
330+
return 1;
331+
332+
return 0;
333+
}
334+
314335
static void
315336
create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip)
316337
{
@@ -419,8 +440,13 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node,
419440
}
420441
else
421442
{
422-
create_bypass_for_fwd(sm, ip0);
423443
dont_translate = 1;
444+
if (next_src_nat(sm, ip0, key0.protocol, key0.port, thread_index))
445+
{
446+
next0 = SNAT_OUT2IN_NEXT_IN2OUT;
447+
goto out;
448+
}
449+
create_bypass_for_fwd(sm, ip0);
424450
goto out;
425451
}
426452
}
@@ -618,6 +644,9 @@ static inline u32 icmp_out2in (snat_main_t *sm,
618644
dst_address /* changed member */);
619645
ip0->checksum = ip_csum_fold (sum0);
620646

647+
if (icmp0->checksum == 0)
648+
icmp0->checksum = 0xffff;
649+
621650
if (!icmp_is_error_message (icmp0))
622651
{
623652
new_id0 = sm0.port;
@@ -804,7 +833,7 @@ snat_out2in_unknown_proto (snat_main_t *sm,
804833
s->in2out.addr.as_u32 = new_addr;
805834
s->in2out.fib_index = m->fib_index;
806835
s->in2out.port = s->out2in.port = ip->protocol;
807-
u->nstaticsessions++;
836+
user_session_increment (sm, u, 1 /* static */);
808837

809838
/* Add to lookup tables */
810839
s_kv.value = s - tsm->sessions;
@@ -916,7 +945,7 @@ snat_out2in_lb (snat_main_t *sm,
916945
s->outside_address_index = ~0;
917946
s->out2in = e_key;
918947
s->in2out = l_key;
919-
u->nstaticsessions++;
948+
user_session_increment (sm, u, 1 /* static */);
920949

921950
/* Add to lookup tables */
922951
s_kv.value = s - tsm->sessions;
@@ -1152,6 +1181,11 @@ snat_out2in_node_fn (vlib_main_t * vm,
11521181
}
11531182
else
11541183
{
1184+
if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1185+
{
1186+
next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1187+
goto trace0;
1188+
}
11551189
create_bypass_for_fwd(sm, ip0);
11561190
goto trace0;
11571191
}
@@ -1319,6 +1353,11 @@ snat_out2in_node_fn (vlib_main_t * vm,
13191353
}
13201354
else
13211355
{
1356+
if (next_src_nat(sm, ip1, proto1, udp1->src_port, thread_index))
1357+
{
1358+
next1 = SNAT_OUT2IN_NEXT_IN2OUT;
1359+
goto trace1;
1360+
}
13221361
create_bypass_for_fwd(sm, ip1);
13231362
goto trace1;
13241363
}
@@ -1522,6 +1561,11 @@ snat_out2in_node_fn (vlib_main_t * vm,
15221561
}
15231562
else
15241563
{
1564+
if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1565+
{
1566+
next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1567+
goto trace00;
1568+
}
15251569
create_bypass_for_fwd(sm, ip0);
15261570
goto trace00;
15271571
}
@@ -1649,6 +1693,7 @@ VLIB_REGISTER_NODE (snat_out2in_node) = {
16491693
[SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
16501694
[SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
16511695
[SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1696+
[SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
16521697
},
16531698
};
16541699
VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
@@ -1765,6 +1810,11 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
17651810
}
17661811
else
17671812
{
1813+
if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1814+
{
1815+
next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1816+
goto trace0;
1817+
}
17681818
create_bypass_for_fwd(sm, ip0);
17691819
goto trace0;
17701820
}
@@ -1936,6 +1986,7 @@ VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
19361986
[SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
19371987
[SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
19381988
[SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1989+
[SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
19391990
},
19401991
};
19411992
VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
@@ -2425,6 +2476,7 @@ VLIB_REGISTER_NODE (snat_det_out2in_node) = {
24252476
[SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
24262477
[SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
24272478
[SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2479+
[SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
24282480
},
24292481
};
24302482
VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn);
@@ -2918,6 +2970,7 @@ VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
29182970
[SNAT_OUT2IN_NEXT_DROP] = "error-drop",
29192971
[SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
29202972
[SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2973+
[SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
29212974
},
29222975
};
29232976
VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);

0 commit comments

Comments
 (0)