Line data Source code
1 : /*
2 : * Copyright (c) 2018 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 endpoint-dependent inside to outside network translation
18 : */
19 :
20 : #include <vlib/vlib.h>
21 : #include <vnet/vnet.h>
22 : #include <vnet/ip/ip.h>
23 : #include <vnet/ethernet/ethernet.h>
24 : #include <vnet/fib/ip4_fib.h>
25 : #include <vnet/udp/udp_local.h>
26 : #include <vppinfra/error.h>
27 :
28 : #include <nat/lib/nat_inlines.h>
29 : #include <nat/lib/ipfix_logging.h>
30 :
31 : #include <nat/nat44-ed/nat44_ed.h>
32 : #include <nat/nat44-ed/nat44_ed_inlines.h>
33 :
34 : static char *nat_in2out_ed_error_strings[] = {
35 : #define _(sym,string) string,
36 : foreach_nat_in2out_ed_error
37 : #undef _
38 : };
39 :
40 : typedef struct
41 : {
42 : u32 sw_if_index;
43 : u32 next_index;
44 : u32 session_index;
45 : nat_translation_error_e translation_error;
46 : nat_6t_flow_t i2of;
47 : nat_6t_flow_t o2if;
48 : clib_bihash_kv_16_8_t search_key;
49 : u8 is_slow_path;
50 : u8 translation_via_i2of;
51 : u8 lookup_skipped;
52 : u8 tcp_state;
53 : } nat_in2out_ed_trace_t;
54 :
55 : static u8 *
56 2756 : format_nat_in2out_ed_trace (u8 * s, va_list * args)
57 : {
58 2756 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59 2756 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60 2756 : nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
61 : char *tag;
62 :
63 2756 : tag =
64 2756 : t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
65 : "NAT44_IN2OUT_ED_FAST_PATH";
66 :
67 2756 : s = format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index,
68 : t->next_index);
69 2756 : if (~0 != t->session_index)
70 : {
71 1218 : s = format (s, ", session %d, translation result '%U' via %s",
72 : t->session_index, format_nat_ed_translation_error,
73 1218 : t->translation_error,
74 1218 : t->translation_via_i2of ? "i2of" : "o2if");
75 1218 : s = format (s, "\n i2of %U", format_nat_6t_flow, &t->i2of);
76 1218 : s = format (s, "\n o2if %U", format_nat_6t_flow, &t->o2if);
77 : }
78 2756 : if (!t->is_slow_path)
79 : {
80 1587 : if (t->lookup_skipped)
81 : {
82 89 : s = format (s, "\n lookup skipped - cached session index used");
83 : }
84 : else
85 : {
86 1498 : s = format (s, "\n search key %U", format_ed_session_kvp,
87 : &t->search_key);
88 : }
89 : }
90 2756 : if (IP_PROTOCOL_TCP == t->i2of.match.proto)
91 : {
92 110 : s = format (s, "\n TCP state: %U", format_nat44_ed_tcp_state,
93 110 : t->tcp_state);
94 : }
95 :
96 2756 : return s;
97 : }
98 :
99 : static int
100 28343 : nat_ed_alloc_addr_and_port_with_snat_address (
101 : snat_main_t *sm, u8 proto, u32 thread_index, snat_address_t *a,
102 : u16 port_per_thread, u32 snat_thread_index, snat_session_t *s,
103 : ip4_address_t *outside_addr, u16 *outside_port)
104 : {
105 28343 : const u16 port_thread_offset =
106 28343 : (port_per_thread * snat_thread_index) + ED_USER_PORT_OFFSET;
107 :
108 : /* Backup original match in case of failure */
109 28343 : const nat_6t_t match = s->o2i.match;
110 :
111 28343 : s->o2i.match.daddr = a->addr;
112 : /* first try port suggested by caller */
113 28343 : u16 port = clib_net_to_host_u16 (*outside_port);
114 28344 : u16 port_offset = port - port_thread_offset;
115 28344 : if (port < port_thread_offset ||
116 211 : port >= port_thread_offset + port_per_thread)
117 : {
118 : /* need to pick a different port, suggested port doesn't fit in
119 : * this thread's port range */
120 28171 : port_offset = snat_random_port (0, port_per_thread - 1);
121 28170 : port = port_thread_offset + port_offset;
122 : }
123 28343 : u16 attempts = ED_PORT_ALLOC_ATTEMPTS;
124 : do
125 : {
126 42731 : if (IP_PROTOCOL_ICMP == proto)
127 : {
128 7531 : s->o2i.match.sport = clib_host_to_net_u16 (port);
129 : }
130 42731 : s->o2i.match.dport = clib_host_to_net_u16 (port);
131 42730 : if (0 == nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2))
132 : {
133 28209 : *outside_addr = a->addr;
134 28209 : *outside_port = clib_host_to_net_u16 (port);
135 28209 : return 0;
136 : }
137 14523 : port_offset = snat_random_port (0, port_per_thread - 1);
138 14523 : port = port_thread_offset + port_offset;
139 14523 : --attempts;
140 : }
141 14523 : while (attempts > 0);
142 :
143 : /* Revert match */
144 135 : s->o2i.match = match;
145 135 : return 1;
146 : }
147 :
148 : static int
149 28346 : nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index,
150 : u32 tx_sw_if_index, u32 nat_proto,
151 : u32 thread_index, ip4_address_t s_addr,
152 : ip4_address_t d_addr, u32 snat_thread_index,
153 : snat_session_t *s, ip4_address_t *outside_addr,
154 : u16 *outside_port)
155 : {
156 28346 : if (vec_len (sm->addresses) > 0)
157 : {
158 28342 : u32 s_addr_offset = s_addr.as_u32 % vec_len (sm->addresses);
159 28342 : snat_address_t *a, *ja = 0, *ra = 0, *ba = 0;
160 : int i;
161 :
162 : // output feature
163 28342 : if (tx_sw_if_index != ~0)
164 : {
165 44 : for (i = s_addr_offset; i < vec_len (sm->addresses); ++i)
166 : {
167 22 : a = sm->addresses + i;
168 22 : if (a->fib_index == rx_fib_index)
169 : {
170 0 : if (a->sw_if_index == tx_sw_if_index)
171 : {
172 0 : if ((a->addr_len != ~0) &&
173 0 : (a->net.as_u32 ==
174 0 : (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
175 :
176 : {
177 0 : return nat_ed_alloc_addr_and_port_with_snat_address (
178 : sm, nat_proto, thread_index, a,
179 0 : sm->port_per_thread, snat_thread_index, s,
180 : outside_addr, outside_port);
181 : }
182 0 : ra = a;
183 : }
184 0 : ja = a;
185 : }
186 22 : else if (a->fib_index == ~0)
187 : {
188 22 : ba = a;
189 : }
190 : }
191 22 : for (i = 0; i < s_addr_offset; ++i)
192 : {
193 0 : a = sm->addresses + i;
194 0 : if (a->fib_index == rx_fib_index)
195 : {
196 0 : if (a->sw_if_index == tx_sw_if_index)
197 : {
198 0 : if ((a->addr_len != ~0) &&
199 0 : (a->net.as_u32 ==
200 0 : (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
201 :
202 : {
203 0 : return nat_ed_alloc_addr_and_port_with_snat_address (
204 : sm, nat_proto, thread_index, a,
205 0 : sm->port_per_thread, snat_thread_index, s,
206 : outside_addr, outside_port);
207 : }
208 0 : ra = a;
209 : }
210 0 : ja = a;
211 : }
212 0 : else if (a->fib_index == ~0)
213 : {
214 0 : ba = a;
215 : }
216 : }
217 22 : if (ra)
218 : {
219 0 : return nat_ed_alloc_addr_and_port_with_snat_address (
220 0 : sm, nat_proto, thread_index, ra, sm->port_per_thread,
221 : snat_thread_index, s, outside_addr, outside_port);
222 : }
223 : }
224 : else
225 : {
226 : // first try nat pool addresses to sw interface addreses mappings
227 66359 : for (i = s_addr_offset; i < vec_len (sm->addresses); ++i)
228 : {
229 38039 : a = sm->addresses + i;
230 38039 : if (a->fib_index == rx_fib_index)
231 : {
232 3 : if ((a->addr_len != ~0) &&
233 0 : (a->net.as_u32 ==
234 0 : (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
235 : {
236 0 : return nat_ed_alloc_addr_and_port_with_snat_address (
237 0 : sm, nat_proto, thread_index, a, sm->port_per_thread,
238 : snat_thread_index, s, outside_addr, outside_port);
239 : }
240 3 : ja = a;
241 : }
242 38036 : else if (a->fib_index == ~0)
243 : {
244 38036 : ba = a;
245 : }
246 : }
247 38171 : for (i = 0; i < s_addr_offset; ++i)
248 : {
249 9850 : a = sm->addresses + i;
250 9850 : if (a->fib_index == rx_fib_index)
251 : {
252 0 : if ((a->addr_len != ~0) &&
253 0 : (a->net.as_u32 ==
254 0 : (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
255 : {
256 0 : return nat_ed_alloc_addr_and_port_with_snat_address (
257 0 : sm, nat_proto, thread_index, a, sm->port_per_thread,
258 : snat_thread_index, s, outside_addr, outside_port);
259 : }
260 0 : ja = a;
261 : }
262 9850 : else if (a->fib_index == ~0)
263 : {
264 9850 : ba = a;
265 : }
266 : }
267 : }
268 :
269 28343 : if (ja || ba)
270 : {
271 28343 : a = ja ? ja : ba;
272 28344 : return nat_ed_alloc_addr_and_port_with_snat_address (
273 28343 : sm, nat_proto, thread_index, a, sm->port_per_thread,
274 : snat_thread_index, s, outside_addr, outside_port);
275 : }
276 : }
277 : /* Totally out of translations to use... */
278 4 : nat_ipfix_logging_addresses_exhausted (thread_index, 0);
279 4 : return 1;
280 : }
281 :
282 : static_always_inline int
283 28353 : nat44_ed_external_sm_lookup (snat_main_t *sm, ip4_address_t match_addr,
284 : u16 match_port, ip_protocol_t match_protocol,
285 : ip4_address_t *daddr, u16 *dport)
286 : {
287 : snat_static_mapping_t *m =
288 28353 : nat44_ed_sm_o2i_lookup (sm, match_addr, match_port, 0, match_protocol);
289 28354 : if (!m)
290 : {
291 : /* Try address only mapping */
292 28352 : m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0);
293 28352 : if (!m)
294 28344 : return 0;
295 : }
296 10 : *daddr = m->local_addr;
297 10 : if (dport)
298 : {
299 : /* Address only mapping doesn't change port */
300 9 : *dport = is_sm_addr_only (m->flags) ? match_port : m->local_port;
301 : }
302 10 : return 1;
303 : }
304 :
305 : static_always_inline vrf_table_t *
306 56689 : get_vrf_table_by_fib (u32 fib_index)
307 : {
308 56689 : snat_main_t *sm = &snat_main;
309 : vrf_table_t *t;
310 :
311 56689 : pool_foreach (t, sm->vrf_tables)
312 : {
313 0 : if (fib_index == t->table_fib_index)
314 : {
315 0 : return t;
316 : }
317 : }
318 :
319 56689 : return 0;
320 : }
321 :
322 : static_always_inline u32
323 28356 : get_tx_fib_index (u32 rx_fib_index, ip4_address_t addr)
324 : {
325 28356 : fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
326 28356 : fib_prefix_t pfx = {
327 : .fp_proto = FIB_PROTOCOL_IP4,
328 : .fp_len = 32,
329 28356 : .fp_addr = {.ip4.as_u32 = addr.as_u32,}
330 : ,
331 : };
332 :
333 28356 : snat_main_t *sm = &snat_main;
334 28356 : vrf_table_t *t = get_vrf_table_by_fib (rx_fib_index);
335 : // default to rx fib
336 28356 : u32 tx_fib_index = rx_fib_index;
337 :
338 28356 : if (0 != t)
339 : {
340 : // managed routes to other fibs
341 : vrf_route_t *r;
342 0 : pool_foreach (r, t->routes)
343 : {
344 0 : fei = fib_table_lookup (r->fib_index, &pfx);
345 0 : if ((FIB_NODE_INDEX_INVALID != fei) &&
346 0 : (~0 != fib_entry_get_resolving_interface (fei)))
347 : {
348 0 : tx_fib_index = r->fib_index;
349 0 : break;
350 : }
351 : }
352 : }
353 : else
354 : {
355 : // default to configured fib
356 28356 : tx_fib_index = sm->outside_fib_index;
357 :
358 : // default routes to other fibs
359 : nat_fib_t *f;
360 28356 : vec_foreach (f, sm->outside_fibs)
361 : {
362 28355 : fei = fib_table_lookup (f->fib_index, &pfx);
363 56707 : if ((FIB_NODE_INDEX_INVALID != fei) &&
364 28355 : (~0 != fib_entry_get_resolving_interface (fei)))
365 : {
366 28352 : tx_fib_index = f->fib_index;
367 28352 : break;
368 : }
369 : }
370 : }
371 :
372 28352 : return tx_fib_index;
373 : }
374 :
375 : static_always_inline int
376 28340 : is_destination_resolvable (u32 rx_fib_index, ip4_address_t addr)
377 : {
378 28340 : fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
379 28340 : fib_prefix_t pfx = {
380 : .fp_proto = FIB_PROTOCOL_IP4,
381 : .fp_len = 32,
382 28340 : .fp_addr = {.ip4.as_u32 = addr.as_u32,}
383 : ,
384 : };
385 :
386 28340 : snat_main_t *sm = &snat_main;
387 28340 : vrf_table_t *t = get_vrf_table_by_fib (rx_fib_index);
388 : u32 ii;
389 :
390 28340 : if (0 != t)
391 : {
392 : // managed routes to other fibs
393 : vrf_route_t *r;
394 0 : pool_foreach (r, t->routes)
395 : {
396 0 : fei = fib_table_lookup (r->fib_index, &pfx);
397 0 : if ((FIB_NODE_INDEX_INVALID != fei) &&
398 0 : (~0 != (ii = fib_entry_get_resolving_interface (fei))))
399 : {
400 0 : return 1;
401 : }
402 : }
403 : }
404 : else
405 : {
406 : // default routes to other fibs
407 : nat_fib_t *f;
408 28346 : vec_foreach (f, sm->outside_fibs)
409 : {
410 28342 : fei = fib_table_lookup (f->fib_index, &pfx);
411 56682 : if ((FIB_NODE_INDEX_INVALID != fei) &&
412 28344 : (~0 != (ii = fib_entry_get_resolving_interface (fei))))
413 : {
414 : snat_interface_t *i;
415 56695 : pool_foreach (i, sm->interfaces)
416 : {
417 56693 : if ((nat44_ed_is_interface_outside (i)) &&
418 28340 : (ii == i->sw_if_index))
419 : {
420 28336 : return 1;
421 : }
422 : }
423 : }
424 : }
425 : }
426 :
427 4 : return 0;
428 : }
429 :
430 : static u32
431 28367 : slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
432 : ip4_address_t l_addr, ip4_address_t r_addr, u16 l_port,
433 : u16 r_port, u8 proto, u32 rx_fib_index, u32 tx_sw_if_index,
434 : snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next,
435 : u32 thread_index, f64 now)
436 : {
437 28367 : snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
438 : ip4_address_t outside_addr;
439 : u16 outside_port;
440 : u32 tx_fib_index;
441 28367 : u8 is_identity_nat = 0;
442 :
443 28367 : snat_session_t *s = NULL;
444 28367 : lb_nat_type_t lb = 0;
445 28367 : ip4_address_t daddr = r_addr;
446 28367 : u16 dport = r_port;
447 :
448 28367 : if (PREDICT_FALSE
449 : (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
450 : {
451 6 : if (!nat_lru_free_one (sm, thread_index, now))
452 : {
453 5 : b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
454 5 : nat_ipfix_logging_max_sessions (thread_index,
455 : sm->max_translations_per_thread);
456 5 : nat_elog_notice (sm, "maximum sessions exceeded");
457 5 : return NAT_NEXT_DROP;
458 : }
459 : }
460 :
461 : ip4_address_t sm_addr;
462 : u16 sm_port;
463 : u32 sm_fib_index;
464 28363 : int is_sm = 0;
465 : // First try to match static mapping by local address and port
466 28363 : if (!snat_static_mapping_match (vm, l_addr, l_port, rx_fib_index, proto,
467 : &sm_addr, &sm_port, &sm_fib_index, 0, 0, 0,
468 : &lb, 0, &is_identity_nat, 0))
469 : {
470 12 : if (PREDICT_FALSE (is_identity_nat))
471 : {
472 0 : *sessionp = NULL;
473 0 : return next;
474 : }
475 12 : is_sm = 1;
476 : }
477 :
478 28362 : if (PREDICT_TRUE (proto == IP_PROTOCOL_TCP))
479 : {
480 1602 : if (PREDICT_FALSE (!tcp_flags_is_init (
481 : vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
482 : {
483 8 : b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
484 8 : return NAT_NEXT_DROP;
485 : }
486 : }
487 :
488 28354 : s = nat_ed_session_alloc (sm, thread_index, now, proto);
489 28354 : ASSERT (s);
490 :
491 28354 : tx_fib_index = get_tx_fib_index (rx_fib_index, r_addr);
492 :
493 28350 : if (!is_sm)
494 : {
495 28344 : s->in2out.addr = l_addr;
496 28344 : s->in2out.port = l_port;
497 28344 : s->proto = proto;
498 28344 : s->in2out.fib_index = rx_fib_index;
499 28344 : s->out2in.fib_index = tx_fib_index;
500 :
501 : // suggest using local port to allocation function
502 28344 : outside_port = l_port;
503 :
504 28344 : if (PREDICT_FALSE (nat44_ed_external_sm_lookup (sm, r_addr, r_port,
505 : proto, &daddr, &dport)))
506 : {
507 9 : s->flags |= SNAT_SESSION_FLAG_HAIRPINNING;
508 : }
509 :
510 : // destination addr/port updated with real values in
511 : // nat_ed_alloc_addr_and_port
512 28346 : nat_6t_o2i_flow_init (sm, thread_index, s, daddr, dport, daddr, 0,
513 : s->out2in.fib_index, proto);
514 28347 : nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32);
515 28349 : if (IP_PROTOCOL_ICMP == proto)
516 : {
517 6565 : nat_6t_flow_icmp_id_rewrite_set (&s->o2i, l_port);
518 : }
519 : else
520 : {
521 21784 : nat_6t_flow_dport_rewrite_set (&s->o2i, l_port);
522 : }
523 28348 : nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
524 :
525 28346 : if (nat_ed_alloc_addr_and_port (
526 : sm, rx_fib_index, tx_sw_if_index, proto, thread_index, l_addr,
527 : r_addr, tsm->snat_thread_index, s, &outside_addr, &outside_port))
528 : {
529 139 : nat_elog_notice (sm, "addresses exhausted");
530 139 : b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
531 139 : nat_ed_session_delete (sm, s, thread_index, 1);
532 139 : return NAT_NEXT_DROP;
533 : }
534 28209 : s->out2in.addr = outside_addr;
535 28209 : s->out2in.port = outside_port;
536 : }
537 : else
538 : {
539 : // static mapping
540 6 : s->out2in.addr = outside_addr = sm_addr;
541 6 : s->out2in.port = outside_port = sm_port;
542 6 : s->in2out.addr = l_addr;
543 6 : s->in2out.port = l_port;
544 6 : s->proto = proto;
545 6 : s->in2out.fib_index = rx_fib_index;
546 6 : s->out2in.fib_index = tx_fib_index;
547 6 : s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
548 :
549 : // hairpinning?
550 6 : int is_hairpinning = nat44_ed_external_sm_lookup (sm, r_addr, r_port,
551 : proto, &daddr, &dport);
552 6 : s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING;
553 :
554 6 : if (IP_PROTOCOL_ICMP == proto)
555 : {
556 0 : nat_6t_o2i_flow_init (sm, thread_index, s, daddr, sm_port, sm_addr,
557 : sm_port, s->out2in.fib_index, proto);
558 0 : nat_6t_flow_icmp_id_rewrite_set (&s->o2i, l_port);
559 : }
560 : else
561 : {
562 6 : nat_6t_o2i_flow_init (sm, thread_index, s, daddr, dport, sm_addr,
563 : sm_port, s->out2in.fib_index, proto);
564 6 : nat_6t_flow_dport_rewrite_set (&s->o2i, l_port);
565 : }
566 6 : nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32);
567 6 : nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
568 6 : if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2))
569 : {
570 0 : nat_elog_notice (sm, "out2in key add failed");
571 0 : goto error;
572 : }
573 : }
574 :
575 28215 : if (lb)
576 0 : s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
577 28215 : s->ext_host_addr = r_addr;
578 28215 : s->ext_host_port = r_port;
579 :
580 28215 : nat_6t_i2o_flow_init (sm, thread_index, s, l_addr, l_port, r_addr, r_port,
581 : rx_fib_index, proto);
582 28216 : nat_6t_flow_saddr_rewrite_set (&s->i2o, outside_addr.as_u32);
583 28216 : nat_6t_flow_daddr_rewrite_set (&s->i2o, daddr.as_u32);
584 :
585 28217 : if (IP_PROTOCOL_ICMP == proto)
586 : {
587 6564 : nat_6t_flow_icmp_id_rewrite_set (&s->i2o, outside_port);
588 : }
589 : else
590 : {
591 21653 : nat_6t_flow_sport_rewrite_set (&s->i2o, outside_port);
592 21653 : nat_6t_flow_dport_rewrite_set (&s->i2o, dport);
593 : }
594 28217 : nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index);
595 :
596 28216 : if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
597 : {
598 0 : nat_elog_notice (sm, "in2out key add failed");
599 0 : goto error;
600 : }
601 :
602 : /* log NAT event */
603 28215 : nat_ipfix_logging_nat44_ses_create (
604 28215 : thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
605 28215 : s->in2out.port, s->out2in.port, s->in2out.fib_index);
606 :
607 28217 : nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
608 28217 : s->in2out.port, &s->ext_host_nat_addr,
609 28217 : s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
610 28217 : &s->ext_host_addr, s->ext_host_port, s->proto, 0);
611 :
612 28219 : per_vrf_sessions_register_session (s, thread_index);
613 :
614 28217 : *sessionp = s;
615 28217 : return next;
616 0 : error:
617 0 : if (s)
618 : {
619 0 : nat_ed_session_delete (sm, s, thread_index, 1);
620 : }
621 0 : *sessionp = s = NULL;
622 0 : return NAT_NEXT_DROP;
623 : }
624 :
625 : static_always_inline int
626 28369 : nat44_ed_not_translate (vlib_main_t *vm, vlib_node_runtime_t *node,
627 : u32 sw_if_index, vlib_buffer_t *b, ip4_header_t *ip,
628 : u32 proto, u32 rx_fib_index)
629 : {
630 28369 : snat_main_t *sm = &snat_main;
631 :
632 : clib_bihash_kv_16_8_t kv, value;
633 : ip4_address_t placeholder_addr;
634 : u32 placeholder_fib_index;
635 : u16 placeholder_port;
636 :
637 28369 : init_ed_k (&kv, ip->dst_address.as_u32,
638 28369 : vnet_buffer (b)->ip.reass.l4_dst_port, ip->src_address.as_u32,
639 28369 : vnet_buffer (b)->ip.reass.l4_src_port, sm->outside_fib_index,
640 28369 : ip->protocol);
641 :
642 : // do nat if active session or is static mapping
643 56738 : if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value) ||
644 28371 : !snat_static_mapping_match (
645 28371 : vm, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
646 : sm->outside_fib_index, proto, &placeholder_addr, &placeholder_port,
647 : &placeholder_fib_index, 1, 0, 0, 0, 0, 0, 0))
648 : {
649 9 : return 0;
650 : }
651 :
652 : // do not nat if forwarding enabled
653 28360 : if (sm->forwarding_enabled)
654 : {
655 17 : return 1;
656 : }
657 :
658 : // do not nat packet aimed at the interface address
659 28343 : if (PREDICT_FALSE (
660 : is_interface_addr (sm, node, sw_if_index, ip->dst_address.as_u32)))
661 : {
662 0 : return 1;
663 : }
664 :
665 : // do nat packets with resolvable destination
666 : // destination can be resolved either by:
667 : // a) vrf routing table entry
668 : // b) (non output feature) outside interface fib
669 28340 : if (is_destination_resolvable (rx_fib_index, ip->dst_address))
670 : {
671 28336 : return 0;
672 : }
673 :
674 4 : return 1;
675 : }
676 :
677 : static_always_inline int
678 66 : nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
679 : u32 thread_index, f64 now,
680 : vlib_main_t * vm, vlib_buffer_t * b)
681 : {
682 : clib_bihash_kv_16_8_t kv, value;
683 66 : snat_session_t *s = 0;
684 66 : snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
685 :
686 66 : if (!sm->forwarding_enabled)
687 21 : return 0;
688 :
689 45 : if (ip->protocol == IP_PROTOCOL_ICMP)
690 : {
691 : ip4_address_t lookup_saddr, lookup_daddr;
692 : u16 lookup_sport, lookup_dport;
693 : u8 lookup_protocol;
694 10 : if (nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr,
695 : &lookup_sport, &lookup_daddr,
696 : &lookup_dport, &lookup_protocol))
697 0 : return 0;
698 10 : init_ed_k (&kv, lookup_saddr.as_u32, lookup_sport, lookup_daddr.as_u32,
699 : lookup_dport, 0, lookup_protocol);
700 : }
701 35 : else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
702 : {
703 35 : init_ed_k (&kv, ip->src_address.as_u32,
704 35 : vnet_buffer (b)->ip.reass.l4_src_port, ip->dst_address.as_u32,
705 35 : vnet_buffer (b)->ip.reass.l4_dst_port, 0, ip->protocol);
706 : }
707 : else
708 : {
709 0 : init_ed_k (&kv, ip->src_address.as_u32, 0, ip->dst_address.as_u32, 0, 0,
710 0 : ip->protocol);
711 : }
712 :
713 45 : if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
714 : {
715 10 : ASSERT (thread_index == ed_value_get_thread_index (&value));
716 10 : s =
717 10 : pool_elt_at_index (tsm->sessions,
718 : ed_value_get_session_index (&value));
719 :
720 10 : if (na44_ed_is_fwd_bypass_session (s))
721 : {
722 8 : if (ip->protocol == IP_PROTOCOL_TCP)
723 : {
724 4 : nat44_set_tcp_session_state_i2o (
725 4 : sm, now, s, vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags,
726 : thread_index);
727 : }
728 : /* Accounting */
729 8 : nat44_session_update_counters (s, now,
730 : vlib_buffer_length_in_chain (vm, b),
731 : thread_index);
732 : /* Per-user LRU list maintenance */
733 8 : nat44_session_update_lru (sm, s, thread_index);
734 8 : return 1;
735 : }
736 : else
737 2 : return 0;
738 : }
739 :
740 35 : return 0;
741 : }
742 :
743 : static_always_inline int
744 46 : nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b,
745 : ip4_header_t *ip, u16 src_port,
746 : u16 dst_port, u32 thread_index,
747 : u32 rx_sw_if_index, u32 tx_sw_if_index,
748 : int is_multi_worker)
749 : {
750 : clib_bihash_kv_16_8_t kv, value;
751 46 : snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
752 : snat_interface_t *i;
753 : snat_session_t *s;
754 46 : u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
755 46 : u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
756 :
757 : /* src NAT check */
758 46 : init_ed_k (&kv, ip->src_address.as_u32, src_port, ip->dst_address.as_u32,
759 46 : dst_port, tx_fib_index, ip->protocol);
760 46 : if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
761 : {
762 0 : ASSERT (thread_index == ed_value_get_thread_index (&value));
763 0 : s =
764 0 : pool_elt_at_index (tsm->sessions,
765 : ed_value_get_session_index (&value));
766 0 : return 1;
767 : }
768 :
769 : /* dst NAT check */
770 46 : if (is_multi_worker &&
771 29 : PREDICT_TRUE (!pool_is_free_index (
772 : tsm->sessions, vnet_buffer2 (b)->nat.cached_dst_nat_session_index)))
773 : {
774 : nat_6t_t lookup;
775 22 : lookup.fib_index = rx_fib_index;
776 22 : lookup.proto = ip->protocol;
777 22 : lookup.daddr.as_u32 = ip->src_address.as_u32;
778 22 : lookup.dport = src_port;
779 22 : lookup.saddr.as_u32 = ip->dst_address.as_u32;
780 22 : lookup.sport = dst_port;
781 22 : s = pool_elt_at_index (
782 : tsm->sessions, vnet_buffer2 (b)->nat.cached_dst_nat_session_index);
783 22 : if (PREDICT_TRUE (nat_6t_t_eq (&s->i2o.match, &lookup)))
784 : {
785 4 : goto skip_dst_nat_lookup;
786 : }
787 18 : s = NULL;
788 : }
789 :
790 42 : init_ed_k (&kv, ip->dst_address.as_u32, dst_port, ip->src_address.as_u32,
791 42 : src_port, rx_fib_index, ip->protocol);
792 42 : if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
793 : {
794 26 : ASSERT (thread_index == ed_value_get_thread_index (&value));
795 26 : s =
796 26 : pool_elt_at_index (tsm->sessions,
797 : ed_value_get_session_index (&value));
798 :
799 30 : skip_dst_nat_lookup:
800 30 : if (na44_ed_is_fwd_bypass_session (s))
801 6 : return 0;
802 :
803 : /* hairpinning */
804 48 : pool_foreach (i, sm->output_feature_interfaces)
805 : {
806 24 : if ((nat44_ed_is_interface_inside (i)) &&
807 24 : (rx_sw_if_index == i->sw_if_index))
808 0 : return 0;
809 : }
810 24 : return 1;
811 : }
812 :
813 16 : return 0;
814 : }
815 :
816 : static inline u32
817 6568 : icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip,
818 : icmp46_header_t *icmp, u32 sw_if_index,
819 : u32 tx_sw_if_index, u32 rx_fib_index,
820 : vlib_node_runtime_t *node, u32 next, f64 now,
821 : u32 thread_index, snat_session_t **s_p,
822 : int is_multi_worker)
823 : {
824 6568 : vlib_main_t *vm = vlib_get_main ();
825 : u16 checksum;
826 : int err;
827 6568 : snat_session_t *s = NULL;
828 6568 : u8 lookup_protocol = ip->protocol;
829 : u16 lookup_sport, lookup_dport;
830 : ip4_address_t lookup_saddr, lookup_daddr;
831 :
832 6568 : err = nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr,
833 : &lookup_sport, &lookup_daddr,
834 : &lookup_dport, &lookup_protocol);
835 6568 : if (err != 0)
836 : {
837 0 : b->error = node->errors[err];
838 0 : return NAT_NEXT_DROP;
839 : }
840 :
841 6568 : if (tx_sw_if_index != ~0)
842 : {
843 8 : if (PREDICT_FALSE (nat44_ed_not_translate_output_feature (
844 : sm, b, ip, lookup_sport, lookup_dport, thread_index, sw_if_index,
845 : tx_sw_if_index, is_multi_worker)))
846 : {
847 2 : return next;
848 : }
849 : }
850 : else
851 : {
852 6560 : if (PREDICT_FALSE (nat44_ed_not_translate (
853 : vm, node, sw_if_index, b, ip, IP_PROTOCOL_ICMP, rx_fib_index)))
854 : {
855 0 : return next;
856 : }
857 : }
858 :
859 6566 : if (PREDICT_FALSE (icmp_type_is_error_message (
860 : vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
861 : {
862 0 : b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
863 0 : return NAT_NEXT_DROP;
864 : }
865 :
866 : next =
867 6566 : slow_path_ed (vm, sm, b, ip->src_address, ip->dst_address, lookup_sport,
868 6566 : lookup_dport, ip->protocol, rx_fib_index, tx_sw_if_index, &s,
869 : node, next, thread_index, vlib_time_now (vm));
870 :
871 6565 : if (NAT_NEXT_DROP == next)
872 1 : goto out;
873 :
874 6564 : if (PREDICT_TRUE (!ip4_is_fragment (ip)))
875 : {
876 13110 : ip_csum_t sum = ip_incremental_checksum_buffer (
877 6555 : vm, b, (u8 *) icmp - (u8 *) vlib_buffer_get_current (b),
878 6555 : ntohs (ip->length) - ip4_header_bytes (ip), 0);
879 6555 : checksum = ~ip_csum_fold (sum);
880 6555 : if (PREDICT_FALSE (checksum != 0 && checksum != 0xffff))
881 : {
882 0 : next = NAT_NEXT_DROP;
883 0 : goto out;
884 : }
885 : }
886 :
887 6564 : out:
888 6565 : if (PREDICT_TRUE (next != NAT_NEXT_DROP && s))
889 : {
890 : /* Accounting */
891 6564 : nat44_session_update_counters (
892 : s, now, vlib_buffer_length_in_chain (vm, b), thread_index);
893 : /* Per-user LRU list maintenance */
894 6564 : nat44_session_update_lru (sm, s, thread_index);
895 : }
896 6565 : *s_p = s;
897 6565 : return next;
898 : }
899 :
900 : static snat_session_t *
901 2 : nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
902 : ip4_header_t *ip, u32 rx_fib_index,
903 : u32 thread_index, f64 now,
904 : vlib_main_t *vm,
905 : vlib_node_runtime_t *node)
906 : {
907 : clib_bihash_kv_16_8_t s_kv, s_value;
908 2 : snat_static_mapping_t *m = NULL;
909 2 : snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
910 2 : snat_session_t *s = NULL;
911 : u32 tx_fib_index;
912 : int i;
913 2 : ip4_address_t new_src_addr = { 0 };
914 2 : ip4_address_t new_dst_addr = ip->dst_address;
915 :
916 2 : if (PREDICT_FALSE (
917 : nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
918 : {
919 0 : b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
920 0 : nat_ipfix_logging_max_sessions (thread_index,
921 : sm->max_translations_per_thread);
922 0 : nat_elog_notice (sm, "maximum sessions exceeded");
923 0 : return 0;
924 : }
925 :
926 2 : tx_fib_index = get_tx_fib_index (rx_fib_index, ip->dst_address);
927 :
928 : // Try to find static mapping first
929 2 : m = nat44_ed_sm_i2o_lookup (sm, ip->src_address, 0, rx_fib_index,
930 2 : ip->protocol);
931 2 : if (m)
932 : {
933 0 : new_src_addr = m->external_addr;
934 : }
935 : else
936 : {
937 2 : pool_foreach (s, tsm->sessions)
938 : {
939 2 : if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
940 : {
941 2 : init_ed_k (&s_kv, s->out2in.addr.as_u32, 0,
942 : ip->dst_address.as_u32, 0, tx_fib_index,
943 2 : ip->protocol);
944 2 : if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value))
945 : {
946 2 : new_src_addr = s->out2in.addr;
947 : }
948 2 : break;
949 : }
950 : }
951 :
952 2 : if (!new_src_addr.as_u32)
953 : {
954 0 : for (i = 0; i < vec_len (sm->addresses); i++)
955 : {
956 0 : init_ed_k (&s_kv, sm->addresses[i].addr.as_u32, 0,
957 : ip->dst_address.as_u32, 0, tx_fib_index,
958 0 : ip->protocol);
959 0 : if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value))
960 : {
961 0 : new_src_addr = sm->addresses[i].addr;
962 : }
963 : }
964 : }
965 : }
966 :
967 2 : if (!new_src_addr.as_u32)
968 : {
969 : // could not allocate address for translation ...
970 0 : return 0;
971 : }
972 :
973 2 : s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
974 2 : if (!s)
975 : {
976 0 : b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
977 0 : nat_elog_warn (sm, "create NAT session failed");
978 0 : return 0;
979 : }
980 :
981 2 : nat_6t_i2o_flow_init (sm, thread_index, s, ip->src_address, 0,
982 2 : ip->dst_address, 0, rx_fib_index, ip->protocol);
983 2 : nat_6t_flow_saddr_rewrite_set (&s->i2o, new_src_addr.as_u32);
984 2 : nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index);
985 :
986 : // hairpinning?
987 2 : int is_hairpinning = nat44_ed_external_sm_lookup (
988 2 : sm, ip->dst_address, 0, ip->protocol, &new_dst_addr, NULL);
989 2 : s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING;
990 :
991 2 : nat_6t_flow_daddr_rewrite_set (&s->i2o, new_dst_addr.as_u32);
992 2 : nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index);
993 :
994 2 : nat_6t_o2i_flow_init (sm, thread_index, s, new_dst_addr, 0, new_src_addr, 0,
995 2 : tx_fib_index, ip->protocol);
996 2 : nat_6t_flow_saddr_rewrite_set (&s->o2i, ip->dst_address.as_u32);
997 2 : nat_6t_flow_daddr_rewrite_set (&s->o2i, ip->src_address.as_u32);
998 2 : nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
999 :
1000 2 : s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
1001 2 : s->out2in.addr.as_u32 = new_src_addr.as_u32;
1002 2 : s->out2in.fib_index = tx_fib_index;
1003 2 : s->in2out.addr.as_u32 = ip->src_address.as_u32;
1004 2 : s->in2out.fib_index = rx_fib_index;
1005 2 : s->in2out.port = s->out2in.port = ip->protocol;
1006 2 : if (m)
1007 0 : s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1008 :
1009 2 : if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
1010 : {
1011 0 : nat_elog_notice (sm, "in2out flow hash add failed");
1012 0 : nat_ed_session_delete (sm, s, thread_index, 1);
1013 0 : return NULL;
1014 : }
1015 :
1016 2 : if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
1017 : {
1018 0 : nat_elog_notice (sm, "out2in flow hash add failed");
1019 0 : nat_ed_session_delete (sm, s, thread_index, 1);
1020 0 : return NULL;
1021 : }
1022 :
1023 2 : per_vrf_sessions_register_session (s, thread_index);
1024 :
1025 : /* Accounting */
1026 2 : nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
1027 : thread_index);
1028 : /* Per-user LRU list maintenance */
1029 2 : nat44_session_update_lru (sm, s, thread_index);
1030 :
1031 2 : return s;
1032 : }
1033 :
1034 : static inline uword
1035 365 : nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm,
1036 : vlib_node_runtime_t *node,
1037 : vlib_frame_t *frame,
1038 : int is_output_feature,
1039 : int is_multi_worker)
1040 : {
1041 : u32 n_left_from, *from;
1042 365 : snat_main_t *sm = &snat_main;
1043 365 : f64 now = vlib_time_now (vm);
1044 364 : u32 thread_index = vm->thread_index;
1045 364 : snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1046 364 : u32 def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH
1047 364 : : NAT_NEXT_IN2OUT_ED_SLOW_PATH;
1048 :
1049 364 : from = vlib_frame_vector_args (frame);
1050 363 : n_left_from = frame->n_vectors;
1051 :
1052 363 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1053 363 : u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1054 363 : vlib_get_buffers (vm, from, b, n_left_from);
1055 :
1056 28967 : while (n_left_from > 0)
1057 : {
1058 : vlib_buffer_t *b0;
1059 28602 : u32 rx_sw_if_index0, rx_fib_index0, iph_offset0 = 0;
1060 : u32 tx_sw_if_index0;
1061 : u32 cntr_sw_if_index0;
1062 : ip_protocol_t proto0;
1063 : ip4_header_t *ip0;
1064 28602 : snat_session_t *s0 = 0;
1065 28602 : clib_bihash_kv_16_8_t kv0 = { 0 }, value0;
1066 28602 : nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
1067 28602 : nat_6t_flow_t *f = 0;
1068 : nat_6t_t lookup;
1069 28602 : int lookup_skipped = 0;
1070 :
1071 28602 : b0 = *b;
1072 28602 : b++;
1073 :
1074 : /* Prefetch next iteration. */
1075 28602 : if (PREDICT_TRUE (n_left_from >= 2))
1076 : {
1077 : vlib_buffer_t *p2;
1078 :
1079 28237 : p2 = *b;
1080 :
1081 28237 : vlib_prefetch_buffer_header (p2, LOAD);
1082 :
1083 28241 : clib_prefetch_load (p2->data);
1084 : }
1085 :
1086 28604 : if (is_output_feature)
1087 : {
1088 66 : iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1089 : }
1090 :
1091 28604 : next[0] = vnet_buffer2 (b0)->nat.arc_next;
1092 :
1093 28602 : ip0 =
1094 28604 : (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + iph_offset0);
1095 :
1096 28602 : rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1097 28602 : tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1098 28602 : cntr_sw_if_index0 =
1099 28602 : is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
1100 28602 : rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1101 : rx_sw_if_index0);
1102 28599 : lookup.fib_index = rx_fib_index0;
1103 :
1104 28599 : if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1))
1105 : {
1106 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1107 0 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1108 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
1109 : 0);
1110 0 : next[0] = NAT_NEXT_ICMP_ERROR;
1111 0 : goto trace0;
1112 : }
1113 :
1114 28599 : proto0 = ip0->protocol;
1115 :
1116 28599 : if (is_output_feature)
1117 : {
1118 66 : if (PREDICT_FALSE
1119 : (nat_not_translate_output_feature_fwd
1120 : (sm, ip0, thread_index, now, vm, b0)))
1121 8 : goto trace0;
1122 : }
1123 :
1124 28591 : if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP))
1125 : {
1126 6597 : if (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
1127 15 : ICMP4_echo_request &&
1128 15 : vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
1129 3 : ICMP4_echo_reply &&
1130 3 : !icmp_type_is_error_message (
1131 3 : vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
1132 : {
1133 0 : b0->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
1134 0 : next[0] = NAT_NEXT_DROP;
1135 0 : goto trace0;
1136 : }
1137 6597 : int err = nat_get_icmp_session_lookup_values (
1138 : b0, ip0, &lookup.saddr, &lookup.sport, &lookup.daddr,
1139 : &lookup.dport, &lookup.proto);
1140 6597 : if (err != 0)
1141 : {
1142 0 : b0->error = node->errors[err];
1143 0 : next[0] = NAT_NEXT_DROP;
1144 0 : goto trace0;
1145 : }
1146 : }
1147 : else
1148 : {
1149 21994 : lookup.proto = ip0->protocol;
1150 21994 : lookup.saddr.as_u32 = ip0->src_address.as_u32;
1151 21994 : lookup.daddr.as_u32 = ip0->dst_address.as_u32;
1152 21994 : lookup.sport = vnet_buffer (b0)->ip.reass.l4_src_port;
1153 21994 : lookup.dport = vnet_buffer (b0)->ip.reass.l4_dst_port;
1154 : }
1155 :
1156 : /* there might be a stashed index in vnet_buffer2 from handoff or
1157 : * classify node, see if it can be used */
1158 56995 : if (is_multi_worker &&
1159 28407 : !pool_is_free_index (tsm->sessions,
1160 28407 : vnet_buffer2 (b0)->nat.cached_session_index))
1161 : {
1162 24058 : s0 = pool_elt_at_index (tsm->sessions,
1163 : vnet_buffer2 (b0)->nat.cached_session_index);
1164 24058 : if (PREDICT_TRUE (
1165 : nat_6t_t_eq (&s0->i2o.match, &lookup)
1166 : // for some hairpinning cases there are two "i2i" flows instead
1167 : // of i2o and o2i as both hosts are on inside
1168 : || (s0->flags & SNAT_SESSION_FLAG_HAIRPINNING &&
1169 : nat_6t_t_eq (&s0->o2i.match, &lookup))))
1170 : {
1171 : /* yes, this is the droid we're looking for */
1172 140 : lookup_skipped = 1;
1173 140 : goto skip_lookup;
1174 : }
1175 23918 : s0 = NULL;
1176 : }
1177 :
1178 28448 : init_ed_k (&kv0, lookup.saddr.as_u32, lookup.sport, lookup.daddr.as_u32,
1179 28448 : lookup.dport, lookup.fib_index, lookup.proto);
1180 :
1181 : // lookup flow
1182 28447 : if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
1183 : {
1184 : // flow does not exist go slow path
1185 28412 : next[0] = def_slow;
1186 28412 : goto trace0;
1187 : }
1188 :
1189 39 : ASSERT (thread_index == ed_value_get_thread_index (&value0));
1190 39 : s0 =
1191 39 : pool_elt_at_index (tsm->sessions,
1192 : ed_value_get_session_index (&value0));
1193 :
1194 179 : skip_lookup:
1195 :
1196 179 : ASSERT (thread_index == s0->thread_index);
1197 :
1198 179 : if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
1199 : {
1200 : // session is closed, go slow path
1201 0 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1202 0 : nat_ed_session_delete (sm, s0, thread_index, 1);
1203 0 : s0 = 0;
1204 0 : next[0] = def_slow;
1205 0 : goto trace0;
1206 : }
1207 :
1208 : // drop if session expired
1209 : u64 sess_timeout_time;
1210 179 : sess_timeout_time =
1211 179 : s0->last_heard + (f64) nat44_session_get_timeout (sm, s0);
1212 179 : if (now >= sess_timeout_time)
1213 : {
1214 7 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1215 7 : nat_ed_session_delete (sm, s0, thread_index, 1);
1216 7 : s0 = 0;
1217 : // session is closed, go slow path
1218 7 : next[0] = def_slow;
1219 7 : goto trace0;
1220 : }
1221 :
1222 172 : b0->flags |= VNET_BUFFER_F_IS_NATED;
1223 :
1224 172 : if (nat_6t_t_eq (&s0->i2o.match, &lookup))
1225 : {
1226 171 : f = &s0->i2o;
1227 : }
1228 2 : else if (s0->flags & SNAT_SESSION_FLAG_HAIRPINNING &&
1229 1 : nat_6t_t_eq (&s0->o2i.match, &lookup))
1230 : {
1231 1 : f = &s0->o2i;
1232 : }
1233 : else
1234 : {
1235 0 : translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH;
1236 0 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1237 0 : nat_ed_session_delete (sm, s0, thread_index, 1);
1238 0 : s0 = 0;
1239 0 : next[0] = NAT_NEXT_DROP;
1240 0 : b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
1241 0 : goto trace0;
1242 : }
1243 :
1244 172 : if (NAT_ED_TRNSL_ERR_SUCCESS !=
1245 172 : (translation_error = nat_6t_flow_buf_translate_i2o (
1246 : vm, sm, b0, ip0, f, proto0, is_output_feature)))
1247 : {
1248 0 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1249 0 : nat_ed_session_delete (sm, s0, thread_index, 1);
1250 0 : s0 = 0;
1251 0 : next[0] = NAT_NEXT_DROP;
1252 0 : b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
1253 0 : goto trace0;
1254 : }
1255 :
1256 172 : switch (proto0)
1257 : {
1258 116 : case IP_PROTOCOL_TCP:
1259 116 : vlib_increment_simple_counter (&sm->counters.fastpath.in2out.tcp,
1260 : thread_index, cntr_sw_if_index0, 1);
1261 116 : nat44_set_tcp_session_state_i2o (
1262 116 : sm, now, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
1263 : thread_index);
1264 116 : break;
1265 25 : case IP_PROTOCOL_UDP:
1266 25 : vlib_increment_simple_counter (&sm->counters.fastpath.in2out.udp,
1267 : thread_index, cntr_sw_if_index0, 1);
1268 25 : break;
1269 30 : case IP_PROTOCOL_ICMP:
1270 30 : vlib_increment_simple_counter (&sm->counters.fastpath.in2out.icmp,
1271 : thread_index, cntr_sw_if_index0, 1);
1272 30 : break;
1273 1 : default:
1274 1 : vlib_increment_simple_counter (&sm->counters.fastpath.in2out.other,
1275 : thread_index, cntr_sw_if_index0, 1);
1276 1 : break;
1277 : }
1278 :
1279 : /* Accounting */
1280 172 : nat44_session_update_counters (s0, now,
1281 : vlib_buffer_length_in_chain (vm, b0),
1282 : thread_index);
1283 : /* Per-user LRU list maintenance */
1284 172 : nat44_session_update_lru (sm, s0, thread_index);
1285 :
1286 28599 : trace0:
1287 28599 : if (PREDICT_FALSE
1288 : ((node->flags & VLIB_NODE_FLAG_TRACE)
1289 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1290 : {
1291 : nat_in2out_ed_trace_t *t =
1292 20101 : vlib_add_trace (vm, node, b0, sizeof (*t));
1293 20109 : t->sw_if_index = rx_sw_if_index0;
1294 20109 : t->next_index = next[0];
1295 20109 : t->is_slow_path = 0;
1296 20109 : t->translation_error = translation_error;
1297 20109 : t->lookup_skipped = lookup_skipped;
1298 20109 : clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
1299 :
1300 20107 : if (s0)
1301 : {
1302 172 : t->session_index = s0 - tsm->sessions;
1303 172 : clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
1304 172 : clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
1305 172 : t->translation_via_i2of = (&s0->i2o == f);
1306 172 : t->tcp_state = s0->tcp_state;
1307 : }
1308 : else
1309 : {
1310 19935 : t->session_index = ~0;
1311 : }
1312 : }
1313 :
1314 28605 : if (next[0] == NAT_NEXT_DROP)
1315 : {
1316 0 : vlib_increment_simple_counter (&sm->counters.fastpath.in2out.drops,
1317 : thread_index, cntr_sw_if_index0, 1);
1318 : }
1319 :
1320 28605 : n_left_from--;
1321 28605 : next++;
1322 : }
1323 :
1324 365 : vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1325 365 : frame->n_vectors);
1326 364 : return frame->n_vectors;
1327 : }
1328 :
1329 : static inline uword
1330 256 : nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm,
1331 : vlib_node_runtime_t *node,
1332 : vlib_frame_t *frame,
1333 : int is_output_feature,
1334 : int is_multi_worker)
1335 : {
1336 : u32 n_left_from, *from;
1337 256 : snat_main_t *sm = &snat_main;
1338 256 : f64 now = vlib_time_now (vm);
1339 256 : u32 thread_index = vm->thread_index;
1340 256 : snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1341 :
1342 256 : from = vlib_frame_vector_args (frame);
1343 256 : n_left_from = frame->n_vectors;
1344 :
1345 256 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1346 256 : u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1347 256 : vlib_get_buffers (vm, from, b, n_left_from);
1348 :
1349 28694 : while (n_left_from > 0)
1350 : {
1351 : vlib_buffer_t *b0;
1352 28437 : u32 rx_sw_if_index0, rx_fib_index0, iph_offset0 = 0;
1353 : u32 tx_sw_if_index0;
1354 : u32 cntr_sw_if_index0;
1355 : ip_protocol_t proto0;
1356 : ip4_header_t *ip0;
1357 : udp_header_t *udp0;
1358 : icmp46_header_t *icmp0;
1359 28437 : snat_session_t *s0 = 0;
1360 28437 : clib_bihash_kv_16_8_t kv0 = { 0 }, value0;
1361 28437 : int translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
1362 :
1363 28437 : b0 = *b;
1364 :
1365 28437 : if (is_output_feature)
1366 52 : iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1367 :
1368 28437 : next[0] = vnet_buffer2 (b0)->nat.arc_next;
1369 :
1370 28437 : ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1371 : iph_offset0);
1372 :
1373 28437 : rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1374 28437 : tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1375 28437 : cntr_sw_if_index0 =
1376 28437 : is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
1377 28437 : rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1378 : rx_sw_if_index0);
1379 :
1380 28436 : if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1))
1381 : {
1382 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1383 0 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1384 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
1385 : 0);
1386 0 : next[0] = NAT_NEXT_ICMP_ERROR;
1387 0 : goto trace0;
1388 : }
1389 :
1390 28436 : udp0 = ip4_next_header (ip0);
1391 28436 : icmp0 = (icmp46_header_t *) udp0;
1392 28436 : proto0 = ip0->protocol;
1393 :
1394 28436 : if (PREDICT_FALSE (nat44_ed_is_unk_proto (proto0)))
1395 : {
1396 2 : s0 = nat44_ed_in2out_slowpath_unknown_proto (
1397 : sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node);
1398 2 : if (!s0)
1399 0 : next[0] = NAT_NEXT_DROP;
1400 :
1401 2 : if (NAT_NEXT_DROP != next[0] && s0 &&
1402 : NAT_ED_TRNSL_ERR_SUCCESS !=
1403 2 : (translation_error = nat_6t_flow_buf_translate_i2o (
1404 2 : vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature)))
1405 : {
1406 0 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1407 0 : nat_ed_session_delete (sm, s0, thread_index, 1);
1408 0 : s0 = 0;
1409 0 : next[0] = NAT_NEXT_DROP;
1410 0 : b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
1411 0 : goto trace0;
1412 : }
1413 :
1414 2 : vlib_increment_simple_counter (&sm->counters.slowpath.in2out.other,
1415 : thread_index, cntr_sw_if_index0, 1);
1416 2 : goto trace0;
1417 : }
1418 :
1419 28435 : if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP))
1420 : {
1421 13135 : next[0] = icmp_in2out_ed_slow_path (
1422 : sm, b0, ip0, icmp0, rx_sw_if_index0, tx_sw_if_index0,
1423 6568 : rx_fib_index0, node, next[0], now, thread_index, &s0,
1424 : is_multi_worker);
1425 6567 : if (NAT_NEXT_DROP != next[0] && s0 &&
1426 : NAT_ED_TRNSL_ERR_SUCCESS !=
1427 6565 : (translation_error = nat_6t_flow_buf_translate_i2o (
1428 6564 : vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature)))
1429 : {
1430 0 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1431 0 : nat_ed_session_delete (sm, s0, thread_index, 1);
1432 0 : s0 = 0;
1433 0 : next[0] = NAT_NEXT_DROP;
1434 0 : b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
1435 0 : goto trace0;
1436 : }
1437 :
1438 6568 : if (NAT_NEXT_DROP != next[0])
1439 : {
1440 6567 : vlib_increment_simple_counter (
1441 : &sm->counters.slowpath.in2out.icmp, thread_index,
1442 : cntr_sw_if_index0, 1);
1443 : }
1444 6567 : goto trace0;
1445 : }
1446 :
1447 21867 : init_ed_k (
1448 21867 : &kv0, ip0->src_address.as_u32, vnet_buffer (b0)->ip.reass.l4_src_port,
1449 21867 : ip0->dst_address.as_u32, vnet_buffer (b0)->ip.reass.l4_dst_port,
1450 21867 : rx_fib_index0, ip0->protocol);
1451 21867 : if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
1452 : {
1453 21 : ASSERT (thread_index == ed_value_get_thread_index (&value0));
1454 21 : s0 =
1455 21 : pool_elt_at_index (tsm->sessions,
1456 : ed_value_get_session_index (&value0));
1457 : }
1458 :
1459 21868 : if (!s0)
1460 : {
1461 21847 : if (is_output_feature)
1462 : {
1463 38 : if (PREDICT_FALSE (nat44_ed_not_translate_output_feature (
1464 : sm, b0, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
1465 : vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1466 : rx_sw_if_index0, tx_sw_if_index0, is_multi_worker)))
1467 22 : goto trace0;
1468 :
1469 : /*
1470 : * Send DHCP packets to the ipv4 stack, or we won't
1471 : * be able to use dhcp client on the outside interface
1472 : */
1473 16 : if (PREDICT_FALSE (
1474 : proto0 == IP_PROTOCOL_UDP &&
1475 : (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1476 : clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server)) &&
1477 : ip0->dst_address.as_u32 == 0xffffffff))
1478 0 : goto trace0;
1479 : }
1480 : else
1481 : {
1482 21809 : if (PREDICT_FALSE (
1483 : nat44_ed_not_translate (vm, node, rx_sw_if_index0, b0, ip0,
1484 : proto0, rx_fib_index0)))
1485 21 : goto trace0;
1486 : }
1487 :
1488 21804 : next[0] =
1489 21802 : slow_path_ed (vm, sm, b0, ip0->src_address, ip0->dst_address,
1490 21802 : vnet_buffer (b0)->ip.reass.l4_src_port,
1491 21802 : vnet_buffer (b0)->ip.reass.l4_dst_port,
1492 21802 : ip0->protocol, rx_fib_index0, tx_sw_if_index0, &s0,
1493 21802 : node, next[0], thread_index, now);
1494 :
1495 21804 : if (PREDICT_FALSE (next[0] == NAT_NEXT_DROP))
1496 151 : goto trace0;
1497 :
1498 21653 : if (PREDICT_FALSE (!s0))
1499 0 : goto trace0;
1500 :
1501 : }
1502 :
1503 21674 : b0->flags |= VNET_BUFFER_F_IS_NATED;
1504 :
1505 21674 : if (NAT_ED_TRNSL_ERR_SUCCESS !=
1506 21674 : (translation_error = nat_6t_flow_buf_translate_i2o (
1507 21674 : vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature)))
1508 : {
1509 0 : nat44_ed_free_session_data (sm, s0, thread_index, 0);
1510 0 : nat_ed_session_delete (sm, s0, thread_index, 1);
1511 0 : s0 = 0;
1512 0 : next[0] = NAT_NEXT_DROP;
1513 0 : b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
1514 0 : goto trace0;
1515 : }
1516 :
1517 21675 : if (PREDICT_TRUE (proto0 == IP_PROTOCOL_TCP))
1518 : {
1519 1608 : vlib_increment_simple_counter (&sm->counters.slowpath.in2out.tcp,
1520 : thread_index, cntr_sw_if_index0, 1);
1521 1608 : nat44_set_tcp_session_state_i2o (
1522 1608 : sm, now, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
1523 : thread_index);
1524 : }
1525 : else
1526 : {
1527 20067 : vlib_increment_simple_counter (&sm->counters.slowpath.in2out.udp,
1528 : thread_index, cntr_sw_if_index0, 1);
1529 : }
1530 :
1531 : /* Accounting */
1532 21675 : nat44_session_update_counters (s0, now,
1533 : vlib_buffer_length_in_chain
1534 : (vm, b0), thread_index);
1535 : /* Per-user LRU list maintenance */
1536 21674 : nat44_session_update_lru (sm, s0, thread_index);
1537 :
1538 28436 : trace0:
1539 28436 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1540 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1541 : {
1542 : nat_in2out_ed_trace_t *t =
1543 17426 : vlib_add_trace (vm, node, b0, sizeof (*t));
1544 17429 : t->sw_if_index = rx_sw_if_index0;
1545 17429 : t->next_index = next[0];
1546 17429 : t->is_slow_path = 1;
1547 17429 : t->translation_error = translation_error;
1548 17429 : clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
1549 :
1550 17428 : if (s0)
1551 : {
1552 17231 : t->session_index = s0 - tsm->sessions;
1553 17231 : clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
1554 17231 : clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
1555 17231 : t->translation_via_i2of = 1;
1556 17231 : t->tcp_state = s0->tcp_state;
1557 : }
1558 :
1559 : else
1560 : {
1561 197 : t->session_index = ~0;
1562 : }
1563 : }
1564 :
1565 28438 : if (next[0] == NAT_NEXT_DROP)
1566 : {
1567 152 : vlib_increment_simple_counter (&sm->counters.slowpath.in2out.drops,
1568 : thread_index, cntr_sw_if_index0, 1);
1569 : }
1570 :
1571 28438 : n_left_from--;
1572 28438 : next++;
1573 28438 : b++;
1574 : }
1575 :
1576 257 : vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1577 257 : frame->n_vectors);
1578 :
1579 257 : return frame->n_vectors;
1580 : }
1581 :
1582 2574 : VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
1583 : vlib_node_runtime_t * node,
1584 : vlib_frame_t * frame)
1585 : {
1586 338 : if (snat_main.num_workers > 1)
1587 : {
1588 302 : return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0, 1);
1589 : }
1590 : else
1591 : {
1592 36 : return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0, 0);
1593 : }
1594 : }
1595 :
1596 49304 : VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1597 : .name = "nat44-ed-in2out",
1598 : .vector_size = sizeof (u32),
1599 : .sibling_of = "nat-default",
1600 : .format_trace = format_nat_in2out_ed_trace,
1601 : .type = VLIB_NODE_TYPE_INTERNAL,
1602 : .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1603 : .error_strings = nat_in2out_ed_error_strings,
1604 : .runtime_data_bytes = sizeof (snat_runtime_t),
1605 : };
1606 :
1607 2263 : VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
1608 : vlib_node_runtime_t * node,
1609 : vlib_frame_t * frame)
1610 : {
1611 27 : if (snat_main.num_workers > 1)
1612 : {
1613 15 : return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1, 1);
1614 : }
1615 : else
1616 : {
1617 12 : return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1, 0);
1618 : }
1619 : }
1620 :
1621 49304 : VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1622 : .name = "nat44-ed-in2out-output",
1623 : .vector_size = sizeof (u32),
1624 : .sibling_of = "nat-default",
1625 : .format_trace = format_nat_in2out_ed_trace,
1626 : .type = VLIB_NODE_TYPE_INTERNAL,
1627 : .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1628 : .error_strings = nat_in2out_ed_error_strings,
1629 : .runtime_data_bytes = sizeof (snat_runtime_t),
1630 : };
1631 :
1632 2468 : VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
1633 : vlib_node_runtime_t *
1634 : node, vlib_frame_t * frame)
1635 : {
1636 232 : if (snat_main.num_workers > 1)
1637 : {
1638 220 : return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0, 1);
1639 : }
1640 : else
1641 : {
1642 12 : return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0, 0);
1643 : }
1644 : }
1645 :
1646 49304 : VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1647 : .name = "nat44-ed-in2out-slowpath",
1648 : .vector_size = sizeof (u32),
1649 : .sibling_of = "nat-default",
1650 : .format_trace = format_nat_in2out_ed_trace,
1651 : .type = VLIB_NODE_TYPE_INTERNAL,
1652 : .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1653 : .error_strings = nat_in2out_ed_error_strings,
1654 : .runtime_data_bytes = sizeof (snat_runtime_t),
1655 : };
1656 :
1657 2260 : VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
1658 : vlib_node_runtime_t
1659 : * node,
1660 : vlib_frame_t * frame)
1661 : {
1662 24 : if (snat_main.num_workers > 1)
1663 : {
1664 13 : return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1, 1);
1665 : }
1666 : else
1667 : {
1668 11 : return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1, 0);
1669 : }
1670 : }
1671 :
1672 49304 : VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1673 : .name = "nat44-ed-in2out-output-slowpath",
1674 : .vector_size = sizeof (u32),
1675 : .sibling_of = "nat-default",
1676 : .format_trace = format_nat_in2out_ed_trace,
1677 : .type = VLIB_NODE_TYPE_INTERNAL,
1678 : .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1679 : .error_strings = nat_in2out_ed_error_strings,
1680 : .runtime_data_bytes = sizeof (snat_runtime_t),
1681 : };
1682 :
1683 : static u8 *
1684 141 : format_nat_pre_trace (u8 * s, va_list * args)
1685 : {
1686 141 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1687 141 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1688 141 : nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
1689 141 : return format (s, "in2out next_index %d arc_next_index %d", t->next_index,
1690 : t->arc_next_index);
1691 : }
1692 :
1693 2254 : VLIB_NODE_FN (nat_pre_in2out_node)
1694 : (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1695 : {
1696 18 : return nat_pre_node_fn_inline (vm, node, frame,
1697 : NAT_NEXT_IN2OUT_ED_FAST_PATH);
1698 : }
1699 :
1700 2248 : VLIB_NODE_FN (nat_pre_in2out_output_node)
1701 : (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1702 : {
1703 12 : return nat_pre_node_fn_inline (vm, node, frame,
1704 : NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH);
1705 : }
1706 :
1707 49304 : VLIB_REGISTER_NODE (nat_pre_in2out_node) = {
1708 : .name = "nat-pre-in2out",
1709 : .vector_size = sizeof (u32),
1710 : .sibling_of = "nat-default",
1711 : .format_trace = format_nat_pre_trace,
1712 : .type = VLIB_NODE_TYPE_INTERNAL,
1713 : .n_errors = 0,
1714 : };
1715 :
1716 49304 : VLIB_REGISTER_NODE (nat_pre_in2out_output_node) = {
1717 : .name = "nat-pre-in2out-output",
1718 : .vector_size = sizeof (u32),
1719 : .sibling_of = "nat-default",
1720 : .format_trace = format_nat_pre_trace,
1721 : .type = VLIB_NODE_TYPE_INTERNAL,
1722 : .n_errors = 0,
1723 : };
1724 :
1725 : /*
1726 : * fd.io coding-style-patch-verification: ON
1727 : *
1728 : * Local Variables:
1729 : * eval: (c-set-style "gnu")
1730 : * End:
1731 : */
|