FD.io VPP  v18.10-34-gcce845e
Vector Packet Processing
in2out_ed.c
Go to the documentation of this file.
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/pg/pg.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/fib/ip4_fib.h>
26 #include <vppinfra/error.h>
27 #include <nat/nat.h>
28 #include <nat/nat_ipfix_logging.h>
29 #include <nat/nat_reass.h>
30 #include <nat/nat_inlines.h>
31 
32 #define foreach_nat_in2out_ed_error \
33 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
34 _(IN2OUT_PACKETS, "Good in2out packets processed") \
35 _(OUT_OF_PORTS, "Out of ports") \
36 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
37 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
38 _(DROP_FRAGMENT, "Drop fragment") \
39 _(MAX_REASS, "Maximum reassemblies exceeded") \
40 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")\
41 _(NON_SYN, "non-SYN packet try to create session")
42 
43 typedef enum
44 {
45 #define _(sym,str) NAT_IN2OUT_ED_ERROR_##sym,
47 #undef _
50 
51 static char *nat_in2out_ed_error_strings[] = {
52 #define _(sym,string) string,
54 #undef _
55 };
56 
57 typedef enum
58 {
66 
67 typedef struct
68 {
74 
80 
81 static u8 *
82 format_nat_in2out_ed_trace (u8 * s, va_list * args)
83 {
84  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
85  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
86  nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
87  char *tag;
88 
89  tag =
90  t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
91  "NAT44_IN2OUT_ED_FAST_PATH";
92 
93  s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
95 
96  return s;
97 }
98 
101 {
102  icmp46_header_t *icmp0;
103  nat_ed_ses_key_t key0;
104  icmp_echo_header_t *echo0, *inner_echo0 = 0;
105  ip4_header_t *inner_ip0 = 0;
106  void *l4_header = 0;
107  icmp46_header_t *inner_icmp0;
108 
109  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
110  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
111 
112  if (!icmp_is_error_message (icmp0))
113  {
114  key0.proto = IP_PROTOCOL_ICMP;
115  key0.l_addr = ip0->src_address;
116  key0.r_addr = ip0->dst_address;
117  key0.l_port = echo0->identifier;
118  key0.r_port = 0;
119  }
120  else
121  {
122  inner_ip0 = (ip4_header_t *) (echo0 + 1);
123  l4_header = ip4_next_header (inner_ip0);
124  key0.proto = inner_ip0->protocol;
125  key0.r_addr = inner_ip0->src_address;
126  key0.l_addr = inner_ip0->dst_address;
127  switch (ip_proto_to_snat_proto (inner_ip0->protocol))
128  {
129  case SNAT_PROTOCOL_ICMP:
130  inner_icmp0 = (icmp46_header_t *) l4_header;
131  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
132  key0.r_port = 0;
133  key0.l_port = inner_echo0->identifier;
134  break;
135  case SNAT_PROTOCOL_UDP:
136  case SNAT_PROTOCOL_TCP:
137  key0.l_port = ((tcp_udp_header_t *) l4_header)->dst_port;
138  key0.r_port = ((tcp_udp_header_t *) l4_header)->src_port;
139  break;
140  default:
141  return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
142  }
143  }
144  *p_key0 = key0;
145  return 0;
146 }
147 
148 int
150 {
151  snat_main_t *sm = &snat_main;
153  snat_session_t *s;
154  u64 sess_timeout_time;
155  nat_ed_ses_key_t ed_key;
156  clib_bihash_kv_16_8_t ed_kv;
157  int i;
158  snat_address_t *a;
159  snat_session_key_t key;
161  ctx->thread_index);
162 
163  s = pool_elt_at_index (tsm->sessions, kv->value);
164  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
165  if (ctx->now >= sess_timeout_time)
166  {
167  if (is_fwd_bypass_session (s))
168  goto delete;
169 
170  ed_key.l_addr = s->out2in.addr;
171  ed_key.r_addr = s->ext_host_addr;
172  ed_key.fib_index = s->out2in.fib_index;
174  {
175  ed_key.proto = s->in2out.port;
176  ed_key.r_port = 0;
177  ed_key.l_port = 0;
178  }
179  else
180  {
181  ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
182  ed_key.l_port = s->out2in.port;
183  ed_key.r_port = s->ext_host_port;
184  }
185  ed_kv.key[0] = ed_key.as_u64[0];
186  ed_kv.key[1] = ed_key.as_u64[1];
187  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
188  nat_log_warn ("out2in_ed key del failed");
189 
191  goto delete;
192 
193  snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
194  s->out2in.addr.as_u32,
195  s->in2out.protocol,
196  s->in2out.port,
197  s->out2in.port,
198  s->in2out.fib_index);
199 
200  if (is_twice_nat_session (s))
201  {
202  for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
203  {
204  key.protocol = s->in2out.protocol;
205  key.port = s->ext_host_nat_port;
206  a = sm->twice_nat_addresses + i;
207  if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
208  {
210  ctx->thread_index,
211  &key);
212  break;
213  }
214  }
215  }
216 
217  if (snat_is_session_static (s))
218  goto delete;
219 
221  &s->out2in);
222  delete:
223  nat44_delete_session (sm, s, ctx->thread_index);
224  return 1;
225  }
226 
227  return 0;
228 }
229 
230 static inline u32
232  ip4_header_t * ip0, icmp46_header_t * icmp0,
233  u32 sw_if_index0, u32 rx_fib_index0,
234  vlib_node_runtime_t * node, u32 next0, f64 now,
235  u32 thread_index, snat_session_t ** p_s0)
236 {
237  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
238  next0, thread_index, p_s0, 0);
239  snat_session_t *s0 = *p_s0;
240  if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP && s0))
241  {
242  /* Accounting */
245  (sm->vlib_main, b0));
246  /* Per-user LRU list maintenance */
247  nat44_session_update_lru (sm, s0, thread_index);
248  }
249  return next0;
250 }
251 
252 static u32
254  vlib_buffer_t * b,
255  u32 rx_fib_index,
257  snat_session_t ** sessionp,
258  vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now,
259  tcp_header_t * tcp)
260 {
261  snat_session_t *s = 0;
262  snat_user_t *u;
263  snat_session_key_t key0, key1;
264  lb_nat_type_t lb = 0, is_sm = 0;
265  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
266  nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key;
267  u32 proto = ip_proto_to_snat_proto (key->proto);
268  nat_outside_fib_t *outside_fib;
270  u8 identity_nat;
271  fib_prefix_t pfx = {
273  .fp_len = 32,
274  .fp_addr = {
275  .ip4.as_u32 = key->r_addr.as_u32,
276  },
277  };
279 
280  if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
281  {
282  b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
284  nat_log_notice ("maximum sessions exceeded");
286  }
287 
288  key0.addr = key->l_addr;
289  key0.port = key->l_port;
290  key1.protocol = key0.protocol = proto;
291  key0.fib_index = rx_fib_index;
292  key1.fib_index = sm->outside_fib_index;
293  /* First try to match static mapping by local address and port */
295  (sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
296  {
297  /* Try to create dynamic translation */
298  if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index,
299  thread_index, &key1,
300  sm->port_per_thread,
301  tsm->snat_thread_index))
302  {
303  nat_log_notice ("addresses exhausted");
304  b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
306  }
307  }
308  else
309  {
310  if (PREDICT_FALSE (identity_nat))
311  {
312  *sessionp = s;
313  return next;
314  }
315 
316  is_sm = 1;
317  }
318 
319  if (proto == SNAT_PROTOCOL_TCP)
320  {
321  if (!tcp_is_init (tcp))
322  {
323  b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
325  }
326  }
327 
328  u = nat_user_get_or_create (sm, &key->l_addr, rx_fib_index, thread_index);
329  if (!u)
330  {
331  nat_log_warn ("create NAT user failed");
332  if (!is_sm)
334  thread_index, &key1);
336  }
337 
338  s = nat_ed_session_alloc (sm, u, thread_index, now);
339  if (!s)
340  {
341  nat44_delete_user_with_no_session (sm, u, thread_index);
342  nat_log_warn ("create NAT session failed");
343  if (!is_sm)
345  thread_index, &key1);
347  }
348 
349  user_session_increment (sm, u, is_sm);
350  if (is_sm)
352  if (lb)
355  s->ext_host_addr = key->r_addr;
356  s->ext_host_port = key->r_port;
357  s->in2out = key0;
358  s->out2in = key1;
359  s->out2in.protocol = key0.protocol;
360 
361  switch (vec_len (sm->outside_fibs))
362  {
363  case 0:
364  s->out2in.fib_index = sm->outside_fib_index;
365  break;
366  case 1:
367  s->out2in.fib_index = sm->outside_fibs[0].fib_index;
368  break;
369  default:
370  /* *INDENT-OFF* */
371  vec_foreach (outside_fib, sm->outside_fibs)
372  {
373  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
374  if (FIB_NODE_INDEX_INVALID != fei)
375  {
376  if (fib_entry_get_resolving_interface (fei) != ~0)
377  {
378  s->out2in.fib_index = outside_fib->fib_index;
379  break;
380  }
381  }
382  }
383  /* *INDENT-ON* */
384  break;
385  }
386 
387  /* Add to lookup tables */
388  kv->value = s - tsm->sessions;
389  ctx.now = now;
390  ctx.thread_index = thread_index;
391  if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, kv,
393  &ctx))
394  nat_log_notice ("in2out-ed key add failed");
395 
396  make_ed_kv (kv, &key1.addr, &key->r_addr, key->proto, s->out2in.fib_index,
397  key1.port, key->r_port);
398  kv->value = s - tsm->sessions;
399  if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, kv,
401  &ctx))
402  nat_log_notice ("out2in-ed key add failed");
403 
404  *sessionp = s;
405 
406  /* log NAT event */
407  snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
408  s->out2in.addr.as_u32,
409  s->in2out.protocol,
410  s->in2out.port,
411  s->out2in.port, s->in2out.fib_index);
412  return next;
413 }
414 
417  u32 sw_if_index, ip4_header_t * ip, u32 proto,
418  u32 rx_fib_index, u32 thread_index)
419 {
420  udp_header_t *udp = ip4_next_header (ip);
421  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
422  clib_bihash_kv_16_8_t kv, value;
423  snat_session_key_t key0, key1;
424 
425  make_ed_kv (&kv, &ip->dst_address, &ip->src_address, ip->protocol,
426  sm->outside_fib_index, udp->dst_port, udp->src_port);
427 
428  /* NAT packet aimed at external address if */
429  /* has active sessions */
430  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
431  {
432  key0.addr = ip->dst_address;
433  key0.port = udp->dst_port;
434  key0.protocol = proto;
435  key0.fib_index = sm->outside_fib_index;
436  /* or is static mappings */
437  if (!snat_static_mapping_match (sm, key0, &key1, 1, 0, 0, 0, 0, 0))
438  return 0;
439  }
440  else
441  return 0;
442 
443  if (sm->forwarding_enabled)
444  return 1;
445 
446  return snat_not_translate_fast (sm, node, sw_if_index, ip, proto,
447  rx_fib_index);
448 }
449 
452  u32 thread_index, f64 now,
454 {
455  nat_ed_ses_key_t key;
456  clib_bihash_kv_16_8_t kv, value;
457  udp_header_t *udp;
458  snat_session_t *s = 0;
459  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
460 
461  if (!sm->forwarding_enabled)
462  return 0;
463 
464  if (ip->protocol == IP_PROTOCOL_ICMP)
465  {
466  key.as_u64[0] = key.as_u64[1] = 0;
467  if (icmp_get_ed_key (ip, &key))
468  return 0;
469  key.fib_index = 0;
470  kv.key[0] = key.as_u64[0];
471  kv.key[1] = key.as_u64[1];
472  }
473  else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
474  {
475  udp = ip4_next_header (ip);
476  make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0,
477  udp->src_port, udp->dst_port);
478  }
479  else
480  {
481  make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
482  0);
483  }
484 
485  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
486  {
487  s = pool_elt_at_index (tsm->sessions, value.value);
488  if (is_fwd_bypass_session (s))
489  {
490  if (ip->protocol == IP_PROTOCOL_TCP)
491  {
492  tcp_header_t *tcp = ip4_next_header (ip);
493  if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
494  return 1;
495  }
496  /* Accounting */
499  /* Per-user LRU list maintenance */
500  nat44_session_update_lru (sm, s, thread_index);
501  return 1;
502  }
503  else
504  return 0;
505  }
506 
507  return 0;
508 }
509 
512  u8 proto, u16 src_port, u16 dst_port,
513  u32 thread_index, u32 rx_sw_if_index,
514  u32 tx_sw_if_index)
515 {
516  clib_bihash_kv_16_8_t kv, value;
517  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
519  snat_session_t *s;
520  u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
521  u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
522 
523  /* src NAT check */
524  make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, tx_fib_index,
525  src_port, dst_port);
526  if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
527  {
528  s = pool_elt_at_index (tsm->sessions, value.value);
529  if (nat44_is_ses_closed (s))
530  {
531  nat_log_debug ("TCP close connection %U", format_snat_session,
532  &sm->per_thread_data[thread_index], s);
533  nat_free_session_data (sm, s, thread_index);
534  nat44_delete_session (sm, s, thread_index);
535  }
536  else
538  return 1;
539  }
540 
541  /* dst NAT check */
542  make_ed_kv (&kv, &ip->dst_address, &ip->src_address, proto, rx_fib_index,
543  dst_port, src_port);
544  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
545  {
546  s = pool_elt_at_index (tsm->sessions, value.value);
547  if (is_fwd_bypass_session (s))
548  return 0;
549 
550  /* hairpinning */
551  /* *INDENT-OFF* */
553  ({
554  if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
555  return 0;
556  }));
557  /* *INDENT-ON* */
558  return 1;
559  }
560 
561  return 0;
562 }
563 
564 u32
566  u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
567  u8 * p_proto, snat_session_key_t * p_value,
568  u8 * p_dont_translate, void *d, void *e)
569 {
570  icmp46_header_t *icmp;
572  u32 rx_fib_index;
573  nat_ed_ses_key_t key;
574  snat_session_t *s = 0;
575  u8 dont_translate = 0;
576  clib_bihash_kv_16_8_t kv, value;
577  u32 next = ~0;
578  int err;
579  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
580 
581  icmp = (icmp46_header_t *) ip4_next_header (ip);
582  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
583  rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
584 
585  key.as_u64[0] = key.as_u64[1] = 0;
586  err = icmp_get_ed_key (ip, &key);
587  if (err != 0)
588  {
589  b->error = node->errors[err];
591  goto out;
592  }
593  key.fib_index = rx_fib_index;
594 
595  kv.key[0] = key.as_u64[0];
596  kv.key[1] = key.as_u64[1];
597 
598  if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
599  {
600  if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0)
601  {
603  key.proto,
604  key.
605  l_port,
606  key.
607  r_port,
608  thread_index,
609  sw_if_index,
611  (b)->
612  sw_if_index
613  [VLIB_TX])))
614  {
615  dont_translate = 1;
616  goto out;
617  }
618  }
619  else
620  {
621  if (PREDICT_FALSE (nat44_ed_not_translate (sm, node, sw_if_index,
622  ip, SNAT_PROTOCOL_ICMP,
623  rx_fib_index,
624  thread_index)))
625  {
626  dont_translate = 1;
627  goto out;
628  }
629  }
630 
632  {
633  b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
635  goto out;
636  }
637 
638  next = slow_path_ed (sm, b, rx_fib_index, &kv, &s, node, next,
639  thread_index, vlib_time_now (sm->vlib_main), 0);
640 
642  goto out;
643 
644  if (!s)
645  {
646  dont_translate = 1;
647  goto out;
648  }
649  }
650  else
651  {
652  if (PREDICT_FALSE (icmp->type != ICMP4_echo_request &&
653  icmp->type != ICMP4_echo_reply &&
654  !icmp_is_error_message (icmp)))
655  {
656  b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
658  goto out;
659  }
660 
661  s = pool_elt_at_index (tsm->sessions, value.value);
662  }
663 
664  *p_proto = ip_proto_to_snat_proto (key.proto);
665 out:
666  if (s)
667  *p_value = s->out2in;
668  *p_dont_translate = dont_translate;
669  if (d)
670  *(snat_session_t **) d = s;
671  return next;
672 }
673 
674 static snat_session_t *
676  vlib_buffer_t * b,
677  ip4_header_t * ip,
678  u32 rx_fib_index,
679  u32 thread_index,
680  f64 now,
682 {
683  clib_bihash_kv_8_8_t kv, value;
684  clib_bihash_kv_16_8_t s_kv, s_value;
686  u32 old_addr, new_addr = 0;
687  ip_csum_t sum;
688  snat_user_t *u;
689  dlist_elt_t *head, *elt;
690  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
691  u32 elt_index, head_index, ses_index;
692  snat_session_t *s;
693  u32 outside_fib_index = sm->outside_fib_index;
694  int i;
695  u8 is_sm = 0;
696  nat_outside_fib_t *outside_fib;
698  fib_prefix_t pfx = {
700  .fp_len = 32,
701  .fp_addr = {
702  .ip4.as_u32 = ip->dst_address.as_u32,
703  },
704  };
705 
706  switch (vec_len (sm->outside_fibs))
707  {
708  case 0:
709  outside_fib_index = sm->outside_fib_index;
710  break;
711  case 1:
712  outside_fib_index = sm->outside_fibs[0].fib_index;
713  break;
714  default:
715  /* *INDENT-OFF* */
716  vec_foreach (outside_fib, sm->outside_fibs)
717  {
718  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
719  if (FIB_NODE_INDEX_INVALID != fei)
720  {
721  if (fib_entry_get_resolving_interface (fei) != ~0)
722  {
723  outside_fib_index = outside_fib->fib_index;
724  break;
725  }
726  }
727  }
728  /* *INDENT-ON* */
729  break;
730  }
731  old_addr = ip->src_address.as_u32;
732 
733  make_ed_kv (&s_kv, &ip->src_address, &ip->dst_address, ip->protocol,
734  rx_fib_index, 0, 0);
735 
736  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
737  {
738  s = pool_elt_at_index (tsm->sessions, s_value.value);
739  new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
740  }
741  else
742  {
743  if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
744  {
745  b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
747  nat_log_notice ("maximum sessions exceeded");
748  return 0;
749  }
750 
751  u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
752  thread_index);
753  if (!u)
754  {
755  nat_log_warn ("create NAT user failed");
756  return 0;
757  }
758 
759  make_sm_kv (&kv, &ip->src_address, 0, rx_fib_index, 0);
760 
761  /* Try to find static mapping first */
762  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
763  {
764  m = pool_elt_at_index (sm->static_mappings, value.value);
765  new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
766  is_sm = 1;
767  goto create_ses;
768  }
769  /* Fallback to 3-tuple key */
770  else
771  {
772  /* Choose same out address as for TCP/UDP session to same destination */
773  head_index = u->sessions_per_user_list_head_index;
774  head = pool_elt_at_index (tsm->list_pool, head_index);
775  elt_index = head->next;
776  if (PREDICT_FALSE (elt_index == ~0))
777  ses_index = ~0;
778  else
779  {
780  elt = pool_elt_at_index (tsm->list_pool, elt_index);
781  ses_index = elt->value;
782  }
783 
784  while (ses_index != ~0)
785  {
786  s = pool_elt_at_index (tsm->sessions, ses_index);
787  elt_index = elt->next;
788  elt = pool_elt_at_index (tsm->list_pool, elt_index);
789  ses_index = elt->value;
790 
791  if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
792  {
793  new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
794 
795  make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address,
796  ip->protocol, outside_fib_index, 0, 0);
797  if (clib_bihash_search_16_8
798  (&tsm->out2in_ed, &s_kv, &s_value))
799  goto create_ses;
800 
801  break;
802  }
803  }
804 
805  for (i = 0; i < vec_len (sm->addresses); i++)
806  {
807  make_ed_kv (&s_kv, &sm->addresses[i].addr, &ip->dst_address,
808  ip->protocol, outside_fib_index, 0, 0);
809  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
810  {
811  new_addr = ip->src_address.as_u32 =
812  sm->addresses[i].addr.as_u32;
813  goto create_ses;
814  }
815  }
816  return 0;
817  }
818 
819  create_ses:
820  s = nat_ed_session_alloc (sm, u, thread_index, now);
821  if (!s)
822  {
823  nat44_delete_user_with_no_session (sm, u, thread_index);
824  nat_log_warn ("create NAT session failed");
825  return 0;
826  }
827 
828  s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
831  s->out2in.addr.as_u32 = new_addr;
832  s->out2in.fib_index = outside_fib_index;
833  s->in2out.addr.as_u32 = old_addr;
834  s->in2out.fib_index = rx_fib_index;
835  s->in2out.port = s->out2in.port = ip->protocol;
836  if (is_sm)
838  user_session_increment (sm, u, is_sm);
839 
840  /* Add to lookup tables */
841  make_ed_kv (&s_kv, &s->in2out.addr, &ip->dst_address, ip->protocol,
842  rx_fib_index, 0, 0);
843  s_kv.value = s - tsm->sessions;
844  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
845  nat_log_notice ("in2out key add failed");
846 
847  make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address, ip->protocol,
848  outside_fib_index, 0, 0);
849  s_kv.value = s - tsm->sessions;
850  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
851  nat_log_notice ("out2in key add failed");
852  }
853 
854  /* Update IP checksum */
855  sum = ip->checksum;
856  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
857  ip->checksum = ip_csum_fold (sum);
858 
859  /* Accounting */
861  /* Per-user LRU list maintenance */
862  nat44_session_update_lru (sm, s, thread_index);
863 
864  /* Hairpinning */
865  if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
867 
868  if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
869  vnet_buffer (b)->sw_if_index[VLIB_TX] = outside_fib_index;
870 
871  return s;
872 }
873 
874 static inline uword
876  vlib_node_runtime_t * node,
877  vlib_frame_t * frame, int is_slow_path,
878  int is_output_feature)
879 {
880  u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
881  nat_in2out_ed_next_t next_index;
882  snat_main_t *sm = &snat_main;
883  f64 now = vlib_time_now (vm);
884  u32 thread_index = vm->thread_index;
885  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
886 
887  stats_node_index = is_slow_path ? nat44_ed_in2out_slowpath_node.index :
888  nat44_ed_in2out_node.index;
889 
890  from = vlib_frame_vector_args (frame);
891  n_left_from = frame->n_vectors;
892  next_index = node->cached_next_index;
893 
894  while (n_left_from > 0)
895  {
896  u32 n_left_to_next;
897 
898  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
899 
900  while (n_left_from >= 4 && n_left_to_next >= 2)
901  {
902  u32 bi0, bi1;
903  vlib_buffer_t *b0, *b1;
904  u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
905  new_addr0, old_addr0;
906  u32 next1, sw_if_index1, rx_fib_index1, iph_offset1 = 0, proto1,
907  new_addr1, old_addr1;
908  u16 old_port0, new_port0, old_port1, new_port1;
909  ip4_header_t *ip0, *ip1;
910  udp_header_t *udp0, *udp1;
911  tcp_header_t *tcp0, *tcp1;
912  icmp46_header_t *icmp0, *icmp1;
913  snat_session_t *s0 = 0, *s1 = 0;
914  clib_bihash_kv_16_8_t kv0, value0, kv1, value1;
915  ip_csum_t sum0, sum1;
916 
917  /* Prefetch next iteration. */
918  {
919  vlib_buffer_t *p2, *p3;
920 
921  p2 = vlib_get_buffer (vm, from[2]);
922  p3 = vlib_get_buffer (vm, from[3]);
923 
924  vlib_prefetch_buffer_header (p2, LOAD);
925  vlib_prefetch_buffer_header (p3, LOAD);
926 
929  }
930 
931  /* speculatively enqueue b0 and b1 to the current next frame */
932  to_next[0] = bi0 = from[0];
933  to_next[1] = bi1 = from[1];
934  from += 2;
935  to_next += 2;
936  n_left_from -= 2;
937  n_left_to_next -= 2;
938 
939  b0 = vlib_get_buffer (vm, bi0);
940  b1 = vlib_get_buffer (vm, bi1);
941 
943 
944  if (is_output_feature)
945  iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
946 
947  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
948  iph_offset0);
949 
950  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
951  rx_fib_index0 =
953  sw_if_index0);
954 
955  if (PREDICT_FALSE (ip0->ttl == 1))
956  {
957  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
958  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
959  ICMP4_time_exceeded_ttl_exceeded_in_transit,
960  0);
962  goto trace00;
963  }
964 
965  udp0 = ip4_next_header (ip0);
966  tcp0 = (tcp_header_t *) udp0;
967  icmp0 = (icmp46_header_t *) udp0;
968  proto0 = ip_proto_to_snat_proto (ip0->protocol);
969 
970  if (is_slow_path)
971  {
972  if (PREDICT_FALSE (proto0 == ~0))
973  {
974  s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
975  rx_fib_index0,
976  thread_index, now, vm,
977  node);
978  if (!s0)
979  next0 = NAT_IN2OUT_ED_NEXT_DROP;
980  goto trace00;
981  }
982 
983  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
984  {
986  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
987  next0, now, thread_index, &s0);
988  goto trace00;
989  }
990  }
991  else
992  {
993  if (PREDICT_FALSE (proto0 == ~0))
994  {
996  goto trace00;
997  }
998 
999  if (ip4_is_fragment (ip0))
1000  {
1001  next0 = NAT_IN2OUT_ED_NEXT_REASS;
1002  goto trace00;
1003  }
1004 
1005  if (is_output_feature)
1006  {
1007  if (PREDICT_FALSE
1009  (sm, ip0, thread_index, now, vm, b0)))
1010  goto trace00;
1011  }
1012 
1013  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1014  {
1016  goto trace00;
1017  }
1018  }
1019 
1020  make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1021  ip0->protocol, rx_fib_index0, udp0->src_port,
1022  udp0->dst_port);
1023 
1024  if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1025  {
1026  if (is_slow_path)
1027  {
1028  if (is_output_feature)
1029  {
1030  if (PREDICT_FALSE
1032  (sm, ip0, ip0->protocol, udp0->src_port,
1033  udp0->dst_port, thread_index, sw_if_index0,
1034  vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1035  goto trace00;
1036  }
1037  else
1038  {
1039  if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1040  sw_if_index0,
1041  ip0, proto0,
1042  rx_fib_index0,
1043  thread_index)))
1044  goto trace00;
1045  }
1046 
1047  next0 =
1048  slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1049  next0, thread_index, now, tcp0);
1050 
1051  if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1052  goto trace00;
1053 
1054  if (PREDICT_FALSE (!s0))
1055  goto trace00;
1056  }
1057  else
1058  {
1060  goto trace00;
1061  }
1062  }
1063  else
1064  {
1065  s0 = pool_elt_at_index (tsm->sessions, value0.value);
1066  }
1067 
1068  b0->flags |= VNET_BUFFER_F_IS_NATED;
1069 
1070  if (!is_output_feature)
1071  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1072 
1073  old_addr0 = ip0->src_address.as_u32;
1074  new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1075  sum0 = ip0->checksum;
1076  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1077  src_address);
1079  sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1080  s0->ext_host_addr.as_u32, ip4_header_t,
1081  dst_address);
1082  ip0->checksum = ip_csum_fold (sum0);
1083 
1084  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1085  {
1086  old_port0 = tcp0->src_port;
1087  new_port0 = tcp0->src_port = s0->out2in.port;
1088 
1089  sum0 = tcp0->checksum;
1090  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1091  dst_address);
1092  sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1093  length);
1095  {
1096  sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1097  s0->ext_host_addr.as_u32,
1098  ip4_header_t, dst_address);
1099  sum0 = ip_csum_update (sum0, tcp0->dst_port,
1100  s0->ext_host_port, ip4_header_t,
1101  length);
1102  tcp0->dst_port = s0->ext_host_port;
1103  ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1104  }
1105  mss_clamping (sm, tcp0, &sum0);
1106  tcp0->checksum = ip_csum_fold (sum0);
1108  (sm, s0, tcp0, thread_index))
1109  goto trace00;
1110  }
1111  else
1112  {
1113  udp0->src_port = s0->out2in.port;
1114  udp0->checksum = 0;
1116  {
1117  udp0->dst_port = s0->ext_host_port;
1118  ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1119  }
1120  }
1121 
1122  /* Accounting */
1125  b0));
1126  /* Per-user LRU list maintenance */
1127  nat44_session_update_lru (sm, s0, thread_index);
1128 
1129  trace00:
1131  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1132  {
1134  vlib_add_trace (vm, node, b0, sizeof (*t));
1135  t->is_slow_path = is_slow_path;
1136  t->sw_if_index = sw_if_index0;
1137  t->next_index = next0;
1138  t->session_index = ~0;
1139  if (s0)
1140  t->session_index = s0 - tsm->sessions;
1141  }
1142 
1143  pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
1144 
1145 
1146  next1 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1147 
1148  if (is_output_feature)
1149  iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1150 
1151  ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1152  iph_offset1);
1153 
1154  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1155  rx_fib_index1 =
1157  sw_if_index1);
1158 
1159  if (PREDICT_FALSE (ip1->ttl == 1))
1160  {
1161  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1162  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1163  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1164  0);
1166  goto trace01;
1167  }
1168 
1169  udp1 = ip4_next_header (ip1);
1170  tcp1 = (tcp_header_t *) udp1;
1171  icmp1 = (icmp46_header_t *) udp1;
1172  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1173 
1174  if (is_slow_path)
1175  {
1176  if (PREDICT_FALSE (proto1 == ~0))
1177  {
1178  s1 = nat44_ed_in2out_unknown_proto (sm, b1, ip1,
1179  rx_fib_index1,
1180  thread_index, now, vm,
1181  node);
1182  if (!s1)
1183  next1 = NAT_IN2OUT_ED_NEXT_DROP;
1184  goto trace01;
1185  }
1186 
1187  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1188  {
1189  next1 = icmp_in2out_ed_slow_path
1190  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1191  next1, now, thread_index, &s1);
1192  goto trace01;
1193  }
1194  }
1195  else
1196  {
1197  if (PREDICT_FALSE (proto1 == ~0))
1198  {
1200  goto trace01;
1201  }
1202 
1203  if (ip4_is_fragment (ip1))
1204  {
1205  next1 = NAT_IN2OUT_ED_NEXT_REASS;
1206  goto trace01;
1207  }
1208 
1209  if (is_output_feature)
1210  {
1211  if (PREDICT_FALSE
1213  (sm, ip1, thread_index, now, vm, b1)))
1214  goto trace01;
1215  }
1216 
1217  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1218  {
1220  goto trace01;
1221  }
1222  }
1223 
1224  make_ed_kv (&kv1, &ip1->src_address, &ip1->dst_address,
1225  ip1->protocol, rx_fib_index1, udp1->src_port,
1226  udp1->dst_port);
1227 
1228  if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv1, &value1))
1229  {
1230  if (is_slow_path)
1231  {
1232  if (is_output_feature)
1233  {
1234  if (PREDICT_FALSE
1236  (sm, ip1, ip1->protocol, udp1->src_port,
1237  udp1->dst_port, thread_index, sw_if_index1,
1238  vnet_buffer (b1)->sw_if_index[VLIB_TX])))
1239  goto trace01;
1240  }
1241  else
1242  {
1243  if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1244  sw_if_index1,
1245  ip1, proto1,
1246  rx_fib_index1,
1247  thread_index)))
1248  goto trace01;
1249  }
1250 
1251  next1 =
1252  slow_path_ed (sm, b1, rx_fib_index1, &kv1, &s1, node,
1253  next1, thread_index, now, tcp1);
1254 
1255  if (PREDICT_FALSE (next1 == NAT_IN2OUT_ED_NEXT_DROP))
1256  goto trace01;
1257 
1258  if (PREDICT_FALSE (!s1))
1259  goto trace01;
1260  }
1261  else
1262  {
1264  goto trace01;
1265  }
1266  }
1267  else
1268  {
1269  s1 = pool_elt_at_index (tsm->sessions, value1.value);
1270  }
1271 
1272  b1->flags |= VNET_BUFFER_F_IS_NATED;
1273 
1274  if (!is_output_feature)
1275  vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1276 
1277  old_addr1 = ip1->src_address.as_u32;
1278  new_addr1 = ip1->src_address.as_u32 = s1->out2in.addr.as_u32;
1279  sum1 = ip1->checksum;
1280  sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1281  src_address);
1283  sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1284  s1->ext_host_addr.as_u32, ip4_header_t,
1285  dst_address);
1286  ip1->checksum = ip_csum_fold (sum1);
1287 
1288  if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1289  {
1290  old_port1 = tcp1->src_port;
1291  new_port1 = tcp1->src_port = s1->out2in.port;
1292 
1293  sum1 = tcp1->checksum;
1294  sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1295  dst_address);
1296  sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
1297  length);
1299  {
1300  sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1301  s1->ext_host_addr.as_u32,
1302  ip4_header_t, dst_address);
1303  sum1 = ip_csum_update (sum1, tcp1->dst_port,
1304  s1->ext_host_port, ip4_header_t,
1305  length);
1306  tcp1->dst_port = s1->ext_host_port;
1307  ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1308  }
1309  tcp1->checksum = ip_csum_fold (sum1);
1310  mss_clamping (sm, tcp1, &sum1);
1312  (sm, s1, tcp1, thread_index))
1313  goto trace01;
1314  }
1315  else
1316  {
1317  udp1->src_port = s1->out2in.port;
1318  udp1->checksum = 0;
1320  {
1321  udp1->dst_port = s1->ext_host_port;
1322  ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1323  }
1324  }
1325 
1326  /* Accounting */
1329  b1));
1330  /* Per-user LRU list maintenance */
1331  nat44_session_update_lru (sm, s1, thread_index);
1332 
1333  trace01:
1335  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1336  {
1338  vlib_add_trace (vm, node, b1, sizeof (*t));
1339  t->is_slow_path = is_slow_path;
1340  t->sw_if_index = sw_if_index1;
1341  t->next_index = next1;
1342  t->session_index = ~0;
1343  if (s1)
1344  t->session_index = s1 - tsm->sessions;
1345  }
1346 
1347  pkts_processed += next1 != NAT_IN2OUT_ED_NEXT_DROP;
1348 
1349  /* verify speculative enqueues, maybe switch current next frame */
1350  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1351  to_next, n_left_to_next,
1352  bi0, bi1, next0, next1);
1353  }
1354 
1355  while (n_left_from > 0 && n_left_to_next > 0)
1356  {
1357  u32 bi0;
1358  vlib_buffer_t *b0;
1359  u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
1360  new_addr0, old_addr0;
1361  u16 old_port0, new_port0;
1362  ip4_header_t *ip0;
1363  udp_header_t *udp0;
1364  tcp_header_t *tcp0;
1365  icmp46_header_t *icmp0;
1366  snat_session_t *s0 = 0;
1367  clib_bihash_kv_16_8_t kv0, value0;
1368  ip_csum_t sum0;
1369 
1370  /* speculatively enqueue b0 to the current next frame */
1371  bi0 = from[0];
1372  to_next[0] = bi0;
1373  from += 1;
1374  to_next += 1;
1375  n_left_from -= 1;
1376  n_left_to_next -= 1;
1377 
1378  b0 = vlib_get_buffer (vm, bi0);
1379  next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1380 
1381  if (is_output_feature)
1382  iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1383 
1384  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1385  iph_offset0);
1386 
1387  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1388  rx_fib_index0 =
1390  sw_if_index0);
1391 
1392  if (PREDICT_FALSE (ip0->ttl == 1))
1393  {
1394  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1395  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1396  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1397  0);
1399  goto trace0;
1400  }
1401 
1402  udp0 = ip4_next_header (ip0);
1403  tcp0 = (tcp_header_t *) udp0;
1404  icmp0 = (icmp46_header_t *) udp0;
1405  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1406 
1407  if (is_slow_path)
1408  {
1409  if (PREDICT_FALSE (proto0 == ~0))
1410  {
1411  s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1412  rx_fib_index0,
1413  thread_index, now, vm,
1414  node);
1415  if (!s0)
1416  next0 = NAT_IN2OUT_ED_NEXT_DROP;
1417  goto trace0;
1418  }
1419 
1420  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1421  {
1422  next0 = icmp_in2out_ed_slow_path
1423  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1424  next0, now, thread_index, &s0);
1425  goto trace0;
1426  }
1427  }
1428  else
1429  {
1430  if (PREDICT_FALSE (proto0 == ~0))
1431  {
1433  goto trace0;
1434  }
1435 
1436  if (ip4_is_fragment (ip0))
1437  {
1438  next0 = NAT_IN2OUT_ED_NEXT_REASS;
1439  goto trace0;
1440  }
1441 
1442  if (is_output_feature)
1443  {
1444  if (PREDICT_FALSE
1446  (sm, ip0, thread_index, now, vm, b0)))
1447  goto trace0;
1448  }
1449 
1450  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1451  {
1453  goto trace0;
1454  }
1455  }
1456 
1457  make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1458  ip0->protocol, rx_fib_index0, udp0->src_port,
1459  udp0->dst_port);
1460 
1461  if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1462  {
1463  if (is_slow_path)
1464  {
1465  if (is_output_feature)
1466  {
1467  if (PREDICT_FALSE
1469  (sm, ip0, ip0->protocol, udp0->src_port,
1470  udp0->dst_port, thread_index, sw_if_index0,
1471  vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1472  goto trace0;
1473  }
1474  else
1475  {
1476  if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1477  sw_if_index0,
1478  ip0, proto0,
1479  rx_fib_index0,
1480  thread_index)))
1481  goto trace0;
1482  }
1483 
1484  next0 =
1485  slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1486  next0, thread_index, now, tcp0);
1487 
1488  if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1489  goto trace0;
1490 
1491  if (PREDICT_FALSE (!s0))
1492  goto trace0;
1493  }
1494  else
1495  {
1497  goto trace0;
1498  }
1499  }
1500  else
1501  {
1502  s0 = pool_elt_at_index (tsm->sessions, value0.value);
1503  }
1504 
1505  b0->flags |= VNET_BUFFER_F_IS_NATED;
1506 
1507  if (!is_output_feature)
1508  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1509 
1510  old_addr0 = ip0->src_address.as_u32;
1511  new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1512  sum0 = ip0->checksum;
1513  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1514  src_address);
1516  sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1517  s0->ext_host_addr.as_u32, ip4_header_t,
1518  dst_address);
1519  ip0->checksum = ip_csum_fold (sum0);
1520 
1521  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1522  {
1523  old_port0 = tcp0->src_port;
1524  new_port0 = tcp0->src_port = s0->out2in.port;
1525 
1526  sum0 = tcp0->checksum;
1527  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1528  dst_address);
1529  sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1530  length);
1532  {
1533  sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1534  s0->ext_host_addr.as_u32,
1535  ip4_header_t, dst_address);
1536  sum0 = ip_csum_update (sum0, tcp0->dst_port,
1537  s0->ext_host_port, ip4_header_t,
1538  length);
1539  tcp0->dst_port = s0->ext_host_port;
1540  ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1541  }
1542  mss_clamping (sm, tcp0, &sum0);
1543  tcp0->checksum = ip_csum_fold (sum0);
1545  (sm, s0, tcp0, thread_index))
1546  goto trace0;
1547  }
1548  else
1549  {
1550  udp0->src_port = s0->out2in.port;
1551  udp0->checksum = 0;
1553  {
1554  udp0->dst_port = s0->ext_host_port;
1555  ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1556  }
1557  }
1558 
1559  /* Accounting */
1562  b0));
1563  /* Per-user LRU list maintenance */
1564  nat44_session_update_lru (sm, s0, thread_index);
1565 
1566  trace0:
1568  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1569  {
1571  vlib_add_trace (vm, node, b0, sizeof (*t));
1572  t->is_slow_path = is_slow_path;
1573  t->sw_if_index = sw_if_index0;
1574  t->next_index = next0;
1575  t->session_index = ~0;
1576  if (s0)
1577  t->session_index = s0 - tsm->sessions;
1578  }
1579 
1580  pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
1581 
1582  /* verify speculative enqueue, maybe switch current next frame */
1583  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1584  to_next, n_left_to_next,
1585  bi0, next0);
1586  }
1587 
1588  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1589  }
1590 
1591  vlib_node_increment_counter (vm, stats_node_index,
1592  NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1593  pkts_processed);
1594  return frame->n_vectors;
1595 }
1596 
1597 static uword
1599  vlib_node_runtime_t * node,
1600  vlib_frame_t * frame)
1601 {
1602  return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 0);
1603 }
1604 
1605 /* *INDENT-OFF* */
1607  .function = nat44_ed_in2out_fast_path_fn,
1608  .name = "nat44-ed-in2out",
1609  .vector_size = sizeof (u32),
1610  .format_trace = format_nat_in2out_ed_trace,
1611  .type = VLIB_NODE_TYPE_INTERNAL,
1612  .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1613  .error_strings = nat_in2out_ed_error_strings,
1614  .runtime_data_bytes = sizeof (snat_runtime_t),
1615  .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1616  .next_nodes = {
1617  [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1618  [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1619  [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1620  [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1621  [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1622  },
1623 };
1624 /* *INDENT-ON* */
1625 
1628 
1629 static uword
1631  vlib_node_runtime_t * node,
1632  vlib_frame_t * frame)
1633 {
1634  return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 1);
1635 }
1636 
1637 /* *INDENT-OFF* */
1640  .name = "nat44-ed-in2out-output",
1641  .vector_size = sizeof (u32),
1642  .format_trace = format_nat_in2out_ed_trace,
1643  .type = VLIB_NODE_TYPE_INTERNAL,
1644  .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1645  .error_strings = nat_in2out_ed_error_strings,
1646  .runtime_data_bytes = sizeof (snat_runtime_t),
1647  .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1648  .next_nodes = {
1649  [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1650  [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1651  [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1652  [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1653  [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass-output",
1654  },
1655 };
1656 /* *INDENT-ON* */
1657 
1660 
1661 static uword
1663  vlib_node_runtime_t * node,
1664  vlib_frame_t * frame)
1665 {
1666  return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 0);
1667 }
1668 
1669 /* *INDENT-OFF* */
1671  .function = nat44_ed_in2out_slow_path_fn,
1672  .name = "nat44-ed-in2out-slowpath",
1673  .vector_size = sizeof (u32),
1674  .format_trace = format_nat_in2out_ed_trace,
1675  .type = VLIB_NODE_TYPE_INTERNAL,
1676  .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1677  .error_strings = nat_in2out_ed_error_strings,
1678  .runtime_data_bytes = sizeof (snat_runtime_t),
1679  .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1680  .next_nodes = {
1681  [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1682  [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1683  [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1684  [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1685  [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1686  },
1687 };
1688 /* *INDENT-ON* */
1689 
1692 
1693 static uword
1695  vlib_node_runtime_t * node,
1696  vlib_frame_t * frame)
1697 {
1698  return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 1);
1699 }
1700 
1701 /* *INDENT-OFF* */
1704  .name = "nat44-ed-in2out-output-slowpath",
1705  .vector_size = sizeof (u32),
1706  .format_trace = format_nat_in2out_ed_trace,
1707  .type = VLIB_NODE_TYPE_INTERNAL,
1708  .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1709  .error_strings = nat_in2out_ed_error_strings,
1710  .runtime_data_bytes = sizeof (snat_runtime_t),
1711  .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1712  .next_nodes = {
1713  [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1714  [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1715  [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1716  [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1717  [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1718  },
1719 };
1720 /* *INDENT-ON* */
1721 
1724 
1725 static inline uword
1727  vlib_node_runtime_t * node,
1728  vlib_frame_t * frame,
1729  int is_output_feature)
1730 {
1731  u32 n_left_from, *from, *to_next;
1732  nat_in2out_ed_next_t next_index;
1733  u32 pkts_processed = 0;
1734  snat_main_t *sm = &snat_main;
1735  f64 now = vlib_time_now (vm);
1736  u32 thread_index = vm->thread_index;
1737  snat_main_per_thread_data_t *per_thread_data =
1738  &sm->per_thread_data[thread_index];
1739  u32 *fragments_to_drop = 0;
1740  u32 *fragments_to_loopback = 0;
1741 
1742  from = vlib_frame_vector_args (frame);
1743  n_left_from = frame->n_vectors;
1744  next_index = node->cached_next_index;
1745 
1746  while (n_left_from > 0)
1747  {
1748  u32 n_left_to_next;
1749 
1750  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1751 
1752  while (n_left_from > 0 && n_left_to_next > 0)
1753  {
1754  u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1755  u32 iph_offset0 = 0;
1756  vlib_buffer_t *b0;
1757  u32 next0;
1758  u8 cached0 = 0;
1759  ip4_header_t *ip0 = 0;
1760  nat_reass_ip4_t *reass0;
1761  udp_header_t *udp0;
1762  tcp_header_t *tcp0;
1763  icmp46_header_t *icmp0;
1764  clib_bihash_kv_16_8_t kv0, value0;
1765  snat_session_t *s0 = 0;
1766  u16 old_port0, new_port0;
1767  ip_csum_t sum0;
1768 
1769  /* speculatively enqueue b0 to the current next frame */
1770  bi0 = from[0];
1771  to_next[0] = bi0;
1772  from += 1;
1773  to_next += 1;
1774  n_left_from -= 1;
1775  n_left_to_next -= 1;
1776 
1777  b0 = vlib_get_buffer (vm, bi0);
1778 
1779  next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1780 
1781  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1782  rx_fib_index0 =
1784  sw_if_index0);
1785 
1787  {
1788  next0 = NAT_IN2OUT_ED_NEXT_DROP;
1789  b0->error = node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT];
1790  goto trace0;
1791  }
1792 
1793  if (is_output_feature)
1794  iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1795 
1796  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1797  iph_offset0);
1798 
1799  udp0 = ip4_next_header (ip0);
1800  tcp0 = (tcp_header_t *) udp0;
1801  icmp0 = (icmp46_header_t *) udp0;
1802  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1803 
1805  ip0->dst_address,
1806  ip0->fragment_id,
1807  ip0->protocol,
1808  1, &fragments_to_drop);
1809 
1810  if (PREDICT_FALSE (!reass0))
1811  {
1812  next0 = NAT_IN2OUT_ED_NEXT_DROP;
1813  b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_REASS];
1814  nat_log_notice ("maximum reassemblies exceeded");
1815  goto trace0;
1816  }
1817 
1819  {
1820  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1821  {
1822  if (is_output_feature)
1823  {
1824  if (PREDICT_FALSE
1826  (sm, ip0, thread_index, now, vm, b0)))
1827  reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1828  goto trace0;
1829  }
1830 
1831  next0 = icmp_in2out_ed_slow_path
1832  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1833  next0, now, thread_index, &s0);
1834 
1835  if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP))
1836  {
1837  if (s0)
1838  reass0->sess_index = s0 - per_thread_data->sessions;
1839  else
1840  reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1841  nat_ip4_reass_get_frags (reass0,
1842  &fragments_to_loopback);
1843  }
1844 
1845  goto trace0;
1846  }
1847 
1848  make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1849  ip0->protocol, rx_fib_index0, udp0->src_port,
1850  udp0->dst_port);
1851 
1852  if (clib_bihash_search_16_8
1853  (&per_thread_data->in2out_ed, &kv0, &value0))
1854  {
1855  if (is_output_feature)
1856  {
1857  if (PREDICT_FALSE
1859  (sm, ip0, ip0->protocol, udp0->src_port,
1860  udp0->dst_port, thread_index, sw_if_index0,
1861  vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1862  {
1863  reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1864  nat_ip4_reass_get_frags (reass0,
1865  &fragments_to_loopback);
1866  goto trace0;
1867  }
1868  }
1869  else
1870  {
1871  if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1872  sw_if_index0,
1873  ip0, proto0,
1874  rx_fib_index0,
1875  thread_index)))
1876  {
1877  reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1878  nat_ip4_reass_get_frags (reass0,
1879  &fragments_to_loopback);
1880  goto trace0;
1881  }
1882  }
1883 
1884  next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0,
1885  &s0, node, next0, thread_index, now,
1886  tcp0);
1887 
1888  if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1889  goto trace0;
1890 
1891  if (PREDICT_FALSE (!s0))
1892  {
1893  reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1894  goto trace0;
1895  }
1896 
1897  reass0->sess_index = s0 - per_thread_data->sessions;
1898  }
1899  else
1900  {
1901  s0 = pool_elt_at_index (per_thread_data->sessions,
1902  value0.value);
1903  reass0->sess_index = value0.value;
1904  }
1905  nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1906  }
1907  else
1908  {
1909  if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1910  goto trace0;
1911  if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1912  {
1914  (reass0, bi0, &fragments_to_drop))
1915  {
1916  b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_FRAG];
1918  ("maximum fragments per reassembly exceeded");
1919  next0 = NAT_IN2OUT_ED_NEXT_DROP;
1920  goto trace0;
1921  }
1922  cached0 = 1;
1923  goto trace0;
1924  }
1925  s0 = pool_elt_at_index (per_thread_data->sessions,
1926  reass0->sess_index);
1927  }
1928 
1929  old_addr0 = ip0->src_address.as_u32;
1930  ip0->src_address = s0->out2in.addr;
1931  new_addr0 = ip0->src_address.as_u32;
1932  if (!is_output_feature)
1933  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1934 
1935  sum0 = ip0->checksum;
1936  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1937  ip4_header_t,
1938  src_address /* changed member */ );
1940  sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1941  s0->ext_host_addr.as_u32, ip4_header_t,
1942  dst_address);
1943  ip0->checksum = ip_csum_fold (sum0);
1944 
1946  {
1947  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1948  {
1949  old_port0 = tcp0->src_port;
1950  tcp0->src_port = s0->out2in.port;
1951  new_port0 = tcp0->src_port;
1952 
1953  sum0 = tcp0->checksum;
1954  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1955  ip4_header_t,
1956  dst_address /* changed member */ );
1957  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1958  ip4_header_t /* cheat */ ,
1959  length /* changed member */ );
1961  {
1962  sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1963  s0->ext_host_addr.as_u32,
1964  ip4_header_t, dst_address);
1965  sum0 = ip_csum_update (sum0, tcp0->dst_port,
1966  s0->ext_host_port, ip4_header_t,
1967  length);
1968  tcp0->dst_port = s0->ext_host_port;
1969  ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1970  }
1971  tcp0->checksum = ip_csum_fold (sum0);
1972  }
1973  else
1974  {
1975  old_port0 = udp0->src_port;
1976  udp0->src_port = s0->out2in.port;
1977  udp0->checksum = 0;
1979  {
1980  udp0->dst_port = s0->ext_host_port;
1981  ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1982  }
1983  }
1984  }
1985 
1986  /* Hairpinning */
1987  nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
1988  s0->ext_host_port, proto0, 1);
1989 
1990  /* Accounting */
1993  b0));
1994  /* Per-user LRU list maintenance */
1995  nat44_session_update_lru (sm, s0, thread_index);
1996 
1997  trace0:
1999  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2000  {
2001  nat44_reass_trace_t *t =
2002  vlib_add_trace (vm, node, b0, sizeof (*t));
2003  t->cached = cached0;
2004  t->sw_if_index = sw_if_index0;
2005  t->next_index = next0;
2006  }
2007 
2008  if (cached0)
2009  {
2010  n_left_to_next++;
2011  to_next--;
2012  }
2013  else
2014  {
2015  pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
2016 
2017  /* verify speculative enqueue, maybe switch current next frame */
2018  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2019  to_next, n_left_to_next,
2020  bi0, next0);
2021  }
2022 
2023  if (n_left_from == 0 && vec_len (fragments_to_loopback))
2024  {
2025  from = vlib_frame_vector_args (frame);
2026  u32 len = vec_len (fragments_to_loopback);
2027  if (len <= VLIB_FRAME_SIZE)
2028  {
2029  clib_memcpy (from, fragments_to_loopback,
2030  sizeof (u32) * len);
2031  n_left_from = len;
2032  vec_reset_length (fragments_to_loopback);
2033  }
2034  else
2035  {
2036  clib_memcpy (from,
2037  fragments_to_loopback + (len -
2038  VLIB_FRAME_SIZE),
2039  sizeof (u32) * VLIB_FRAME_SIZE);
2040  n_left_from = VLIB_FRAME_SIZE;
2041  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
2042  }
2043  }
2044  }
2045 
2046  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2047  }
2048 
2050  NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
2051  pkts_processed);
2052 
2053  nat_send_all_to_node (vm, fragments_to_drop, node,
2054  &node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT],
2056 
2057  vec_free (fragments_to_drop);
2058  vec_free (fragments_to_loopback);
2059  return frame->n_vectors;
2060 }
2061 
2062 static uword
2064  vlib_node_runtime_t * node,
2065  vlib_frame_t * frame)
2066 {
2067  return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 0);
2068 }
2069 
2070 /* *INDENT-OFF* */
2072  .function = nat44_ed_in2out_reass_node_fn,
2073  .name = "nat44-ed-in2out-reass",
2074  .vector_size = sizeof (u32),
2075  .format_trace = format_nat44_reass_trace,
2076  .type = VLIB_NODE_TYPE_INTERNAL,
2077  .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2078  .error_strings = nat_in2out_ed_error_strings,
2079  .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2080  .next_nodes = {
2081  [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2082  [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
2083  [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2084  [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2085  [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2086  },
2087 };
2088 /* *INDENT-ON* */
2089 
2092 
2093 static uword
2095  vlib_node_runtime_t * node,
2096  vlib_frame_t * frame)
2097 {
2098  return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 1);
2099 }
2100 
2101 /* *INDENT-OFF* */
2104  .name = "nat44-ed-in2out-reass-output",
2105  .vector_size = sizeof (u32),
2106  .format_trace = format_nat44_reass_trace,
2107  .type = VLIB_NODE_TYPE_INTERNAL,
2108  .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2109  .error_strings = nat_in2out_ed_error_strings,
2110  .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2111  .next_nodes = {
2112  [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2113  [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
2114  [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2115  [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2116  [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2117  },
2118 };
2119 /* *INDENT-ON* */
2120 
2123 
2124 /*
2125  * fd.io coding-style-patch-verification: ON
2126  *
2127  * Local Variables:
2128  * eval: (c-set-style "gnu")
2129  * End:
2130  */
ip4_address_t external_addr
Definition: nat.h:327
void nat_ipfix_logging_max_sessions(u32 limit)
Generate maximum session entries exceeded event.
u32 next
Definition: dlist.h:30
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
nat_outside_fib_t * outside_fibs
Definition: nat.h:473
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:598
u32 sessions_per_user_list_head_index
Definition: nat.h:233
static uword nat44_ed_in2out_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path, int is_output_feature)
Definition: in2out_ed.c:875
vlib_node_registration_t nat44_ed_in2out_output_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_output_node)
Definition: in2out_ed.c:77
#define CLIB_UNUSED(x)
Definition: clib.h:81
a
Definition: bitmap.h:538
ip4_address_t src_address
Definition: ip4_packet.h:169
static u32 nat44_session_get_timeout(snat_main_t *sm, snat_session_t *s)
Definition: nat_inlines.h:269
static uword nat44_ed_in2out_output_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out_ed.c:1630
#define PREDICT_TRUE(x)
Definition: clib.h:108
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: nat_inlines.h:53
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:956
static void make_sm_kv(clib_bihash_kv_8_8_t *kv, ip4_address_t *addr, u8 proto, u32 fib_index, u16 port)
Definition: nat_inlines.h:328
u16 port_per_thread
Definition: nat.h:439
u32 thread_index
Definition: main.h:179
VLIB_NODE_FUNCTION_MULTIARCH(nat44_ed_in2out_node, nat44_ed_in2out_fast_path_fn)
#define nat_log_warn(...)
Definition: nat.h:687
int i
uword ip_csum_t
Definition: ip_packet.h:181
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define nat44_is_ses_closed(s)
Check if NAT44 endpoint-dependent TCP session is closed.
Definition: nat.h:652
static_always_inline int nat44_ed_not_translate(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index, ip4_header_t *ip, u32 proto, u32 rx_fib_index, u32 thread_index)
Definition: in2out_ed.c:416
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:472
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:263
dlist_elt_t * list_pool
Definition: nat.h:396
struct _tcp_header tcp_header_t
#define snat_is_unk_proto_session(s)
Check if SNAT session for unknown protocol.
Definition: nat.h:604
static snat_session_t * nat44_ed_in2out_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index, f64 now, vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: in2out_ed.c:675
u32 proto
Definition: nat.h:69
unsigned char u8
Definition: types.h:56
u16 l_port
Definition: nat.h:70
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:212
static int snat_not_translate_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
Check if packet should be translated.
Definition: nat_inlines.h:406
u16 src_port
Definition: udp.api:41
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:224
#define tcp_is_init(t)
Check if client initiating TCP connection (received SYN from client)
Definition: nat.h:682
#define static_always_inline
Definition: clib.h:95
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:443
u16 r_port
Definition: nat.h:71
u32 sw_if_index
Definition: vxlan_gbp.api:39
ip4_address_t dst_address
Definition: ip4_packet.h:169
lb_nat_type_t
Definition: nat.h:312
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:187
#define SNAT_SESSION_FLAG_OUTPUT_FEATURE
Definition: nat.h:178
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Aggregrate type for a prefix.
Definition: fib_types.h:203
u32 icmp_in2out(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, u32 thread_index, void *d, void *e)
Definition: in2out.c:617
#define is_fwd_bypass_session(s)
Check if NAT session is forwarding bypass.
Definition: nat.h:622
#define NAT_REASS_FLAG_ED_DONT_TRANSLATE
Definition: nat_reass.h:35
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:240
unsigned int u32
Definition: types.h:88
#define VLIB_FRAME_SIZE
Definition: node.h:382
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:66
u64 as_u64[2]
Definition: nat.h:73
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
Definition: nat_inlines.h:94
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat)
Match NAT44 static mapping.
Definition: nat.c:2070
static uword nat44_ed_in2out_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out_ed.c:1598
void snat_free_outside_address_and_port(snat_address_t *addresses, u32 thread_index, snat_session_key_t *k)
Free outside address and port pair.
Definition: nat.c:2032
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:166
u32 max_translations
Definition: nat.h:513
static void mss_clamping(snat_main_t *sm, tcp_header_t *tcp, ip_csum_t *sum)
Definition: nat_inlines.h:343
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Alloc outside address and port.
Definition: nat.c:2204
u32 fib_index
Definition: nat.h:69
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Find or create NAT user.
Definition: nat.c:278
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
void nat_free_session_data(snat_main_t *sm, snat_session_t *s, u32 thread_index)
Free NAT44 session data (lookup keys, external addrres port)
Definition: nat.c:177
u32 fib_index
Definition: nat.h:254
clib_bihash_16_8_t out2in_ed
Definition: nat.h:383
long ctx[MAX_CONNS]
Definition: main.c:144
static uword nat44_ed_in2out_output_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out_ed.c:1694
vlib_main_t * vlib_main
Definition: nat.h:539
vlib_node_registration_t nat44_ed_in2out_slowpath_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node)
Definition: in2out_ed.c:76
unsigned short u16
Definition: types.h:57
u16 protocol
Definition: nat.h:54
snat_session_t * nat_ed_session_alloc(snat_main_t *sm, snat_user_t *u, u32 thread_index, f64 now)
Allocate NAT endpoint-dependent session.
Definition: nat.c:391
snat_static_mapping_t * static_mappings
Definition: nat.h:452
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:205
void snat_ipfix_logging_nat44_ses_delete(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
#define PREDICT_FALSE(x)
Definition: clib.h:107
void snat_ipfix_logging_nat44_ses_create(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
static_always_inline int icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
Definition: in2out_ed.c:100
vl_api_address_union_t src_address
Definition: ip_types.api:49
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define SNAT_SESSION_FLAG_UNKNOWN_PROTO
Definition: nat.h:172
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
#define nat_log_notice(...)
Definition: nat.h:689
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:138
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1176
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1409
static u8 * format_nat_in2out_ed_trace(u8 *s, va_list *args)
Definition: in2out_ed.c:82
snat_interface_t * output_feature_interfaces
Definition: nat.h:456
snat_main_t snat_main
Definition: nat.c:37
u64 value
the value
Definition: bihash_8_8.h:34
static void nat44_delete_user_with_no_session(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat_inlines.h:146
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
#define nat_log_debug(...)
Definition: nat.h:693
static u8 snat_proto_to_ip_proto(snat_protocol_t snat_proto)
Definition: nat_inlines.h:41
u16 n_vectors
Definition: node.h:401
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:168
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:79
int nat44_o2i_ed_is_idle_session_cb(clib_bihash_kv_16_8_t *kv, void *arg)
Definition: out2in_ed.c:123
vlib_main_t * vm
Definition: buffer.c:294
vlib_node_registration_t nat44_ed_in2out_output_slowpath_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node)
Definition: in2out_ed.c:78
ip4_address_t l_addr
Definition: nat.h:67
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
#define clib_memcpy(a, b, c)
Definition: string.h:75
vlib_node_registration_t nat44_ed_in2out_reass_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_reass_node)
Definition: in2out_ed.c:79
static void nat44_session_update_counters(snat_session_t *s, f64 now, uword bytes)
Definition: nat_inlines.h:292
u32 outside_fib_index
Definition: nat.h:518
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
static uword nat44_ed_in2out_reass_output_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out_ed.c:2094
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:31
#define ARRAY_LEN(x)
Definition: clib.h:61
ip4_address_t addr
Definition: nat.h:52
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:455
static_always_inline int nat_not_translate_output_feature_fwd(snat_main_t *sm, ip4_header_t *ip, u32 thread_index, f64 now, vlib_main_t *vm, vlib_buffer_t *b)
Definition: in2out_ed.c:451
static void make_ed_kv(clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr, ip4_address_t *r_addr, u8 proto, u32 fib_index, u16 l_port, u16 r_port)
Definition: nat_inlines.h:311
ip4_address_t r_addr
Definition: nat.h:68
static int nat44_set_tcp_session_state_i2o(snat_main_t *sm, snat_session_t *ses, tcp_header_t *tcp, u32 thread_index)
Set TCP session state.
Definition: nat_inlines.h:200
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:513
nat_in2out_ed_error_t
Definition: in2out_ed.c:43
static uword nat44_ed_in2out_reass_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_output_feature)
Definition: in2out_ed.c:1726
static void nat44_session_update_lru(snat_main_t *sm, snat_session_t *s, u32 thread_index)
Per-user LRU list maintenance.
Definition: nat_inlines.h:301
static uword nat44_ed_in2out_reass_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out_ed.c:2063
#define SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT
Definition: nat.h:175
static u32 icmp_in2out_ed_slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, f64 now, u32 thread_index, snat_session_t **p_s0)
Definition: in2out_ed.c:231
ip4_address_t addr
Definition: nat.h:240
vlib_node_registration_t nat44_ed_in2out_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_node)
Definition: in2out_ed.c:75
snat_address_t * twice_nat_addresses
Definition: nat.h:476
u32 value
Definition: dlist.h:32
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
format_function_t format_snat_session
Definition: nat.h:584
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
format_function_t format_nat44_reass_trace
Definition: nat.h:590
static int ip4_is_first_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:219
static u32 ip_proto_to_snat_proto(u8 ip_proto)
The NAT inline functions.
Definition: nat_inlines.h:26
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
int nat44_i2o_ed_is_idle_session_cb(clib_bihash_kv_16_8_t *kv, void *arg)
Definition: in2out_ed.c:149
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:134
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:443
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:231
nat_reass_ip4_t * nat_ip4_reass_find_or_create(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto, u8 reset_timeout, u32 **bi_to_drop)
Find or create reassembly.
Definition: nat_reass.c:220
snat_address_t * addresses
Definition: nat.h:459
#define vnet_buffer(b)
Definition: buffer.h:344
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:171
nat_in2out_ed_next_t
Definition: in2out_ed.c:57
void nat44_ed_hairpinning_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip)
int nat_ip4_reass_add_fragment(nat_reass_ip4_t *reass, u32 bi, u32 **bi_to_drop)
Cache fragment.
Definition: nat_reass.c:338
u8 data[0]
Packet data.
Definition: buffer.h:175
u8 forwarding_enabled
Definition: nat.h:503
#define foreach_nat_in2out_ed_error
Definition: in2out_ed.c:32
#define vec_foreach(var, vec)
Vector iterator.
u32 icmp_match_in2out_ed(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b, ip4_header_t *ip, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Definition: in2out_ed.c:565
u16 flags
Copy of main node flags.
Definition: node.h:507
static void nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: nat_inlines.h:104
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:610
clib_bihash_16_8_t in2out_ed
Definition: nat.h:384
u16 dst_port
Definition: udp.api:42
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:370
NAT plugin virtual fragmentation reassembly.
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:310
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:116
static uword nat44_ed_in2out_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out_ed.c:1662
snat_session_t * sessions
Definition: nat.h:393
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:58
static char * nat_in2out_ed_error_strings[]
Definition: in2out_ed.c:51
#define SNAT_SESSION_FLAG_LOAD_BALANCING
Definition: nat.h:173
clib_bihash_8_8_t static_mapping_by_local
Definition: nat.h:446
vlib_node_registration_t nat44_ed_in2out_reass_output_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_reass_output_node)
Definition: in2out_ed.c:2102
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:237
void nat44_reass_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, u16 sport, u16 dport, u32 proto0, int is_ed)
static u32 slow_path_ed(snat_main_t *sm, vlib_buffer_t *b, u32 rx_fib_index, clib_bihash_kv_16_8_t *kv, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next, u32 thread_index, f64 now, tcp_header_t *tcp)
Definition: in2out_ed.c:253
Definition: defs.h:46
u16 fib_index
Definition: nat.h:54
static_always_inline int nat44_ed_not_translate_output_feature(snat_main_t *sm, ip4_header_t *ip, u8 proto, u16 src_port, u16 dst_port, u32 thread_index, u32 rx_sw_if_index, u32 tx_sw_if_index)
Definition: in2out_ed.c:511