Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /**
16 : * @file
17 : * @brief NAT44 EI inside to outside network translation
18 : */
19 :
20 : #include <vlib/vlib.h>
21 :
22 : #include <vnet/vnet.h>
23 : #include <vnet/ip/ip.h>
24 : #include <vnet/ethernet/ethernet.h>
25 : #include <vnet/udp/udp_local.h>
26 : #include <vnet/fib/ip4_fib.h>
27 :
28 : #include <vppinfra/hash.h>
29 : #include <vppinfra/error.h>
30 :
31 : #include <nat/lib/log.h>
32 : #include <nat/lib/nat_syslog.h>
33 : #include <nat/lib/ipfix_logging.h>
34 : #include <nat/lib/nat_inlines.h>
35 : #include <nat/nat44-ei/nat44_ei_inlines.h>
36 : #include <nat/nat44-ei/nat44_ei.h>
37 :
38 : extern vnet_feature_arc_registration_t vnet_feat_arc_ip4_local;
39 :
40 : #define foreach_nat44_ei_in2out_error \
41 : _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \
42 : _ (OUT_OF_PORTS, "out of ports") \
43 : _ (BAD_OUTSIDE_FIB, "outside VRF ID not found") \
44 : _ (BAD_ICMP_TYPE, "unsupported ICMP type") \
45 : _ (NO_TRANSLATION, "no translation") \
46 : _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
47 : _ (CANNOT_CREATE_USER, "cannot create NAT user")
48 :
49 : #define foreach_nat44_ei_hairpinning_handoff_error \
50 : _ (CONGESTION_DROP, "congestion drop")
51 :
52 : typedef enum
53 : {
54 : #define _(sym, str) NAT44_EI_IN2OUT_ERROR_##sym,
55 : foreach_nat44_ei_in2out_error
56 : #undef _
57 : NAT44_EI_IN2OUT_N_ERROR,
58 : } nat44_ei_in2out_error_t;
59 :
60 : static char *nat44_ei_in2out_error_strings[] = {
61 : #define _(sym,string) string,
62 : foreach_nat44_ei_in2out_error
63 : #undef _
64 : };
65 :
66 : typedef enum
67 : {
68 : #define _(sym, str) NAT44_EI_HAIRPINNING_HANDOFF_ERROR_##sym,
69 : foreach_nat44_ei_hairpinning_handoff_error
70 : #undef _
71 : NAT44_EI_HAIRPINNING_HANDOFF_N_ERROR,
72 : } nat44_ei_hairpinning_handoff_error_t;
73 :
74 : static char *nat44_ei_hairpinning_handoff_error_strings[] = {
75 : #define _(sym, string) string,
76 : foreach_nat44_ei_hairpinning_handoff_error
77 : #undef _
78 : };
79 :
80 : typedef enum
81 : {
82 : NAT44_EI_IN2OUT_NEXT_LOOKUP,
83 : NAT44_EI_IN2OUT_NEXT_DROP,
84 : NAT44_EI_IN2OUT_NEXT_ICMP_ERROR,
85 : NAT44_EI_IN2OUT_NEXT_SLOW_PATH,
86 : NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF,
87 : NAT44_EI_IN2OUT_N_NEXT,
88 : } nat44_ei_in2out_next_t;
89 :
90 : typedef enum
91 : {
92 : NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP,
93 : NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP,
94 : NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
95 : } nat44_ei_in2out_hairpinnig_finish_next_t;
96 :
97 : typedef enum
98 : {
99 : NAT44_EI_HAIRPIN_NEXT_LOOKUP,
100 : NAT44_EI_HAIRPIN_NEXT_DROP,
101 : NAT44_EI_HAIRPIN_NEXT_HANDOFF,
102 : NAT44_EI_HAIRPIN_N_NEXT,
103 : } nat44_ei_hairpin_next_t;
104 :
105 : typedef struct
106 : {
107 : u32 sw_if_index;
108 : u32 next_index;
109 : u32 session_index;
110 : u32 is_slow_path;
111 : u32 is_hairpinning;
112 : } nat44_ei_in2out_trace_t;
113 :
114 : typedef struct
115 : {
116 : ip4_address_t addr;
117 : u16 port;
118 : u32 fib_index;
119 : u32 session_index;
120 : } nat44_ei_hairpin_trace_t;
121 :
122 : typedef struct
123 : {
124 : u32 next_worker_index;
125 : } nat44_ei_hairpinning_handoff_trace_t;
126 :
127 : static u8 *
128 334 : format_nat44_ei_in2out_trace (u8 *s, va_list *args)
129 : {
130 334 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
131 334 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
132 334 : nat44_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *);
133 : char *tag;
134 334 : tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
135 334 : s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
136 : t->sw_if_index, t->next_index, t->session_index);
137 334 : if (t->is_hairpinning)
138 0 : s = format (s, ", with-hairpinning");
139 334 : return s;
140 : }
141 :
142 : static u8 *
143 0 : format_nat44_ei_in2out_fast_trace (u8 *s, va_list *args)
144 : {
145 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
146 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
147 0 : nat44_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *);
148 0 : s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
149 : t->sw_if_index, t->next_index);
150 0 : return s;
151 : }
152 :
153 : static u8 *
154 7 : format_nat44_ei_hairpin_trace (u8 *s, va_list *args)
155 : {
156 7 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
157 7 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
158 7 : nat44_ei_hairpin_trace_t *t = va_arg (*args, nat44_ei_hairpin_trace_t *);
159 :
160 7 : s = format (s, "new dst addr %U port %u fib-index %u", format_ip4_address,
161 7 : &t->addr, clib_net_to_host_u16 (t->port), t->fib_index);
162 7 : if (~0 == t->session_index)
163 : {
164 4 : s = format (s, " is-static-mapping");
165 : }
166 : else
167 : {
168 3 : s = format (s, " session-index %u", t->session_index);
169 : }
170 :
171 7 : return s;
172 : }
173 :
174 : static u8 *
175 1 : format_nat44_ei_hairpinning_handoff_trace (u8 *s, va_list *args)
176 : {
177 1 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
178 1 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
179 1 : nat44_ei_hairpinning_handoff_trace_t *t =
180 : va_arg (*args, nat44_ei_hairpinning_handoff_trace_t *);
181 :
182 1 : s = format (s, "nat44-ei-hairpinning-handoff: next-worker %d",
183 : t->next_worker_index);
184 :
185 1 : return s;
186 : }
187 :
188 : static_always_inline int
189 10450 : nat44_ei_not_translate_fast (vlib_node_runtime_t *node, u32 sw_if_index0,
190 : ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
191 : {
192 10450 : nat44_ei_main_t *nm = &nat44_ei_main;
193 :
194 10450 : if (nm->out2in_dpo)
195 0 : return 0;
196 :
197 10450 : fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
198 : nat44_ei_outside_fib_t *outside_fib;
199 10450 : fib_prefix_t pfx = {
200 : .fp_proto = FIB_PROTOCOL_IP4,
201 : .fp_len = 32,
202 : .fp_addr = {
203 10450 : .ip4.as_u32 = ip0->dst_address.as_u32,
204 : }
205 : ,
206 : };
207 :
208 : /* Don't NAT packet aimed at the intfc address */
209 10450 : if (PREDICT_FALSE (nat44_ei_is_interface_addr (
210 : nm->ip4_main, node, sw_if_index0, ip0->dst_address.as_u32)))
211 0 : return 1;
212 :
213 10450 : fei = fib_table_lookup (rx_fib_index0, &pfx);
214 10450 : if (FIB_NODE_INDEX_INVALID != fei)
215 : {
216 10450 : u32 sw_if_index = fib_entry_get_resolving_interface (fei);
217 10450 : if (sw_if_index == ~0)
218 : {
219 27 : vec_foreach (outside_fib, nm->outside_fibs)
220 : {
221 27 : fei = fib_table_lookup (outside_fib->fib_index, &pfx);
222 27 : if (FIB_NODE_INDEX_INVALID != fei)
223 : {
224 27 : sw_if_index = fib_entry_get_resolving_interface (fei);
225 27 : if (sw_if_index != ~0)
226 24 : break;
227 : }
228 : }
229 : }
230 10450 : if (sw_if_index == ~0)
231 0 : return 1;
232 :
233 : nat44_ei_interface_t *i;
234 20932 : pool_foreach (i, nm->interfaces)
235 : {
236 : /* NAT packet aimed at outside interface */
237 20920 : if ((nat44_ei_interface_is_outside (i)) &&
238 10453 : (sw_if_index == i->sw_if_index))
239 10438 : return 0;
240 : }
241 : }
242 :
243 12 : return 1;
244 : }
245 :
246 : static_always_inline int
247 10482 : nat44_ei_not_translate (nat44_ei_main_t *nm, vlib_node_runtime_t *node,
248 : u32 sw_if_index0, ip4_header_t *ip0, u32 proto0,
249 : u32 rx_fib_index0, u32 thread_index)
250 : {
251 10482 : udp_header_t *udp0 = ip4_next_header (ip0);
252 : clib_bihash_kv_8_8_t kv0, value0;
253 :
254 10482 : init_nat_k (&kv0, ip0->dst_address, udp0->dst_port, nm->outside_fib_index,
255 : proto0);
256 :
257 : /* NAT packet aimed at external address if */
258 : /* has active sessions */
259 10482 : if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
260 : {
261 : /* or is static mappings */
262 : ip4_address_t placeholder_addr;
263 : u16 placeholder_port;
264 : u32 placeholder_fib_index;
265 10471 : if (!nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port,
266 : nm->outside_fib_index, proto0,
267 : &placeholder_addr, &placeholder_port,
268 : &placeholder_fib_index, 1, 0, 0))
269 17 : return 0;
270 : }
271 : else
272 11 : return 0;
273 :
274 10454 : if (nm->forwarding_enabled)
275 4 : return 1;
276 :
277 10450 : return nat44_ei_not_translate_fast (node, sw_if_index0, ip0, proto0,
278 : rx_fib_index0);
279 : }
280 :
281 : static_always_inline int
282 10 : nat44_ei_not_translate_output_feature (nat44_ei_main_t *nm, ip4_header_t *ip0,
283 : u32 proto0, u16 src_port, u16 dst_port,
284 : u32 thread_index, u32 sw_if_index)
285 : {
286 : clib_bihash_kv_8_8_t kv0, value0;
287 : nat44_ei_interface_t *i;
288 :
289 : /* src NAT check */
290 10 : init_nat_k (&kv0, ip0->src_address, src_port,
291 : ip4_fib_table_get_index_for_sw_if_index (sw_if_index), proto0);
292 :
293 10 : if (!clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
294 0 : return 1;
295 :
296 : /* dst NAT check */
297 10 : init_nat_k (&kv0, ip0->dst_address, dst_port,
298 : ip4_fib_table_get_index_for_sw_if_index (sw_if_index), proto0);
299 10 : if (!clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
300 : {
301 : /* hairpinning */
302 1 : pool_foreach (i, nm->output_feature_interfaces)
303 : {
304 1 : if ((nat44_ei_interface_is_inside (i)) &&
305 1 : (sw_if_index == i->sw_if_index))
306 1 : return 0;
307 : }
308 0 : return 1;
309 : }
310 :
311 9 : return 0;
312 : }
313 :
314 : #ifndef CLIB_MARCH_VARIANT
315 : int
316 0 : nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
317 : {
318 0 : nat44_ei_main_t *nm = &nat44_ei_main;
319 0 : nat44_ei_is_idle_session_ctx_t *ctx = arg;
320 : nat44_ei_session_t *s;
321 : u64 sess_timeout_time;
322 0 : nat44_ei_main_per_thread_data_t *tnm =
323 0 : vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
324 : clib_bihash_kv_8_8_t s_kv;
325 :
326 0 : if (ctx->thread_index != nat_value_get_thread_index (kv))
327 : {
328 0 : return 0;
329 : }
330 :
331 0 : s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (kv));
332 0 : sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
333 0 : &nm->timeouts, s->nat_proto, s->state);
334 0 : if (ctx->now >= sess_timeout_time)
335 : {
336 0 : init_nat_o2i_k (&s_kv, s);
337 0 : if (clib_bihash_add_del_8_8 (&nm->out2in, &s_kv, 0))
338 0 : nat_elog_warn (nm, "out2in key del failed");
339 :
340 0 : nat_ipfix_logging_nat44_ses_delete (
341 : ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
342 0 : nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
343 : s->in2out.fib_index);
344 :
345 0 : nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
346 0 : &s->in2out.addr, s->in2out.port,
347 0 : &s->out2in.addr, s->out2in.port, s->nat_proto);
348 :
349 0 : nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
350 0 : s->ext_host_port, s->nat_proto, s->out2in.fib_index,
351 : ctx->thread_index);
352 :
353 0 : if (!nat44_ei_is_session_static (s))
354 0 : nat44_ei_free_outside_address_and_port (
355 0 : nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
356 : s->nat_proto);
357 :
358 0 : nat44_ei_delete_session (nm, s, ctx->thread_index);
359 0 : return 1;
360 : }
361 :
362 0 : return 0;
363 : }
364 : #endif
365 :
366 : static u32
367 10476 : slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0,
368 : ip4_address_t i2o_addr, u16 i2o_port, u32 rx_fib_index0,
369 : nat_protocol_t nat_proto, nat44_ei_session_t **sessionp,
370 : vlib_node_runtime_t *node, u32 next0, u32 thread_index, f64 now)
371 : {
372 : nat44_ei_user_t *u;
373 10476 : nat44_ei_session_t *s = 0;
374 : clib_bihash_kv_8_8_t kv0;
375 10476 : u8 is_sm = 0;
376 : nat44_ei_outside_fib_t *outside_fib;
377 10476 : fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
378 : u8 identity_nat;
379 10476 : fib_prefix_t pfx = {
380 : .fp_proto = FIB_PROTOCOL_IP4,
381 : .fp_len = 32,
382 : .fp_addr = {
383 10476 : .ip4.as_u32 = ip0->dst_address.as_u32,
384 : },
385 : };
386 : nat44_ei_is_idle_session_ctx_t ctx0;
387 : ip4_address_t sm_addr;
388 : u16 sm_port;
389 : u32 sm_fib_index;
390 :
391 10476 : if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
392 : {
393 1 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
394 1 : nat_ipfix_logging_max_sessions (thread_index,
395 : nm->max_translations_per_thread);
396 1 : nat_elog_notice (nm, "maximum sessions exceeded");
397 1 : return NAT44_EI_IN2OUT_NEXT_DROP;
398 : }
399 :
400 : /* First try to match static mapping by local address and port */
401 10475 : if (nat44_ei_static_mapping_match (i2o_addr, i2o_port, rx_fib_index0,
402 : nat_proto, &sm_addr, &sm_port,
403 : &sm_fib_index, 0, 0, &identity_nat))
404 : {
405 : /* Try to create dynamic translation */
406 10443 : if (nm->alloc_addr_and_port (
407 : nm->addresses, rx_fib_index0, thread_index, nat_proto,
408 10443 : ip0->src_address, &sm_addr, &sm_port, nm->port_per_thread,
409 10443 : nm->per_thread_data[thread_index].snat_thread_index))
410 : {
411 7 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_OUT_OF_PORTS];
412 7 : return NAT44_EI_IN2OUT_NEXT_DROP;
413 : }
414 : }
415 : else
416 : {
417 32 : if (PREDICT_FALSE (identity_nat))
418 : {
419 0 : *sessionp = s;
420 0 : return next0;
421 : }
422 :
423 32 : is_sm = 1;
424 : }
425 :
426 10468 : u = nat44_ei_user_get_or_create (nm, &ip0->src_address, rx_fib_index0,
427 : thread_index);
428 10468 : if (!u)
429 : {
430 0 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_CANNOT_CREATE_USER];
431 0 : return NAT44_EI_IN2OUT_NEXT_DROP;
432 : }
433 :
434 10468 : s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
435 10468 : if (!s)
436 : {
437 0 : nat44_ei_delete_user_with_no_session (nm, u, thread_index);
438 0 : nat_elog_warn (nm, "create NAT session failed");
439 0 : return NAT44_EI_IN2OUT_NEXT_DROP;
440 : }
441 :
442 10468 : if (is_sm)
443 32 : s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
444 10468 : nat44_ei_user_session_increment (nm, u, is_sm);
445 10468 : s->in2out.addr = i2o_addr;
446 10468 : s->in2out.port = i2o_port;
447 10468 : s->in2out.fib_index = rx_fib_index0;
448 10468 : s->nat_proto = nat_proto;
449 10468 : s->out2in.addr = sm_addr;
450 10468 : s->out2in.port = sm_port;
451 10468 : s->out2in.fib_index = nm->outside_fib_index;
452 10468 : switch (vec_len (nm->outside_fibs))
453 : {
454 0 : case 0:
455 0 : s->out2in.fib_index = nm->outside_fib_index;
456 0 : break;
457 10462 : case 1:
458 10462 : s->out2in.fib_index = nm->outside_fibs[0].fib_index;
459 10462 : break;
460 6 : default:
461 9 : vec_foreach (outside_fib, nm->outside_fibs)
462 : {
463 9 : fei = fib_table_lookup (outside_fib->fib_index, &pfx);
464 9 : if (FIB_NODE_INDEX_INVALID != fei)
465 : {
466 9 : if (fib_entry_get_resolving_interface (fei) != ~0)
467 : {
468 6 : s->out2in.fib_index = outside_fib->fib_index;
469 6 : break;
470 : }
471 : }
472 : }
473 6 : break;
474 : }
475 10468 : s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
476 10468 : s->ext_host_port = vnet_buffer (b0)->ip.reass.l4_dst_port;
477 10468 : *sessionp = s;
478 :
479 : /* Add to translation hashes */
480 10468 : ctx0.now = now;
481 10468 : ctx0.thread_index = thread_index;
482 10468 : init_nat_i2o_kv (&kv0, s, thread_index,
483 10468 : s - nm->per_thread_data[thread_index].sessions);
484 10468 : if (clib_bihash_add_or_overwrite_stale_8_8 (
485 : &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
486 0 : nat_elog_notice (nm, "in2out key add failed");
487 :
488 10468 : init_nat_o2i_kv (&kv0, s, thread_index,
489 10468 : s - nm->per_thread_data[thread_index].sessions);
490 10468 : if (clib_bihash_add_or_overwrite_stale_8_8 (
491 : &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
492 0 : nat_elog_notice (nm, "out2in key add failed");
493 :
494 : /* log NAT event */
495 10468 : nat_ipfix_logging_nat44_ses_create (
496 : thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
497 10468 : nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
498 : s->in2out.fib_index);
499 :
500 10468 : nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index, &s->in2out.addr,
501 10468 : s->in2out.port, &s->out2in.addr, s->out2in.port,
502 : s->nat_proto);
503 :
504 10468 : nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
505 10468 : s->out2in.port, &s->ext_host_addr, s->ext_host_port,
506 10468 : &s->ext_host_nat_addr, s->ext_host_nat_port, s->nat_proto,
507 10468 : s->in2out.fib_index, s->flags, thread_index, 0);
508 :
509 10468 : return next0;
510 : }
511 :
512 : static_always_inline nat44_ei_in2out_error_t
513 63 : icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
514 : u16 *port, nat_protocol_t *nat_proto)
515 : {
516 : icmp46_header_t *icmp0;
517 63 : icmp_echo_header_t *echo0, *inner_echo0 = 0;
518 63 : ip4_header_t *inner_ip0 = 0;
519 63 : void *l4_header = 0;
520 : icmp46_header_t *inner_icmp0;
521 :
522 63 : icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
523 63 : echo0 = (icmp_echo_header_t *) (icmp0 + 1);
524 :
525 63 : if (!icmp_type_is_error_message
526 63 : (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
527 : {
528 59 : *nat_proto = NAT_PROTOCOL_ICMP;
529 59 : *addr = ip0->src_address;
530 59 : *port = vnet_buffer (b)->ip.reass.l4_src_port;
531 : }
532 : else
533 : {
534 4 : inner_ip0 = (ip4_header_t *) (echo0 + 1);
535 4 : l4_header = ip4_next_header (inner_ip0);
536 4 : *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
537 4 : *addr = inner_ip0->dst_address;
538 4 : switch (*nat_proto)
539 : {
540 1 : case NAT_PROTOCOL_ICMP:
541 1 : inner_icmp0 = (icmp46_header_t *) l4_header;
542 1 : inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
543 1 : *port = inner_echo0->identifier;
544 1 : break;
545 3 : case NAT_PROTOCOL_UDP:
546 : case NAT_PROTOCOL_TCP:
547 3 : *port = ((tcp_udp_header_t *) l4_header)->dst_port;
548 3 : break;
549 0 : default:
550 0 : return NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
551 : }
552 : }
553 63 : return -1; /* success */
554 : }
555 :
556 : static_always_inline u32
557 63 : nat44_ei_icmp_match_in2out_slow (vlib_node_runtime_t *node, u32 thread_index,
558 : vlib_buffer_t *b0, ip4_header_t *ip0,
559 : ip4_address_t *addr, u16 *port,
560 : u32 *fib_index, nat_protocol_t *proto,
561 : nat44_ei_session_t **p_s0, u8 *dont_translate)
562 : {
563 63 : nat44_ei_main_t *nm = &nat44_ei_main;
564 63 : nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
565 : u32 sw_if_index0;
566 63 : nat44_ei_session_t *s0 = 0;
567 : clib_bihash_kv_8_8_t kv0, value0;
568 63 : u32 next0 = ~0;
569 : int err;
570 63 : vlib_main_t *vm = vlib_get_main ();
571 63 : *dont_translate = 0;
572 :
573 63 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
574 63 : *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
575 :
576 63 : err = icmp_get_key (b0, ip0, addr, port, proto);
577 63 : if (err != -1)
578 : {
579 0 : b0->error = node->errors[err];
580 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
581 0 : goto out;
582 : }
583 :
584 63 : init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
585 63 : if (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
586 : {
587 44 : if (vnet_buffer (b0)->sw_if_index[VLIB_TX] != ~0)
588 : {
589 3 : if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
590 : nm, ip0, *proto, *port, *port, thread_index, sw_if_index0)))
591 : {
592 0 : *dont_translate = 1;
593 0 : goto out;
594 : }
595 : }
596 : else
597 : {
598 41 : if (PREDICT_FALSE (nat44_ei_not_translate (
599 : nm, node, sw_if_index0, ip0, NAT_PROTOCOL_ICMP, *fib_index,
600 : thread_index)))
601 : {
602 4 : *dont_translate = 1;
603 4 : goto out;
604 : }
605 : }
606 :
607 40 : if (PREDICT_FALSE
608 : (icmp_type_is_error_message
609 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)))
610 : {
611 0 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
612 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
613 0 : goto out;
614 : }
615 :
616 40 : next0 = slow_path (nm, b0, ip0, *addr, *port, *fib_index, *proto, &s0,
617 : node, next0, thread_index, vlib_time_now (vm));
618 :
619 40 : if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
620 1 : goto out;
621 :
622 39 : if (!s0)
623 : {
624 0 : *dont_translate = 1;
625 0 : goto out;
626 : }
627 : }
628 : else
629 : {
630 19 : if (PREDICT_FALSE
631 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
632 : ICMP4_echo_request
633 : && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
634 : ICMP4_echo_reply
635 : && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
636 : reass.icmp_type_or_tcp_flags)))
637 : {
638 0 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
639 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
640 0 : goto out;
641 : }
642 :
643 19 : s0 = pool_elt_at_index (tnm->sessions,
644 : nat_value_get_session_index (&value0));
645 : }
646 :
647 63 : out:
648 63 : if (s0)
649 : {
650 58 : *addr = s0->out2in.addr;
651 58 : *port = s0->out2in.port;
652 58 : *fib_index = s0->out2in.fib_index;
653 : }
654 63 : if (p_s0)
655 63 : *p_s0 = s0;
656 63 : return next0;
657 : }
658 :
659 : static_always_inline u32
660 0 : nat44_ei_icmp_match_in2out_fast (vlib_node_runtime_t *node, u32 thread_index,
661 : vlib_buffer_t *b0, ip4_header_t *ip0,
662 : ip4_address_t *addr, u16 *port,
663 : u32 *fib_index, nat_protocol_t *proto,
664 : nat44_ei_session_t **s0, u8 *dont_translate)
665 : {
666 : u32 sw_if_index0;
667 : u8 is_addr_only;
668 0 : u32 next0 = ~0;
669 : int err;
670 0 : *dont_translate = 0;
671 :
672 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
673 0 : *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
674 :
675 0 : err = icmp_get_key (b0, ip0, addr, port, proto);
676 0 : if (err != -1)
677 : {
678 0 : b0->error = node->errors[err];
679 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
680 0 : goto out;
681 : }
682 :
683 : ip4_address_t sm_addr;
684 : u16 sm_port;
685 : u32 sm_fib_index;
686 :
687 0 : if (nat44_ei_static_mapping_match (*addr, *port, *fib_index, *proto,
688 : &sm_addr, &sm_port, &sm_fib_index, 0,
689 : &is_addr_only, 0))
690 : {
691 0 : if (PREDICT_FALSE (nat44_ei_not_translate_fast (
692 : node, sw_if_index0, ip0, IP_PROTOCOL_ICMP, *fib_index)))
693 : {
694 0 : *dont_translate = 1;
695 0 : goto out;
696 : }
697 :
698 0 : if (icmp_type_is_error_message
699 0 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
700 : {
701 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
702 0 : goto out;
703 : }
704 :
705 0 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_NO_TRANSLATION];
706 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
707 0 : goto out;
708 : }
709 :
710 0 : if (PREDICT_FALSE
711 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
712 : && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
713 : ICMP4_echo_reply || !is_addr_only)
714 : && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
715 : reass.icmp_type_or_tcp_flags)))
716 : {
717 0 : b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
718 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
719 0 : goto out;
720 : }
721 :
722 0 : out:
723 0 : return next0;
724 : }
725 :
726 : static_always_inline u32
727 56 : nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0,
728 : u32 thread_index, ip4_header_t *ip0,
729 : icmp46_header_t *icmp0, u32 *required_thread_index)
730 : {
731 : clib_bihash_kv_8_8_t kv0, value0;
732 : u32 old_dst_addr0, new_dst_addr0;
733 : u32 old_addr0, new_addr0;
734 : u16 old_port0, new_port0;
735 : u16 old_checksum0, new_checksum0;
736 56 : u32 si, ti = 0;
737 : ip_csum_t sum0;
738 : nat44_ei_session_t *s0;
739 : nat44_ei_static_mapping_t *m0;
740 :
741 56 : if (icmp_type_is_error_message (
742 56 : vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
743 : {
744 4 : ip4_header_t *inner_ip0 = 0;
745 4 : tcp_udp_header_t *l4_header = 0;
746 :
747 4 : inner_ip0 = (ip4_header_t *) ((icmp_echo_header_t *) (icmp0 + 1) + 1);
748 4 : l4_header = ip4_next_header (inner_ip0);
749 4 : u32 protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
750 :
751 4 : if (protocol != NAT_PROTOCOL_TCP && protocol != NAT_PROTOCOL_UDP)
752 1 : return 1;
753 :
754 3 : init_nat_k (&kv0, ip0->dst_address, l4_header->src_port,
755 : nm->outside_fib_index, protocol);
756 3 : if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
757 3 : return 1;
758 0 : ti = nat_value_get_thread_index (&value0);
759 0 : if (ti != thread_index)
760 : {
761 0 : *required_thread_index = ti;
762 0 : return 1;
763 : }
764 0 : si = nat_value_get_session_index (&value0);
765 0 : s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si);
766 0 : new_dst_addr0 = s0->in2out.addr.as_u32;
767 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
768 :
769 : /* update inner source IP address */
770 0 : old_addr0 = inner_ip0->src_address.as_u32;
771 0 : inner_ip0->src_address.as_u32 = new_dst_addr0;
772 0 : new_addr0 = inner_ip0->src_address.as_u32;
773 0 : sum0 = icmp0->checksum;
774 : sum0 =
775 0 : ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address);
776 0 : icmp0->checksum = ip_csum_fold (sum0);
777 :
778 : /* update inner IP header checksum */
779 0 : old_checksum0 = inner_ip0->checksum;
780 0 : sum0 = inner_ip0->checksum;
781 : sum0 =
782 0 : ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address);
783 0 : inner_ip0->checksum = ip_csum_fold (sum0);
784 0 : new_checksum0 = inner_ip0->checksum;
785 0 : sum0 = icmp0->checksum;
786 0 : sum0 = ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
787 : checksum);
788 0 : icmp0->checksum = ip_csum_fold (sum0);
789 :
790 : /* update inner source port */
791 0 : old_port0 = l4_header->src_port;
792 0 : l4_header->src_port = s0->in2out.port;
793 0 : new_port0 = l4_header->src_port;
794 0 : sum0 = icmp0->checksum;
795 0 : sum0 = ip_csum_update (sum0, old_port0, new_port0, tcp_udp_header_t,
796 : src_port);
797 0 : icmp0->checksum = ip_csum_fold (sum0);
798 : }
799 : else
800 : {
801 52 : init_nat_k (&kv0, ip0->dst_address, 0, nm->outside_fib_index, 0);
802 52 : if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv0,
803 : &value0))
804 : {
805 43 : icmp_echo_header_t *echo0 = (icmp_echo_header_t *) (icmp0 + 1);
806 43 : u16 icmp_id0 = echo0->identifier;
807 43 : init_nat_k (&kv0, ip0->dst_address, icmp_id0, nm->outside_fib_index,
808 : NAT_PROTOCOL_ICMP);
809 43 : int rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0);
810 43 : if (!rv)
811 : {
812 3 : ti = nat_value_get_thread_index (&value0);
813 3 : if (ti != thread_index)
814 : {
815 1 : *required_thread_index = ti;
816 1 : return 1;
817 : }
818 2 : si = nat_value_get_session_index (&value0);
819 2 : s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si);
820 2 : new_dst_addr0 = s0->in2out.addr.as_u32;
821 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
822 2 : echo0->identifier = s0->in2out.port;
823 2 : sum0 = icmp0->checksum;
824 2 : sum0 = ip_csum_update (sum0, icmp_id0, s0->in2out.port,
825 : icmp_echo_header_t, identifier);
826 2 : icmp0->checksum = ip_csum_fold (sum0);
827 2 : goto change_addr;
828 : }
829 :
830 40 : return 1;
831 : }
832 :
833 9 : m0 = pool_elt_at_index (nm->static_mappings, value0.value);
834 :
835 9 : new_dst_addr0 = m0->local_addr.as_u32;
836 9 : if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
837 9 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = m0->fib_index;
838 : }
839 0 : change_addr:
840 : /* Destination is behind the same NAT, use internal address and port */
841 11 : if (new_dst_addr0)
842 : {
843 11 : old_dst_addr0 = ip0->dst_address.as_u32;
844 11 : ip0->dst_address.as_u32 = new_dst_addr0;
845 11 : sum0 = ip0->checksum;
846 11 : sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t,
847 : dst_address);
848 11 : ip0->checksum = ip_csum_fold (sum0);
849 : }
850 11 : return 0;
851 : }
852 :
853 : static_always_inline u32
854 63 : nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0,
855 : icmp46_header_t *icmp0, u32 sw_if_index0,
856 : u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
857 : u32 thread_index, nat44_ei_session_t **p_s0)
858 : {
859 63 : nat44_ei_main_t *nm = &nat44_ei_main;
860 63 : vlib_main_t *vm = vlib_get_main ();
861 : ip4_address_t addr;
862 : u16 port;
863 : u32 fib_index;
864 : nat_protocol_t proto;
865 63 : icmp_echo_header_t *echo0, *inner_echo0 = 0;
866 : ip4_header_t *inner_ip0;
867 63 : void *l4_header = 0;
868 : icmp46_header_t *inner_icmp0;
869 : u8 dont_translate;
870 : u32 new_addr0, old_addr0;
871 : u16 old_id0, new_id0;
872 : u16 old_checksum0, new_checksum0;
873 : ip_csum_t sum0;
874 : u16 checksum0;
875 : u32 next0_tmp;
876 63 : u32 required_thread_index = thread_index;
877 :
878 63 : echo0 = (icmp_echo_header_t *) (icmp0 + 1);
879 :
880 63 : if (PREDICT_TRUE (nm->pat))
881 : {
882 63 : next0_tmp = nat44_ei_icmp_match_in2out_slow (
883 : node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
884 : &dont_translate);
885 : }
886 : else
887 : {
888 0 : next0_tmp = nat44_ei_icmp_match_in2out_fast (
889 : node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
890 : &dont_translate);
891 : }
892 :
893 63 : if (next0_tmp != ~0)
894 1 : next0 = next0_tmp;
895 63 : if (next0 == NAT44_EI_IN2OUT_NEXT_DROP || dont_translate)
896 5 : goto out;
897 :
898 58 : if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
899 : {
900 : sum0 =
901 92 : ip_incremental_checksum_buffer (vm, b0,
902 46 : (u8 *) icmp0 -
903 46 : (u8 *) vlib_buffer_get_current (b0),
904 46 : ntohs (ip0->length) -
905 46 : ip4_header_bytes (ip0), 0);
906 46 : checksum0 = ~ip_csum_fold (sum0);
907 46 : if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
908 : {
909 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
910 0 : goto out;
911 : }
912 : }
913 :
914 58 : old_addr0 = ip0->src_address.as_u32;
915 58 : new_addr0 = ip0->src_address.as_u32 = addr.as_u32;
916 :
917 58 : sum0 = ip0->checksum;
918 58 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
919 : src_address /* changed member */ );
920 58 : ip0->checksum = ip_csum_fold (sum0);
921 :
922 58 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
923 : {
924 50 : if (icmp0->checksum == 0)
925 0 : icmp0->checksum = 0xffff;
926 :
927 50 : if (!icmp_type_is_error_message (icmp0->type))
928 : {
929 46 : new_id0 = port;
930 46 : if (PREDICT_FALSE (new_id0 != echo0->identifier))
931 : {
932 32 : old_id0 = echo0->identifier;
933 32 : new_id0 = port;
934 32 : echo0->identifier = new_id0;
935 :
936 32 : sum0 = icmp0->checksum;
937 : sum0 =
938 32 : ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
939 : identifier);
940 32 : icmp0->checksum = ip_csum_fold (sum0);
941 : }
942 : }
943 : else
944 : {
945 4 : inner_ip0 = (ip4_header_t *) (echo0 + 1);
946 4 : l4_header = ip4_next_header (inner_ip0);
947 :
948 4 : if (!ip4_header_checksum_is_valid (inner_ip0))
949 : {
950 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
951 0 : goto out;
952 : }
953 :
954 : /* update inner destination IP address */
955 4 : old_addr0 = inner_ip0->dst_address.as_u32;
956 4 : inner_ip0->dst_address = addr;
957 4 : new_addr0 = inner_ip0->dst_address.as_u32;
958 4 : sum0 = icmp0->checksum;
959 4 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
960 : dst_address /* changed member */ );
961 4 : icmp0->checksum = ip_csum_fold (sum0);
962 :
963 : /* update inner IP header checksum */
964 4 : old_checksum0 = inner_ip0->checksum;
965 4 : sum0 = inner_ip0->checksum;
966 4 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
967 : dst_address /* changed member */ );
968 4 : inner_ip0->checksum = ip_csum_fold (sum0);
969 4 : new_checksum0 = inner_ip0->checksum;
970 4 : sum0 = icmp0->checksum;
971 : sum0 =
972 4 : ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
973 : checksum);
974 4 : icmp0->checksum = ip_csum_fold (sum0);
975 :
976 4 : switch (proto)
977 : {
978 1 : case NAT_PROTOCOL_ICMP:
979 1 : inner_icmp0 = (icmp46_header_t *) l4_header;
980 1 : inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
981 :
982 1 : old_id0 = inner_echo0->identifier;
983 1 : new_id0 = port;
984 1 : inner_echo0->identifier = new_id0;
985 :
986 1 : sum0 = icmp0->checksum;
987 : sum0 =
988 1 : ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
989 : identifier);
990 1 : icmp0->checksum = ip_csum_fold (sum0);
991 1 : break;
992 3 : case NAT_PROTOCOL_UDP:
993 : case NAT_PROTOCOL_TCP:
994 3 : old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
995 3 : new_id0 = port;
996 3 : ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
997 :
998 3 : sum0 = icmp0->checksum;
999 3 : sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
1000 : dst_port);
1001 3 : icmp0->checksum = ip_csum_fold (sum0);
1002 3 : break;
1003 0 : default:
1004 0 : ASSERT (0);
1005 : }
1006 : }
1007 : }
1008 :
1009 58 : if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
1010 : {
1011 55 : if (0 != nat44_ei_icmp_hairpinning (nm, b0, thread_index, ip0, icmp0,
1012 : &required_thread_index))
1013 45 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
1014 55 : if (thread_index != required_thread_index)
1015 : {
1016 1 : vnet_buffer (b0)->snat.required_thread_index = required_thread_index;
1017 1 : next0 = NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
1018 : }
1019 : }
1020 :
1021 57 : out:
1022 63 : return next0;
1023 : }
1024 :
1025 : static_always_inline u32
1026 63 : nat44_ei_icmp_in2out_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
1027 : ip4_header_t *ip0, icmp46_header_t *icmp0,
1028 : u32 sw_if_index0, u32 rx_fib_index0,
1029 : vlib_node_runtime_t *node, u32 next0, f64 now,
1030 : u32 thread_index, nat44_ei_session_t **p_s0)
1031 : {
1032 63 : vlib_main_t *vm = vlib_get_main ();
1033 :
1034 63 : next0 = nat44_ei_icmp_in2out (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1035 : node, next0, thread_index, p_s0);
1036 63 : nat44_ei_session_t *s0 = *p_s0;
1037 63 : if (PREDICT_TRUE (next0 != NAT44_EI_IN2OUT_NEXT_DROP && s0))
1038 : {
1039 : /* Accounting */
1040 58 : nat44_ei_session_update_counters (
1041 : s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1042 : /* Per-user LRU list maintenance */
1043 58 : nat44_ei_session_update_lru (nm, s0, thread_index);
1044 : }
1045 63 : return next0;
1046 : }
1047 :
1048 : static_always_inline void
1049 3 : nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
1050 : ip4_header_t *ip)
1051 : {
1052 : clib_bihash_kv_8_8_t kv, value;
1053 : nat44_ei_static_mapping_t *m;
1054 : u32 old_addr, new_addr;
1055 : ip_csum_t sum;
1056 :
1057 3 : init_nat_k (&kv, ip->dst_address, 0, 0, 0);
1058 3 : if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
1059 1 : return;
1060 :
1061 2 : m = pool_elt_at_index (nm->static_mappings, value.value);
1062 :
1063 2 : old_addr = ip->dst_address.as_u32;
1064 2 : new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
1065 2 : sum = ip->checksum;
1066 2 : sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
1067 2 : ip->checksum = ip_csum_fold (sum);
1068 :
1069 2 : if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
1070 0 : vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
1071 : }
1072 :
1073 : static int
1074 3 : nat_in2out_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
1075 : ip4_header_t *ip, u32 rx_fib_index)
1076 : {
1077 : clib_bihash_kv_8_8_t kv, value;
1078 : nat44_ei_static_mapping_t *m;
1079 : u32 old_addr, new_addr;
1080 : ip_csum_t sum;
1081 :
1082 3 : init_nat_k (&kv, ip->src_address, 0, rx_fib_index, 0);
1083 3 : if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
1084 0 : return 1;
1085 :
1086 3 : m = pool_elt_at_index (nm->static_mappings, value.value);
1087 :
1088 3 : old_addr = ip->src_address.as_u32;
1089 3 : new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
1090 3 : sum = ip->checksum;
1091 3 : sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1092 3 : ip->checksum = ip_csum_fold (sum);
1093 :
1094 :
1095 : /* Hairpinning */
1096 3 : if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
1097 : {
1098 3 : vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
1099 3 : nat44_ei_hairpinning_sm_unknown_proto (nm, b, ip);
1100 : }
1101 :
1102 3 : return 0;
1103 : }
1104 :
1105 : static_always_inline int
1106 33 : nat44_ei_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node,
1107 : nat44_ei_main_t *nm, u32 thread_index, vlib_buffer_t *b0,
1108 : ip4_header_t *ip0, udp_header_t *udp0,
1109 : tcp_header_t *tcp0, u32 proto0, int do_trace,
1110 : u32 *required_thread_index)
1111 : {
1112 33 : nat44_ei_session_t *s0 = NULL;
1113 : clib_bihash_kv_8_8_t kv0, value0;
1114 : ip_csum_t sum0;
1115 33 : u32 new_dst_addr0 = 0, old_dst_addr0, si = ~0;
1116 33 : u16 new_dst_port0 = ~0, old_dst_port0;
1117 : int rv;
1118 : ip4_address_t sm0_addr;
1119 : u16 sm0_port;
1120 : u32 sm0_fib_index;
1121 33 : u32 old_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1122 :
1123 : /* Check if destination is static mappings */
1124 33 : if (!nat44_ei_static_mapping_match (
1125 33 : ip0->dst_address, udp0->dst_port, nm->outside_fib_index, proto0,
1126 : &sm0_addr, &sm0_port, &sm0_fib_index, 1 /* by external */, 0, 0))
1127 : {
1128 23 : new_dst_addr0 = sm0_addr.as_u32;
1129 23 : new_dst_port0 = sm0_port;
1130 23 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0_fib_index;
1131 : }
1132 : /* or active session */
1133 : else
1134 : {
1135 10 : init_nat_k (&kv0, ip0->dst_address, udp0->dst_port,
1136 : nm->outside_fib_index, proto0);
1137 10 : rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0);
1138 10 : if (rv)
1139 : {
1140 0 : rv = 0;
1141 0 : goto trace;
1142 : }
1143 :
1144 10 : if (thread_index != nat_value_get_thread_index (&value0))
1145 : {
1146 3 : *required_thread_index = nat_value_get_thread_index (&value0);
1147 3 : return 0;
1148 : }
1149 :
1150 7 : si = nat_value_get_session_index (&value0);
1151 7 : s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions, si);
1152 7 : new_dst_addr0 = s0->in2out.addr.as_u32;
1153 7 : new_dst_port0 = s0->in2out.port;
1154 7 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1155 : }
1156 :
1157 : /* Check if anything has changed and if not, then return 0. This
1158 : helps avoid infinite loop, repeating the three nodes
1159 : nat44-hairpinning-->ip4-lookup-->ip4-local, in case nothing has
1160 : changed. */
1161 30 : old_dst_addr0 = ip0->dst_address.as_u32;
1162 30 : old_dst_port0 = tcp0->dst;
1163 30 : if (new_dst_addr0 == old_dst_addr0 && new_dst_port0 == old_dst_port0 &&
1164 1 : vnet_buffer (b0)->sw_if_index[VLIB_TX] == old_sw_if_index)
1165 1 : return 0;
1166 :
1167 : /* Destination is behind the same NAT, use internal address and port */
1168 29 : if (new_dst_addr0)
1169 : {
1170 29 : old_dst_addr0 = ip0->dst_address.as_u32;
1171 29 : ip0->dst_address.as_u32 = new_dst_addr0;
1172 29 : sum0 = ip0->checksum;
1173 29 : sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t,
1174 : dst_address);
1175 29 : ip0->checksum = ip_csum_fold (sum0);
1176 :
1177 29 : old_dst_port0 = tcp0->dst;
1178 29 : if (PREDICT_TRUE (new_dst_port0 != old_dst_port0))
1179 : {
1180 12 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1181 : {
1182 9 : tcp0->dst = new_dst_port0;
1183 9 : sum0 = tcp0->checksum;
1184 9 : sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
1185 : ip4_header_t, dst_address);
1186 9 : sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
1187 : ip4_header_t /* cheat */, length);
1188 9 : tcp0->checksum = ip_csum_fold (sum0);
1189 : }
1190 : else
1191 : {
1192 3 : udp0->dst_port = new_dst_port0;
1193 3 : udp0->checksum = 0;
1194 : }
1195 : }
1196 : else
1197 : {
1198 17 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1199 : {
1200 9 : sum0 = tcp0->checksum;
1201 9 : sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
1202 : ip4_header_t, dst_address);
1203 9 : tcp0->checksum = ip_csum_fold (sum0);
1204 : }
1205 : }
1206 29 : rv = 1;
1207 29 : goto trace;
1208 : }
1209 0 : rv = 0;
1210 29 : trace:
1211 29 : if (do_trace && PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
1212 : (b0->flags & VLIB_BUFFER_IS_TRACED)))
1213 : {
1214 29 : nat44_ei_hairpin_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
1215 29 : t->addr.as_u32 = new_dst_addr0;
1216 29 : t->port = new_dst_port0;
1217 29 : t->fib_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1218 29 : if (s0)
1219 : {
1220 7 : t->session_index = si;
1221 : }
1222 : else
1223 : {
1224 22 : t->session_index = ~0;
1225 : }
1226 : }
1227 29 : return rv;
1228 : }
1229 :
1230 : static_always_inline uword
1231 3 : nat44_ei_hairpinning_handoff_fn_inline (vlib_main_t *vm,
1232 : vlib_node_runtime_t *node,
1233 : vlib_frame_t *frame, u32 fq_index)
1234 : {
1235 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1236 : u32 n_enq, n_left_from, *from;
1237 : u16 thread_indices[VLIB_FRAME_SIZE], *ti;
1238 :
1239 3 : from = vlib_frame_vector_args (frame);
1240 3 : n_left_from = frame->n_vectors;
1241 3 : vlib_get_buffers (vm, from, bufs, n_left_from);
1242 :
1243 3 : b = bufs;
1244 3 : ti = thread_indices;
1245 :
1246 7 : while (n_left_from > 0)
1247 : {
1248 4 : ti[0] = vnet_buffer (b[0])->snat.required_thread_index;
1249 :
1250 4 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
1251 : (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
1252 : {
1253 : nat44_ei_hairpinning_handoff_trace_t *t =
1254 4 : vlib_add_trace (vm, node, b[0], sizeof (*t));
1255 4 : t->next_worker_index = ti[0];
1256 : }
1257 :
1258 4 : n_left_from -= 1;
1259 4 : ti += 1;
1260 4 : b += 1;
1261 : }
1262 3 : n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from,
1263 3 : thread_indices, frame->n_vectors, 1);
1264 :
1265 3 : if (n_enq < frame->n_vectors)
1266 0 : vlib_node_increment_counter (
1267 : vm, node->node_index, NAT44_EI_HAIRPINNING_HANDOFF_ERROR_CONGESTION_DROP,
1268 0 : frame->n_vectors - n_enq);
1269 3 : return frame->n_vectors;
1270 : }
1271 :
1272 : static_always_inline uword
1273 241 : nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1274 : vlib_frame_t *frame, int is_slow_path,
1275 : int is_output_feature)
1276 : {
1277 : u32 n_left_from, *from;
1278 241 : nat44_ei_main_t *nm = &nat44_ei_main;
1279 241 : f64 now = vlib_time_now (vm);
1280 241 : u32 thread_index = vm->thread_index;
1281 :
1282 241 : from = vlib_frame_vector_args (frame);
1283 241 : n_left_from = frame->n_vectors;
1284 :
1285 241 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1286 241 : u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1287 241 : vlib_get_buffers (vm, from, b, n_left_from);
1288 :
1289 10769 : while (n_left_from >= 2)
1290 : {
1291 : vlib_buffer_t *b0, *b1;
1292 : u32 next0, next1;
1293 : u32 rx_sw_if_index0, rx_sw_if_index1;
1294 : u32 tx_sw_if_index0, tx_sw_if_index1;
1295 : u32 cntr_sw_if_index0, cntr_sw_if_index1;
1296 : ip4_header_t *ip0, *ip1;
1297 : ip_csum_t sum0, sum1;
1298 : u32 new_addr0, old_addr0, new_addr1, old_addr1;
1299 : u16 old_port0, new_port0, old_port1, new_port1;
1300 : udp_header_t *udp0, *udp1;
1301 : tcp_header_t *tcp0, *tcp1;
1302 : icmp46_header_t *icmp0, *icmp1;
1303 : u32 rx_fib_index0, rx_fib_index1;
1304 : u32 proto0, proto1;
1305 10528 : nat44_ei_session_t *s0 = 0, *s1 = 0;
1306 : clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
1307 10528 : u32 iph_offset0 = 0, iph_offset1 = 0;
1308 :
1309 10528 : b0 = *b;
1310 10528 : b++;
1311 10528 : b1 = *b;
1312 10528 : b++;
1313 :
1314 : /* Prefetch next iteration. */
1315 10528 : if (PREDICT_TRUE (n_left_from >= 4))
1316 : {
1317 : vlib_buffer_t *p2, *p3;
1318 :
1319 10334 : p2 = *b;
1320 10334 : p3 = *(b + 1);
1321 :
1322 10334 : vlib_prefetch_buffer_header (p2, LOAD);
1323 10334 : vlib_prefetch_buffer_header (p3, LOAD);
1324 :
1325 10334 : clib_prefetch_load (p2->data);
1326 10334 : clib_prefetch_load (p3->data);
1327 : }
1328 :
1329 10528 : if (is_output_feature)
1330 12 : iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1331 :
1332 10528 : ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1333 : iph_offset0);
1334 :
1335 10528 : udp0 = ip4_next_header (ip0);
1336 10528 : tcp0 = (tcp_header_t *) udp0;
1337 10528 : icmp0 = (icmp46_header_t *) udp0;
1338 :
1339 10528 : rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1340 10528 : tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1341 10528 : cntr_sw_if_index0 =
1342 10528 : is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
1343 10528 : rx_fib_index0 =
1344 10528 : vec_elt (nm->ip4_main->fib_index_by_sw_if_index, rx_sw_if_index0);
1345 :
1346 10528 : next0 = next1 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
1347 :
1348 10528 : if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1))
1349 : {
1350 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1351 2 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1352 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
1353 : 0);
1354 2 : next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
1355 2 : goto trace00;
1356 : }
1357 :
1358 10526 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
1359 :
1360 : /* Next configured feature, probably ip4-lookup */
1361 10526 : if (is_slow_path)
1362 : {
1363 5256 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1364 : {
1365 0 : if (nat_in2out_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1366 : {
1367 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
1368 0 : b0->error =
1369 0 : node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1370 : }
1371 0 : vlib_increment_simple_counter (
1372 : is_slow_path ? &nm->counters.slowpath.in2out.other :
1373 : &nm->counters.fastpath.in2out.other,
1374 : thread_index, cntr_sw_if_index0, 1);
1375 0 : goto trace00;
1376 : }
1377 :
1378 5256 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1379 : {
1380 6 : next0 = nat44_ei_icmp_in2out_slow_path (
1381 : nm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node,
1382 : next0, now, thread_index, &s0);
1383 6 : vlib_increment_simple_counter (
1384 : is_slow_path ? &nm->counters.slowpath.in2out.icmp :
1385 : &nm->counters.fastpath.in2out.icmp,
1386 : thread_index, cntr_sw_if_index0, 1);
1387 6 : goto trace00;
1388 : }
1389 : }
1390 : else
1391 : {
1392 5270 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1393 : {
1394 0 : next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1395 0 : goto trace00;
1396 : }
1397 :
1398 5270 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1399 : {
1400 6 : next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1401 6 : goto trace00;
1402 : }
1403 : }
1404 :
1405 10514 : init_nat_k (&kv0, ip0->src_address,
1406 10514 : vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
1407 : proto0);
1408 10514 : if (PREDICT_FALSE (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0) !=
1409 : 0))
1410 : {
1411 10500 : if (is_slow_path)
1412 : {
1413 5250 : if (is_output_feature)
1414 : {
1415 6 : if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
1416 : nm, ip0, proto0,
1417 : vnet_buffer (b0)->ip.reass.l4_src_port,
1418 : vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1419 : rx_sw_if_index0)))
1420 0 : goto trace00;
1421 :
1422 : /*
1423 : * Send DHCP packets to the ipv4 stack, or we won't
1424 : * be able to use dhcp client on the outside interface
1425 : */
1426 6 : if (PREDICT_FALSE
1427 : (proto0 == NAT_PROTOCOL_UDP
1428 : && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1429 : clib_host_to_net_u16
1430 : (UDP_DST_PORT_dhcp_to_server))
1431 : && ip0->dst_address.as_u32 == 0xffffffff))
1432 0 : goto trace00;
1433 : }
1434 : else
1435 : {
1436 5244 : if (PREDICT_FALSE (nat44_ei_not_translate (
1437 : nm, node, rx_sw_if_index0, ip0, proto0, rx_fib_index0,
1438 : thread_index)))
1439 8 : goto trace00;
1440 : }
1441 :
1442 5242 : next0 = slow_path (nm, b0, ip0, ip0->src_address,
1443 5242 : vnet_buffer (b0)->ip.reass.l4_src_port,
1444 : rx_fib_index0, proto0, &s0, node, next0,
1445 : thread_index, now);
1446 5242 : if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
1447 2 : goto trace00;
1448 :
1449 5240 : if (PREDICT_FALSE (!s0))
1450 0 : goto trace00;
1451 : }
1452 : else
1453 : {
1454 5250 : next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1455 5250 : goto trace00;
1456 : }
1457 : }
1458 : else
1459 14 : s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1460 : nat_value_get_session_index (&value0));
1461 :
1462 5254 : b0->flags |= VNET_BUFFER_F_IS_NATED;
1463 :
1464 5254 : old_addr0 = ip0->src_address.as_u32;
1465 5254 : ip0->src_address = s0->out2in.addr;
1466 5254 : new_addr0 = ip0->src_address.as_u32;
1467 5254 : if (!is_output_feature)
1468 5248 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1469 :
1470 5254 : sum0 = ip0->checksum;
1471 5254 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1472 : ip4_header_t, src_address /* changed member */ );
1473 5254 : ip0->checksum = ip_csum_fold (sum0);
1474 :
1475 :
1476 5254 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1477 : {
1478 5167 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1479 : {
1480 5165 : old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1481 5165 : new_port0 = udp0->src_port = s0->out2in.port;
1482 5165 : sum0 = tcp0->checksum;
1483 5165 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1484 : ip4_header_t,
1485 : dst_address /* changed member */ );
1486 5165 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
1487 : ip4_header_t /* cheat */ ,
1488 : length /* changed member */ );
1489 5165 : mss_clamping (nm->mss_clamping, tcp0, &sum0);
1490 5165 : tcp0->checksum = ip_csum_fold (sum0);
1491 : }
1492 5167 : vlib_increment_simple_counter (is_slow_path ?
1493 : &nm->counters.slowpath.in2out.tcp :
1494 : &nm->counters.fastpath.in2out.tcp,
1495 : thread_index, cntr_sw_if_index0, 1);
1496 : }
1497 : else
1498 : {
1499 87 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1500 : {
1501 85 : udp0->src_port = s0->out2in.port;
1502 85 : if (PREDICT_FALSE (udp0->checksum))
1503 : {
1504 85 : old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1505 85 : new_port0 = udp0->src_port;
1506 85 : sum0 = udp0->checksum;
1507 85 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1508 : );
1509 85 : sum0 =
1510 85 : ip_csum_update (sum0, old_port0, new_port0,
1511 : ip4_header_t /* cheat */ ,
1512 : length /* changed member */ );
1513 85 : udp0->checksum = ip_csum_fold (sum0);
1514 : }
1515 : }
1516 87 : vlib_increment_simple_counter (is_slow_path ?
1517 : &nm->counters.slowpath.in2out.udp :
1518 : &nm->counters.fastpath.in2out.udp,
1519 : thread_index, cntr_sw_if_index0, 1);
1520 : }
1521 :
1522 : /* Accounting */
1523 5254 : nat44_ei_session_update_counters (
1524 : s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1525 : /* Per-user LRU list maintenance */
1526 5254 : nat44_ei_session_update_lru (nm, s0, thread_index);
1527 10528 : trace00:
1528 :
1529 10528 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1530 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1531 : {
1532 : nat44_ei_in2out_trace_t *t =
1533 1288 : vlib_add_trace (vm, node, b0, sizeof (*t));
1534 1288 : t->is_slow_path = is_slow_path;
1535 1288 : t->sw_if_index = rx_sw_if_index0;
1536 1288 : t->next_index = next0;
1537 1288 : t->session_index = ~0;
1538 1288 : if (s0)
1539 640 : t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
1540 : }
1541 :
1542 10528 : if (next0 == NAT44_EI_IN2OUT_NEXT_DROP)
1543 : {
1544 2 : vlib_increment_simple_counter (
1545 : is_slow_path ? &nm->counters.slowpath.in2out.drops :
1546 : &nm->counters.fastpath.in2out.drops,
1547 : thread_index, cntr_sw_if_index0, 1);
1548 : }
1549 :
1550 10528 : if (is_output_feature)
1551 12 : iph_offset1 = vnet_buffer (b1)->ip.reass.save_rewrite_length;
1552 :
1553 10528 : ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1554 : iph_offset1);
1555 :
1556 10528 : udp1 = ip4_next_header (ip1);
1557 10528 : tcp1 = (tcp_header_t *) udp1;
1558 10528 : icmp1 = (icmp46_header_t *) udp1;
1559 :
1560 10528 : rx_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1561 10528 : tx_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
1562 10528 : cntr_sw_if_index1 =
1563 10528 : is_output_feature ? tx_sw_if_index1 : rx_sw_if_index1;
1564 10528 : rx_fib_index1 =
1565 10528 : vec_elt (nm->ip4_main->fib_index_by_sw_if_index, rx_sw_if_index1);
1566 :
1567 10528 : if (PREDICT_FALSE (!is_output_feature && ip1->ttl == 1))
1568 : {
1569 2 : vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1570 2 : icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1571 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
1572 : 0);
1573 2 : next1 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
1574 2 : goto trace01;
1575 : }
1576 :
1577 10526 : proto1 = ip_proto_to_nat_proto (ip1->protocol);
1578 :
1579 : /* Next configured feature, probably ip4-lookup */
1580 10526 : if (is_slow_path)
1581 : {
1582 5256 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
1583 : {
1584 0 : if (nat_in2out_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
1585 : {
1586 0 : next1 = NAT44_EI_IN2OUT_NEXT_DROP;
1587 0 : b1->error =
1588 0 : node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1589 : }
1590 0 : vlib_increment_simple_counter (
1591 : is_slow_path ? &nm->counters.slowpath.in2out.other :
1592 : &nm->counters.fastpath.in2out.other,
1593 : thread_index, cntr_sw_if_index1, 1);
1594 0 : goto trace01;
1595 : }
1596 :
1597 5256 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
1598 : {
1599 39 : next1 = nat44_ei_icmp_in2out_slow_path (
1600 : nm, b1, ip1, icmp1, rx_sw_if_index1, rx_fib_index1, node,
1601 : next1, now, thread_index, &s1);
1602 39 : vlib_increment_simple_counter (
1603 : is_slow_path ? &nm->counters.slowpath.in2out.icmp :
1604 : &nm->counters.fastpath.in2out.icmp,
1605 : thread_index, cntr_sw_if_index1, 1);
1606 39 : goto trace01;
1607 : }
1608 : }
1609 : else
1610 : {
1611 5270 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
1612 : {
1613 0 : next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1614 0 : goto trace01;
1615 : }
1616 :
1617 5270 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
1618 : {
1619 44 : next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1620 44 : goto trace01;
1621 : }
1622 : }
1623 :
1624 10443 : init_nat_k (&kv1, ip1->src_address,
1625 10443 : vnet_buffer (b1)->ip.reass.l4_src_port, rx_fib_index1,
1626 : proto1);
1627 10443 : if (PREDICT_FALSE (clib_bihash_search_8_8 (&nm->in2out, &kv1, &value1) !=
1628 : 0))
1629 : {
1630 10400 : if (is_slow_path)
1631 : {
1632 5183 : if (is_output_feature)
1633 : {
1634 0 : if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
1635 : nm, ip1, proto1,
1636 : vnet_buffer (b1)->ip.reass.l4_src_port,
1637 : vnet_buffer (b1)->ip.reass.l4_dst_port, thread_index,
1638 : rx_sw_if_index1)))
1639 0 : goto trace01;
1640 :
1641 : /*
1642 : * Send DHCP packets to the ipv4 stack, or we won't
1643 : * be able to use dhcp client on the outside interface
1644 : */
1645 0 : if (PREDICT_FALSE
1646 : (proto1 == NAT_PROTOCOL_UDP
1647 : && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
1648 : clib_host_to_net_u16
1649 : (UDP_DST_PORT_dhcp_to_server))
1650 : && ip1->dst_address.as_u32 == 0xffffffff))
1651 0 : goto trace01;
1652 : }
1653 : else
1654 : {
1655 5183 : if (PREDICT_FALSE (nat44_ei_not_translate (
1656 : nm, node, rx_sw_if_index1, ip1, proto1, rx_fib_index1,
1657 : thread_index)))
1658 4 : goto trace01;
1659 : }
1660 :
1661 5179 : next1 = slow_path (nm, b1, ip1, ip1->src_address,
1662 5179 : vnet_buffer (b1)->ip.reass.l4_src_port,
1663 : rx_fib_index1, proto1, &s1, node, next1,
1664 : thread_index, now);
1665 5179 : if (PREDICT_FALSE (next1 == NAT44_EI_IN2OUT_NEXT_DROP))
1666 2 : goto trace01;
1667 :
1668 5177 : if (PREDICT_FALSE (!s1))
1669 0 : goto trace01;
1670 : }
1671 : else
1672 : {
1673 5217 : next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1674 5217 : goto trace01;
1675 : }
1676 : }
1677 : else
1678 43 : s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1679 : nat_value_get_session_index (&value1));
1680 :
1681 5220 : b1->flags |= VNET_BUFFER_F_IS_NATED;
1682 :
1683 5220 : old_addr1 = ip1->src_address.as_u32;
1684 5220 : ip1->src_address = s1->out2in.addr;
1685 5220 : new_addr1 = ip1->src_address.as_u32;
1686 5220 : if (!is_output_feature)
1687 5217 : vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1688 :
1689 5220 : sum1 = ip1->checksum;
1690 5220 : sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1691 : ip4_header_t, src_address /* changed member */ );
1692 5220 : ip1->checksum = ip_csum_fold (sum1);
1693 :
1694 5220 : if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1695 : {
1696 5158 : if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1697 : {
1698 5154 : old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
1699 5154 : new_port1 = udp1->src_port = s1->out2in.port;
1700 5154 : sum1 = tcp1->checksum;
1701 5154 : sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1702 : ip4_header_t,
1703 : dst_address /* changed member */ );
1704 5154 : sum1 = ip_csum_update (sum1, old_port1, new_port1,
1705 : ip4_header_t /* cheat */ ,
1706 : length /* changed member */ );
1707 5154 : mss_clamping (nm->mss_clamping, tcp1, &sum1);
1708 5154 : tcp1->checksum = ip_csum_fold (sum1);
1709 : }
1710 5158 : vlib_increment_simple_counter (is_slow_path ?
1711 : &nm->counters.slowpath.in2out.tcp :
1712 : &nm->counters.fastpath.in2out.tcp,
1713 : thread_index, cntr_sw_if_index1, 1);
1714 : }
1715 : else
1716 : {
1717 62 : if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1718 : {
1719 58 : udp1->src_port = s1->out2in.port;
1720 58 : if (PREDICT_FALSE (udp1->checksum))
1721 : {
1722 58 : old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
1723 58 : new_port1 = udp1->src_port;
1724 58 : sum1 = udp1->checksum;
1725 58 : sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t, dst_address /* changed member */
1726 : );
1727 58 : sum1 =
1728 58 : ip_csum_update (sum1, old_port1, new_port1,
1729 : ip4_header_t /* cheat */ ,
1730 : length /* changed member */ );
1731 58 : udp1->checksum = ip_csum_fold (sum1);
1732 : }
1733 : }
1734 62 : vlib_increment_simple_counter (is_slow_path ?
1735 : &nm->counters.slowpath.in2out.udp :
1736 : &nm->counters.fastpath.in2out.udp,
1737 : thread_index, cntr_sw_if_index1, 1);
1738 : }
1739 :
1740 : /* Accounting */
1741 5220 : nat44_ei_session_update_counters (
1742 : s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
1743 : /* Per-user LRU list maintenance */
1744 5220 : nat44_ei_session_update_lru (nm, s1, thread_index);
1745 10528 : trace01:
1746 :
1747 10528 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1748 : && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1749 : {
1750 : nat44_ei_in2out_trace_t *t =
1751 1288 : vlib_add_trace (vm, node, b1, sizeof (*t));
1752 1288 : t->sw_if_index = rx_sw_if_index1;
1753 1288 : t->next_index = next1;
1754 1288 : t->session_index = ~0;
1755 1288 : if (s1)
1756 634 : t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
1757 : }
1758 :
1759 10528 : if (next1 == NAT44_EI_IN2OUT_NEXT_DROP)
1760 : {
1761 3 : vlib_increment_simple_counter (
1762 : is_slow_path ? &nm->counters.slowpath.in2out.drops :
1763 : &nm->counters.fastpath.in2out.drops,
1764 : thread_index, cntr_sw_if_index1, 1);
1765 : }
1766 :
1767 10528 : n_left_from -= 2;
1768 10528 : next[0] = next0;
1769 10528 : next[1] = next1;
1770 10528 : next += 2;
1771 : }
1772 :
1773 326 : while (n_left_from > 0)
1774 : {
1775 : vlib_buffer_t *b0;
1776 : u32 next0;
1777 : u32 rx_sw_if_index0;
1778 : u32 tx_sw_if_index0;
1779 : u32 cntr_sw_if_index0;
1780 : ip4_header_t *ip0;
1781 : ip_csum_t sum0;
1782 : u32 new_addr0, old_addr0;
1783 : u16 old_port0, new_port0;
1784 : udp_header_t *udp0;
1785 : tcp_header_t *tcp0;
1786 : icmp46_header_t *icmp0;
1787 : u32 rx_fib_index0;
1788 : u32 proto0;
1789 85 : nat44_ei_session_t *s0 = 0;
1790 : clib_bihash_kv_8_8_t kv0, value0;
1791 85 : u32 iph_offset0 = 0;
1792 :
1793 85 : b0 = *b;
1794 85 : b++;
1795 85 : next0 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
1796 :
1797 85 : if (is_output_feature)
1798 3 : iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1799 :
1800 85 : ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1801 : iph_offset0);
1802 :
1803 85 : udp0 = ip4_next_header (ip0);
1804 85 : tcp0 = (tcp_header_t *) udp0;
1805 85 : icmp0 = (icmp46_header_t *) udp0;
1806 :
1807 85 : rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1808 85 : tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1809 85 : cntr_sw_if_index0 =
1810 85 : is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
1811 85 : rx_fib_index0 =
1812 85 : vec_elt (nm->ip4_main->fib_index_by_sw_if_index, rx_sw_if_index0);
1813 :
1814 85 : if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1))
1815 : {
1816 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1817 0 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1818 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
1819 : 0);
1820 0 : next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
1821 0 : goto trace0;
1822 : }
1823 :
1824 85 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
1825 :
1826 : /* Next configured feature, probably ip4-lookup */
1827 85 : if (is_slow_path)
1828 : {
1829 42 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1830 : {
1831 3 : if (nat_in2out_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1832 : {
1833 0 : next0 = NAT44_EI_IN2OUT_NEXT_DROP;
1834 0 : b0->error =
1835 0 : node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1836 : }
1837 3 : vlib_increment_simple_counter (
1838 : is_slow_path ? &nm->counters.slowpath.in2out.other :
1839 : &nm->counters.fastpath.in2out.other,
1840 : thread_index, cntr_sw_if_index0, 1);
1841 3 : goto trace0;
1842 : }
1843 :
1844 39 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1845 : {
1846 18 : next0 = nat44_ei_icmp_in2out_slow_path (
1847 : nm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node,
1848 : next0, now, thread_index, &s0);
1849 18 : vlib_increment_simple_counter (
1850 : is_slow_path ? &nm->counters.slowpath.in2out.icmp :
1851 : &nm->counters.fastpath.in2out.icmp,
1852 : thread_index, cntr_sw_if_index0, 1);
1853 18 : goto trace0;
1854 : }
1855 : }
1856 : else
1857 : {
1858 43 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1859 : {
1860 3 : next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1861 3 : goto trace0;
1862 : }
1863 :
1864 40 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1865 : {
1866 13 : next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1867 13 : goto trace0;
1868 : }
1869 : }
1870 :
1871 48 : init_nat_k (&kv0, ip0->src_address,
1872 48 : vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
1873 : proto0);
1874 :
1875 48 : if (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
1876 : {
1877 36 : if (is_slow_path)
1878 : {
1879 15 : if (is_output_feature)
1880 : {
1881 1 : if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
1882 : nm, ip0, proto0,
1883 : vnet_buffer (b0)->ip.reass.l4_src_port,
1884 : vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1885 : rx_sw_if_index0)))
1886 0 : goto trace0;
1887 :
1888 : /*
1889 : * Send DHCP packets to the ipv4 stack, or we won't
1890 : * be able to use dhcp client on the outside interface
1891 : */
1892 1 : if (PREDICT_FALSE
1893 : (proto0 == NAT_PROTOCOL_UDP
1894 : && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1895 : clib_host_to_net_u16
1896 : (UDP_DST_PORT_dhcp_to_server))
1897 : && ip0->dst_address.as_u32 == 0xffffffff))
1898 0 : goto trace0;
1899 : }
1900 : else
1901 : {
1902 14 : if (PREDICT_FALSE (nat44_ei_not_translate (
1903 : nm, node, rx_sw_if_index0, ip0, proto0, rx_fib_index0,
1904 : thread_index)))
1905 0 : goto trace0;
1906 : }
1907 :
1908 15 : next0 = slow_path (nm, b0, ip0, ip0->src_address,
1909 15 : vnet_buffer (b0)->ip.reass.l4_src_port,
1910 : rx_fib_index0, proto0, &s0, node, next0,
1911 : thread_index, now);
1912 :
1913 15 : if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
1914 3 : goto trace0;
1915 :
1916 12 : if (PREDICT_FALSE (!s0))
1917 0 : goto trace0;
1918 : }
1919 : else
1920 : {
1921 21 : next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1922 21 : goto trace0;
1923 : }
1924 : }
1925 : else
1926 12 : s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1927 : nat_value_get_session_index (&value0));
1928 :
1929 24 : b0->flags |= VNET_BUFFER_F_IS_NATED;
1930 :
1931 24 : old_addr0 = ip0->src_address.as_u32;
1932 24 : ip0->src_address = s0->out2in.addr;
1933 24 : new_addr0 = ip0->src_address.as_u32;
1934 24 : if (!is_output_feature)
1935 22 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1936 :
1937 24 : sum0 = ip0->checksum;
1938 24 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1939 : ip4_header_t, src_address /* changed member */ );
1940 24 : ip0->checksum = ip_csum_fold (sum0);
1941 :
1942 24 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1943 : {
1944 20 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1945 : {
1946 18 : old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1947 18 : new_port0 = udp0->src_port = s0->out2in.port;
1948 18 : sum0 = tcp0->checksum;
1949 18 : sum0 =
1950 18 : ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1951 : dst_address /* changed member */ );
1952 18 : sum0 =
1953 18 : ip_csum_update (sum0, old_port0, new_port0,
1954 : ip4_header_t /* cheat */ ,
1955 : length /* changed member */ );
1956 18 : mss_clamping (nm->mss_clamping, tcp0, &sum0);
1957 18 : tcp0->checksum = ip_csum_fold (sum0);
1958 : }
1959 20 : vlib_increment_simple_counter (is_slow_path ?
1960 : &nm->counters.slowpath.in2out.tcp :
1961 : &nm->counters.fastpath.in2out.tcp,
1962 : thread_index, cntr_sw_if_index0, 1);
1963 : }
1964 : else
1965 : {
1966 4 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1967 : {
1968 2 : udp0->src_port = s0->out2in.port;
1969 2 : if (PREDICT_FALSE (udp0->checksum))
1970 : {
1971 2 : old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1972 2 : new_port0 = udp0->src_port;
1973 2 : sum0 = udp0->checksum;
1974 2 : sum0 =
1975 2 : ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1976 : dst_address /* changed member */ );
1977 2 : sum0 =
1978 2 : ip_csum_update (sum0, old_port0, new_port0,
1979 : ip4_header_t /* cheat */ ,
1980 : length /* changed member */ );
1981 2 : udp0->checksum = ip_csum_fold (sum0);
1982 : }
1983 : }
1984 4 : vlib_increment_simple_counter (is_slow_path ?
1985 : &nm->counters.slowpath.in2out.udp :
1986 : &nm->counters.fastpath.in2out.udp,
1987 : thread_index, cntr_sw_if_index0, 1);
1988 : }
1989 :
1990 : /* Accounting */
1991 24 : nat44_ei_session_update_counters (
1992 : s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1993 : /* Per-user LRU list maintenance */
1994 24 : nat44_ei_session_update_lru (nm, s0, thread_index);
1995 :
1996 85 : trace0:
1997 85 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1998 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1999 : {
2000 : nat44_ei_in2out_trace_t *t =
2001 85 : vlib_add_trace (vm, node, b0, sizeof (*t));
2002 85 : t->is_slow_path = is_slow_path;
2003 85 : t->sw_if_index = rx_sw_if_index0;
2004 85 : t->next_index = next0;
2005 85 : t->session_index = ~0;
2006 85 : if (s0)
2007 42 : t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
2008 : }
2009 :
2010 85 : if (next0 == NAT44_EI_IN2OUT_NEXT_DROP)
2011 : {
2012 3 : vlib_increment_simple_counter (
2013 : is_slow_path ? &nm->counters.slowpath.in2out.drops :
2014 : &nm->counters.fastpath.in2out.drops,
2015 : thread_index, cntr_sw_if_index0, 1);
2016 : }
2017 :
2018 85 : n_left_from--;
2019 85 : next[0] = next0;
2020 85 : next++;
2021 : }
2022 :
2023 241 : vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
2024 241 : frame->n_vectors);
2025 241 : return frame->n_vectors;
2026 : }
2027 :
2028 : static_always_inline uword
2029 1 : nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm,
2030 : vlib_node_runtime_t *node,
2031 : vlib_frame_t *frame)
2032 : {
2033 : u32 n_left_from, *from, *to_next;
2034 1 : u32 thread_index = vm->thread_index;
2035 : nat44_ei_in2out_next_t next_index;
2036 1 : nat44_ei_main_t *nm = &nat44_ei_main;
2037 1 : int is_hairpinning = 0;
2038 :
2039 1 : from = vlib_frame_vector_args (frame);
2040 1 : n_left_from = frame->n_vectors;
2041 1 : next_index = node->cached_next_index;
2042 :
2043 2 : while (n_left_from > 0)
2044 : {
2045 : u32 n_left_to_next;
2046 :
2047 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2048 :
2049 2 : while (n_left_from > 0 && n_left_to_next > 0)
2050 : {
2051 : u32 bi0;
2052 : vlib_buffer_t *b0;
2053 : u32 next0;
2054 : u32 sw_if_index0;
2055 : ip4_header_t *ip0;
2056 : udp_header_t *udp0;
2057 : tcp_header_t *tcp0;
2058 : icmp46_header_t *icmp0;
2059 : u32 proto0;
2060 1 : u32 required_thread_index = thread_index;
2061 :
2062 1 : bi0 = from[0];
2063 1 : to_next[0] = bi0;
2064 1 : from += 1;
2065 1 : to_next += 1;
2066 1 : n_left_from -= 1;
2067 1 : n_left_to_next -= 1;
2068 :
2069 1 : b0 = vlib_get_buffer (vm, bi0);
2070 1 : next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP;
2071 :
2072 1 : ip0 = vlib_buffer_get_current (b0);
2073 1 : udp0 = ip4_next_header (ip0);
2074 1 : tcp0 = (tcp_header_t *) udp0;
2075 1 : icmp0 = (icmp46_header_t *) udp0;
2076 :
2077 1 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2078 1 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
2079 :
2080 1 : switch (proto0)
2081 : {
2082 0 : case NAT_PROTOCOL_TCP:
2083 : // fallthrough
2084 : case NAT_PROTOCOL_UDP:
2085 0 : is_hairpinning = nat44_ei_hairpinning (
2086 : vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0,
2087 : 0 /* do_trace */, &required_thread_index);
2088 0 : break;
2089 1 : case NAT_PROTOCOL_ICMP:
2090 1 : is_hairpinning = (0 == nat44_ei_icmp_hairpinning (
2091 : nm, b0, thread_index, ip0, icmp0,
2092 : &required_thread_index));
2093 1 : break;
2094 0 : case NAT_PROTOCOL_OTHER:
2095 : // this should never happen
2096 0 : next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
2097 0 : break;
2098 : }
2099 :
2100 1 : if (thread_index != required_thread_index)
2101 : {
2102 : // but we already did a handoff ...
2103 0 : next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
2104 : }
2105 :
2106 1 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2107 : (b0->flags & VLIB_BUFFER_IS_TRACED)))
2108 : {
2109 : nat44_ei_in2out_trace_t *t =
2110 1 : vlib_add_trace (vm, node, b0, sizeof (*t));
2111 1 : t->sw_if_index = sw_if_index0;
2112 1 : t->next_index = next0;
2113 1 : t->is_hairpinning = is_hairpinning;
2114 : }
2115 :
2116 1 : if (next0 != NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP)
2117 : {
2118 1 : vlib_increment_simple_counter (
2119 : &nm->counters.fastpath.in2out.other, sw_if_index0,
2120 : vm->thread_index, 1);
2121 : }
2122 :
2123 1 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2124 : n_left_to_next, bi0, next0);
2125 : }
2126 :
2127 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2128 : }
2129 :
2130 1 : return frame->n_vectors;
2131 : }
2132 :
2133 2256 : VLIB_NODE_FN (nat44_ei_hairpinning_node)
2134 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2135 : {
2136 : u32 n_left_from, *from, *to_next;
2137 20 : u32 thread_index = vm->thread_index;
2138 : nat44_ei_hairpin_next_t next_index;
2139 20 : nat44_ei_main_t *nm = &nat44_ei_main;
2140 20 : vnet_feature_main_t *fm = &feature_main;
2141 20 : u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
2142 20 : vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
2143 :
2144 20 : from = vlib_frame_vector_args (frame);
2145 20 : n_left_from = frame->n_vectors;
2146 20 : next_index = node->cached_next_index;
2147 :
2148 40 : while (n_left_from > 0)
2149 : {
2150 : u32 n_left_to_next;
2151 :
2152 20 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2153 :
2154 53 : while (n_left_from > 0 && n_left_to_next > 0)
2155 : {
2156 : u32 bi0;
2157 : vlib_buffer_t *b0;
2158 : u32 next0;
2159 : ip4_header_t *ip0;
2160 : u32 proto0;
2161 : udp_header_t *udp0;
2162 : tcp_header_t *tcp0;
2163 : u32 sw_if_index0;
2164 33 : u32 required_thread_index = thread_index;
2165 :
2166 33 : bi0 = from[0];
2167 33 : to_next[0] = bi0;
2168 33 : from += 1;
2169 33 : to_next += 1;
2170 33 : n_left_from -= 1;
2171 33 : n_left_to_next -= 1;
2172 :
2173 33 : b0 = vlib_get_buffer (vm, bi0);
2174 33 : ip0 = vlib_buffer_get_current (b0);
2175 33 : udp0 = ip4_next_header (ip0);
2176 33 : tcp0 = (tcp_header_t *) udp0;
2177 33 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2178 :
2179 33 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
2180 33 : int next0_resolved = 0;
2181 :
2182 33 : if (nat44_ei_hairpinning (vm, node, nm, thread_index, b0, ip0, udp0,
2183 : tcp0, proto0, 1, &required_thread_index))
2184 : {
2185 29 : next0 = NAT44_EI_HAIRPIN_NEXT_LOOKUP;
2186 29 : next0_resolved = 1;
2187 : }
2188 :
2189 33 : if (thread_index != required_thread_index)
2190 : {
2191 3 : vnet_buffer (b0)->snat.required_thread_index =
2192 : required_thread_index;
2193 3 : next0 = NAT44_EI_HAIRPIN_NEXT_HANDOFF;
2194 3 : next0_resolved = 1;
2195 : }
2196 :
2197 33 : if (!next0_resolved)
2198 1 : vnet_get_config_data (&cm->config_main, &b0->current_config_index,
2199 : &next0, 0);
2200 :
2201 33 : if (next0 != NAT44_EI_HAIRPIN_NEXT_DROP)
2202 : {
2203 33 : vlib_increment_simple_counter (
2204 : &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1);
2205 : }
2206 :
2207 33 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2208 : n_left_to_next, bi0, next0);
2209 : }
2210 :
2211 20 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2212 : }
2213 :
2214 20 : return frame->n_vectors;
2215 : }
2216 :
2217 2355 : VLIB_NODE_FN (nat44_ei_in2out_node)
2218 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2219 : {
2220 119 : return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0, 0);
2221 : }
2222 :
2223 2241 : VLIB_NODE_FN (nat44_ei_in2out_output_node)
2224 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2225 : {
2226 5 : return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0, 1);
2227 : }
2228 :
2229 2349 : VLIB_NODE_FN (nat44_ei_in2out_slowpath_node)
2230 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2231 : {
2232 113 : return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1, 0);
2233 : }
2234 :
2235 2240 : VLIB_NODE_FN (nat44_ei_in2out_output_slowpath_node)
2236 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2237 : {
2238 4 : return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1, 1);
2239 : }
2240 :
2241 2237 : VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node)
2242 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2243 : {
2244 1 : return nat44_ei_hairpinning_handoff_fn_inline (
2245 : vm, node, frame,
2246 : nat44_ei_main.in2out_hairpinning_finish_ip4_lookup_node_fq_index);
2247 : }
2248 :
2249 2236 : VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_interface_output_node)
2250 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2251 : {
2252 0 : return nat44_ei_hairpinning_handoff_fn_inline (
2253 : vm, node, frame,
2254 : nat44_ei_main.in2out_hairpinning_finish_interface_output_node_fq_index);
2255 : }
2256 :
2257 2237 : VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node)
2258 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2259 : {
2260 1 : return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame);
2261 : }
2262 :
2263 2236 : VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_interface_output_node)
2264 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2265 : {
2266 0 : return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame);
2267 : }
2268 :
2269 2238 : VLIB_NODE_FN (nat44_ei_hairpinning_handoff_node)
2270 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2271 : {
2272 2 : return nat44_ei_hairpinning_handoff_fn_inline (
2273 : vm, node, frame, nat44_ei_main.hairpinning_fq_index);
2274 : }
2275 :
2276 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_node) = {
2277 : .name = "nat44-ei-in2out",
2278 : .vector_size = sizeof (u32),
2279 : .format_trace = format_nat44_ei_in2out_trace,
2280 : .type = VLIB_NODE_TYPE_INTERNAL,
2281 : .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2282 : .error_strings = nat44_ei_in2out_error_strings,
2283 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2284 : .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
2285 : .next_nodes = {
2286 : [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
2287 : [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2288 : [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
2289 : [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2290 : [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
2291 : },
2292 : };
2293 :
2294 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_output_node) = {
2295 : .name = "nat44-ei-in2out-output",
2296 : .vector_size = sizeof (u32),
2297 : .format_trace = format_nat44_ei_in2out_trace,
2298 : .type = VLIB_NODE_TYPE_INTERNAL,
2299 : .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2300 : .error_strings = nat44_ei_in2out_error_strings,
2301 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2302 : .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
2303 : .next_nodes = {
2304 : [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
2305 : [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output",
2306 : [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath",
2307 : [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2308 : [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output",
2309 : },
2310 : };
2311 :
2312 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_slowpath_node) = {
2313 : .name = "nat44-ei-in2out-slowpath",
2314 : .vector_size = sizeof (u32),
2315 : .format_trace = format_nat44_ei_in2out_trace,
2316 : .type = VLIB_NODE_TYPE_INTERNAL,
2317 : .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2318 : .error_strings = nat44_ei_in2out_error_strings,
2319 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2320 : .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
2321 : .next_nodes = {
2322 : [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
2323 : [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2324 : [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
2325 : [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2326 : [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
2327 : },
2328 : };
2329 :
2330 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_output_slowpath_node) = {
2331 : .name = "nat44-ei-in2out-output-slowpath",
2332 : .vector_size = sizeof (u32),
2333 : .format_trace = format_nat44_ei_in2out_trace,
2334 : .type = VLIB_NODE_TYPE_INTERNAL,
2335 : .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2336 : .error_strings = nat44_ei_in2out_error_strings,
2337 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2338 : .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
2339 : .next_nodes = {
2340 : [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
2341 : [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output",
2342 : [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath",
2343 : [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2344 : [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output",
2345 : },
2346 : };
2347 :
2348 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) = {
2349 : .name = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
2350 : .vector_size = sizeof (u32),
2351 : .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
2352 : .error_strings = nat44_ei_hairpinning_handoff_error_strings,
2353 : .format_trace = format_nat44_ei_hairpinning_handoff_trace,
2354 : .n_next_nodes = 1,
2355 : .next_nodes = {
2356 : [0] = "error-drop",
2357 : },
2358 : };
2359 :
2360 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_interface_output_node) = {
2361 : .name = "nat44-ei-in2out-hairpinning-handoff-interface-output",
2362 : .vector_size = sizeof (u32),
2363 : .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
2364 : .error_strings = nat44_ei_hairpinning_handoff_error_strings,
2365 : .format_trace = format_nat44_ei_hairpinning_handoff_trace,
2366 : .n_next_nodes = 1,
2367 : .next_nodes = {
2368 : [0] = "error-drop",
2369 : },
2370 : };
2371 :
2372 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node) = {
2373 : .name = "nat44-ei-in2out-hairpinning-finish-ip4-lookup",
2374 : .vector_size = sizeof (u32),
2375 : .format_trace = format_nat44_ei_in2out_fast_trace,
2376 : .type = VLIB_NODE_TYPE_INTERNAL,
2377 : .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2378 : .error_strings = nat44_ei_in2out_error_strings,
2379 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2380 : .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
2381 : .next_nodes = {
2382 : [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
2383 : [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "ip4-lookup",
2384 : },
2385 : };
2386 :
2387 62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_interface_output_node) = {
2388 : .name = "nat44-ei-in2out-hairpinning-finish-interface-output",
2389 : .vector_size = sizeof (u32),
2390 : .format_trace = format_nat44_ei_in2out_fast_trace,
2391 : .type = VLIB_NODE_TYPE_INTERNAL,
2392 : .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2393 : .error_strings = nat44_ei_in2out_error_strings,
2394 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2395 : .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
2396 : .next_nodes = {
2397 : [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
2398 : [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "interface-output",
2399 : },
2400 : };
2401 :
2402 62744 : VLIB_REGISTER_NODE (nat44_ei_hairpinning_handoff_node) = {
2403 : .name = "nat44-ei-hairpinning-handoff",
2404 : .vector_size = sizeof (u32),
2405 : .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
2406 : .error_strings = nat44_ei_hairpinning_handoff_error_strings,
2407 : .format_trace = format_nat44_ei_hairpinning_handoff_trace,
2408 : .n_next_nodes = 1,
2409 : .next_nodes = {
2410 : [0] = "error-drop",
2411 : },
2412 : };
2413 :
2414 62744 : VLIB_REGISTER_NODE (nat44_ei_hairpinning_node) = {
2415 : .name = "nat44-ei-hairpinning",
2416 : .vector_size = sizeof (u32),
2417 : .type = VLIB_NODE_TYPE_INTERNAL,
2418 : .format_trace = format_nat44_ei_hairpin_trace,
2419 : .n_next_nodes = NAT44_EI_HAIRPIN_N_NEXT,
2420 : .next_nodes = {
2421 : [NAT44_EI_HAIRPIN_NEXT_DROP] = "error-drop",
2422 : [NAT44_EI_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup",
2423 : [NAT44_EI_HAIRPIN_NEXT_HANDOFF] = "nat44-ei-hairpinning-handoff",
2424 : },
2425 : };
2426 :
2427 : /*
2428 : * fd.io coding-style-patch-verification: ON
2429 : *
2430 : * Local Variables:
2431 : * eval: (c-set-style "gnu")
2432 : * End:
2433 : */
|