FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
out2in.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT44 endpoint-dependent outside to inside network translation
18  */
19 
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
23 
24 #include <vnet/ip/ip.h>
25 #include <vnet/udp/udp.h>
26 #include <vnet/ethernet/ethernet.h>
27 #include <vnet/fib/ip4_fib.h>
28 #include <nat/nat.h>
29 #include <nat/nat_ipfix_logging.h>
30 #include <nat/nat_inlines.h>
31 #include <nat/nat44/inlines.h>
32 #include <nat/nat_syslog.h>
33 #include <nat/nat_ha.h>
34 
35 #include <vppinfra/hash.h>
36 #include <vppinfra/error.h>
37 #include <vppinfra/elog.h>
38 
39 typedef struct
40 {
45 
46 /* packet trace format function */
47 static u8 *
48 format_snat_out2in_trace (u8 * s, va_list * args)
49 {
50  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
51  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
52  snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
53 
54  s =
55  format (s,
56  "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
58  return s;
59 }
60 
61 static u8 *
62 format_snat_out2in_fast_trace (u8 * s, va_list * args)
63 {
64  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
65  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
66  snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
67 
68  s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
69  t->sw_if_index, t->next_index);
70  return s;
71 }
72 
73 #define foreach_snat_out2in_error \
74 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
75 _(OUT_OF_PORTS, "out of ports") \
76 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
77 _(NO_TRANSLATION, "no translation") \
78 _(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
79 _(CANNOT_CREATE_USER, "cannot create NAT user")
80 
81 typedef enum
82 {
83 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
85 #undef _
88 
89 static char *snat_out2in_error_strings[] = {
90 #define _(sym,string) string,
92 #undef _
93 };
94 
95 typedef enum
96 {
102 
103 #ifndef CLIB_MARCH_VARIANT
104 int
106 {
107  snat_main_t *sm = &snat_main;
109  snat_session_t *s;
110  u64 sess_timeout_time;
112  ctx->thread_index);
114 
115  s = pool_elt_at_index (tsm->sessions, kv->value);
116  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
117  if (ctx->now >= sess_timeout_time)
118  {
119  init_nat_i2o_k (&s_kv, s);
120  if (clib_bihash_add_del_8_8 (&tsm->in2out, &s_kv, 0))
121  nat_elog_warn ("out2in key del failed");
122 
124  s->in2out.addr.as_u32,
125  s->out2in.addr.as_u32,
126  s->nat_proto,
127  s->in2out.port,
128  s->out2in.port,
129  s->in2out.fib_index);
130 
131  nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
132  &s->in2out.addr, s->in2out.port,
133  &s->out2in.addr, s->out2in.port, s->nat_proto);
134 
135  nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
136  s->ext_host_port, s->nat_proto, s->out2in.fib_index,
137  ctx->thread_index);
138 
139  if (!snat_is_session_static (s))
141  &s->out2in.addr, s->out2in.port,
142  s->nat_proto);
143 
144  nat44_delete_session (sm, s, ctx->thread_index);
145  return 1;
146  }
147 
148  return 0;
149 }
150 #endif
151 
152 /**
153  * @brief Create session for static mapping.
154  *
155  * Create NAT session initiated by host from external network with static
156  * mapping.
157  *
158  * @param sm NAT main.
159  * @param b0 Vlib buffer.
160  * @param in2out In2out NAT44 session key.
161  * @param out2in Out2in NAT44 session key.
162  * @param node Vlib node.
163  *
164  * @returns SNAT session if successfully created otherwise 0.
165  */
166 static inline snat_session_t *
168  vlib_buffer_t * b0,
169  ip4_address_t i2o_addr,
170  u16 i2o_port,
171  u32 i2o_fib_index,
172  ip4_address_t o2i_addr,
173  u16 o2i_port,
174  u32 o2i_fib_index,
177  u32 thread_index, f64 now)
178 {
179  snat_user_t *u;
180  snat_session_t *s;
182  ip4_header_t *ip0;
183  udp_header_t *udp0;
185 
186  if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
187  {
188  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
189  nat_elog_notice ("maximum sessions exceeded");
190  return 0;
191  }
192 
193  ip0 = vlib_buffer_get_current (b0);
194  udp0 = ip4_next_header (ip0);
195 
196  u = nat_user_get_or_create (sm, &i2o_addr, i2o_fib_index, thread_index);
197  if (!u)
198  {
199  b0->error = node->errors[SNAT_OUT2IN_ERROR_CANNOT_CREATE_USER];
200  return 0;
201  }
202 
203  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
204  if (!s)
205  {
206  nat44_delete_user_with_no_session (sm, u, thread_index);
207  nat_elog_warn ("create NAT session failed");
208  return 0;
209  }
210 
212  s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
213  s->ext_host_port = udp0->src_port;
214  user_session_increment (sm, u, 1 /* static */ );
215  s->in2out.addr = i2o_addr;
216  s->in2out.port = i2o_port;
217  s->in2out.fib_index = i2o_fib_index;
218  s->out2in.addr = o2i_addr;
219  s->out2in.port = o2i_port;
220  s->out2in.fib_index = o2i_fib_index;
221  s->nat_proto = proto;
222 
223  /* Add to translation hashes */
224  ctx0.now = now;
225  ctx0.thread_index = thread_index;
226  init_nat_i2o_kv (&kv0, s, s - sm->per_thread_data[thread_index].sessions);
227  if (clib_bihash_add_or_overwrite_stale_8_8
228  (&sm->per_thread_data[thread_index].in2out, &kv0,
230  nat_elog_notice ("in2out key add failed");
231 
232  init_nat_o2i_kv (&kv0, s, s - sm->per_thread_data[thread_index].sessions);
233  if (clib_bihash_add_or_overwrite_stale_8_8
234  (&sm->per_thread_data[thread_index].out2in, &kv0,
236  nat_elog_notice ("out2in key add failed");
237 
238  /* log NAT event */
240  s->in2out.addr.as_u32,
241  s->out2in.addr.as_u32,
242  s->nat_proto,
243  s->in2out.port,
244  s->out2in.port, s->in2out.fib_index);
245 
246  nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
247  &s->in2out.addr, s->in2out.port, &s->out2in.addr,
248  s->out2in.port, s->nat_proto);
249 
250  nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
251  s->out2in.port, &s->ext_host_addr, s->ext_host_port,
252  &s->ext_host_nat_addr, s->ext_host_nat_port,
253  s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
254 
255  return s;
256 }
257 
258 #ifndef CLIB_MARCH_VARIANT
261  ip4_address_t * addr, u16 * port, nat_protocol_t * nat_proto)
262 {
263  icmp46_header_t *icmp0;
264  icmp_echo_header_t *echo0, *inner_echo0 = 0;
265  ip4_header_t *inner_ip0;
266  void *l4_header = 0;
267  icmp46_header_t *inner_icmp0;
268 
269  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
270  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
271 
273  (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
274  {
275  *nat_proto = NAT_PROTOCOL_ICMP;
276  *addr = ip0->dst_address;
277  *port = vnet_buffer (b)->ip.reass.l4_src_port;
278  }
279  else
280  {
281  inner_ip0 = (ip4_header_t *) (echo0 + 1);
282  l4_header = ip4_next_header (inner_ip0);
283  *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
284  *addr = inner_ip0->src_address;
285  switch (*nat_proto)
286  {
287  case NAT_PROTOCOL_ICMP:
288  inner_icmp0 = (icmp46_header_t *) l4_header;
289  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
290  *port = inner_echo0->identifier;
291  break;
292  case NAT_PROTOCOL_UDP:
293  case NAT_PROTOCOL_TCP:
294  *port = ((tcp_udp_header_t *) l4_header)->src_port;
295  break;
296  default:
297  return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
298  }
299  }
300  return -1; /* success */
301 }
302 
303 /**
304  * Get address and port values to be used for ICMP packet translation
305  * and create session if needed
306  *
307  * @param[in,out] sm NAT main
308  * @param[in,out] node NAT node runtime
309  * @param[in] thread_index thread index
310  * @param[in,out] b0 buffer containing packet to be translated
311  * @param[in,out] ip0 ip header
312  * @param[out] p_proto protocol used for matching
313  * @param[out] p_value address and port after NAT translation
314  * @param[out] p_dont_translate if packet should not be translated
315  * @param d optional parameter
316  * @param e optional parameter
317  */
318 u32
320  u32 thread_index, vlib_buffer_t * b0,
322  u16 * port, u32 * fib_index,
323  nat_protocol_t * proto, void *d, void *e,
324  u8 * dont_translate)
325 {
326  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
327  u32 sw_if_index0;
328  snat_session_t *s0 = 0;
329  clib_bihash_kv_8_8_t kv0, value0;
330  u8 is_addr_only;
331  u32 next0 = ~0;
332  int err;
333  u8 identity_nat;
334  vlib_main_t *vm = vlib_get_main ();
335  *dont_translate = 0;
336 
337  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
338  *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
339 
340  *proto = 0;
341 
342  err = icmp_get_key (b0, ip0, addr, port, proto);
343  if (err != -1)
344  {
345  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
346  next0 = SNAT_OUT2IN_NEXT_DROP;
347  goto out;
348  }
349 
350  ip4_address_t mapping_addr;
351  u16 mapping_port;
352  u32 mapping_fib_index;
353 
354  init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
355  if (clib_bihash_search_8_8 (&tsm->out2in, &kv0, &value0))
356  {
357  /* Try to match static mapping by external address and port,
358  destination address and port in packet */
360  (sm, *addr, *port, *fib_index, *proto,
361  &mapping_addr, &mapping_port, &mapping_fib_index, 1, &is_addr_only,
362  0, 0, 0, &identity_nat, 0))
363  {
364  if (!sm->forwarding_enabled)
365  {
366  /* Don't NAT packet aimed at the intfc address */
367  if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
368  ip0->dst_address.as_u32)))
369  {
370  *dont_translate = 1;
371  goto out;
372  }
373  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
374  next0 = SNAT_OUT2IN_NEXT_DROP;
375  goto out;
376  }
377  else
378  {
379  *dont_translate = 1;
380  goto out;
381  }
382  }
383 
384  if (PREDICT_FALSE
385  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
386  ICMP4_echo_reply
387  && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
388  ICMP4_echo_request || !is_addr_only)))
389  {
390  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
391  next0 = SNAT_OUT2IN_NEXT_DROP;
392  goto out;
393  }
394 
395  if (PREDICT_FALSE (identity_nat))
396  {
397  *dont_translate = 1;
398  goto out;
399  }
400  /* Create session initiated by host from external network */
401  s0 =
402  create_session_for_static_mapping (sm, b0, mapping_addr, mapping_port,
403  mapping_fib_index, *addr, *port,
404  *fib_index, *proto, node,
405  thread_index, vlib_time_now (vm));
406 
407  if (!s0)
408  {
409  next0 = SNAT_OUT2IN_NEXT_DROP;
410  goto out;
411  }
412  }
413  else
414  {
415  if (PREDICT_FALSE
416  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
417  ICMP4_echo_reply
418  && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
419  ICMP4_echo_request
421  reass.icmp_type_or_tcp_flags)))
422  {
423  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
424  next0 = SNAT_OUT2IN_NEXT_DROP;
425  goto out;
426  }
427 
428  s0 = pool_elt_at_index (tsm->sessions, value0.value);
429  }
430 
431 out:
432  if (s0)
433  {
434  *addr = s0->in2out.addr;
435  *port = s0->in2out.port;
436  *fib_index = s0->in2out.fib_index;
437  }
438  if (d)
439  *(snat_session_t **) d = s0;
440  return next0;
441 }
442 #endif
443 
444 #ifndef CLIB_MARCH_VARIANT
445 /**
446  * Get address and port values to be used for ICMP packet translation
447  *
448  * @param[in] sm NAT main
449  * @param[in,out] node NAT node runtime
450  * @param[in] thread_index thread index
451  * @param[in,out] b0 buffer containing packet to be translated
452  * @param[in,out] ip0 ip header
453  * @param[out] p_proto protocol used for matching
454  * @param[out] p_value address and port after NAT translation
455  * @param[out] p_dont_translate if packet should not be translated
456  * @param d optional parameter
457  * @param e optional parameter
458  */
459 u32
461  u32 thread_index, vlib_buffer_t * b0,
462  ip4_header_t * ip0, ip4_address_t * mapping_addr,
463  u16 * mapping_port, u32 * mapping_fib_index,
464  nat_protocol_t * proto, void *d, void *e,
465  u8 * dont_translate)
466 {
467  u32 sw_if_index0;
468  u32 rx_fib_index0;
469  u8 is_addr_only;
470  u32 next0 = ~0;
471  int err;
473  u16 port;
474  *dont_translate = 0;
475 
476  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
477  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
478 
479  err = icmp_get_key (b0, ip0, &addr, &port, proto);
480  if (err != -1)
481  {
482  b0->error = node->errors[err];
483  next0 = SNAT_OUT2IN_NEXT_DROP;
484  goto out;
485  }
487  (sm, addr, port, rx_fib_index0, *proto, mapping_addr, mapping_port,
488  mapping_fib_index, 1, &is_addr_only, 0, 0, 0, 0, 0))
489  {
490  /* Don't NAT packet aimed at the intfc address */
491  if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
492  {
493  *dont_translate = 1;
494  goto out;
495  }
496  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
497  next0 = SNAT_OUT2IN_NEXT_DROP;
498  goto out;
499  }
500 
501  if (PREDICT_FALSE
502  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
503  && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
504  ICMP4_echo_request || !is_addr_only)
506  reass.icmp_type_or_tcp_flags)))
507  {
508  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
509  next0 = SNAT_OUT2IN_NEXT_DROP;
510  goto out;
511  }
512 
513 out:
514  return next0;
515 }
516 #endif
517 
518 #ifndef CLIB_MARCH_VARIANT
519 u32
521  vlib_buffer_t * b0,
522  ip4_header_t * ip0,
523  icmp46_header_t * icmp0,
524  u32 sw_if_index0,
525  u32 rx_fib_index0,
527  u32 next0, u32 thread_index, void *d, void *e)
528 {
529  icmp_echo_header_t *echo0, *inner_echo0 = 0;
530  ip4_header_t *inner_ip0 = 0;
531  void *l4_header = 0;
532  icmp46_header_t *inner_icmp0;
533  u8 dont_translate;
534  u32 new_addr0, old_addr0;
535  u16 old_id0, new_id0;
536  ip_csum_t sum0;
537  u16 checksum0;
538  u32 next0_tmp;
539  vlib_main_t *vm = vlib_get_main ();
541  u16 port;
542  u32 fib_index;
544 
545  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
546 
547  next0_tmp = sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0,
548  &addr, &port, &fib_index, &proto,
549  d, e, &dont_translate);
550  if (next0_tmp != ~0)
551  next0 = next0_tmp;
552  if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
553  goto out;
554 
555  if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
556  {
557  sum0 =
559  (u8 *) icmp0 -
560  (u8 *) vlib_buffer_get_current (b0),
561  ntohs (ip0->length) -
562  ip4_header_bytes (ip0), 0);
563  checksum0 = ~ip_csum_fold (sum0);
564  if (checksum0 != 0 && checksum0 != 0xffff)
565  {
566  next0 = SNAT_OUT2IN_NEXT_DROP;
567  goto out;
568  }
569  }
570 
571  old_addr0 = ip0->dst_address.as_u32;
572  new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
573  vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
574 
575  sum0 = ip0->checksum;
576  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
577  dst_address /* changed member */ );
578  ip0->checksum = ip_csum_fold (sum0);
579 
580 
581  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
582  {
583  if (icmp0->checksum == 0)
584  icmp0->checksum = 0xffff;
585 
586  if (!icmp_type_is_error_message (icmp0->type))
587  {
588  new_id0 = port;
589  if (PREDICT_FALSE (new_id0 != echo0->identifier))
590  {
591  old_id0 = echo0->identifier;
592  new_id0 = port;
593  echo0->identifier = new_id0;
594 
595  sum0 = icmp0->checksum;
596  sum0 =
597  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
598  identifier /* changed member */ );
599  icmp0->checksum = ip_csum_fold (sum0);
600  }
601  }
602  else
603  {
604  inner_ip0 = (ip4_header_t *) (echo0 + 1);
605  l4_header = ip4_next_header (inner_ip0);
606 
607  if (!ip4_header_checksum_is_valid (inner_ip0))
608  {
609  next0 = SNAT_OUT2IN_NEXT_DROP;
610  goto out;
611  }
612 
613  old_addr0 = inner_ip0->src_address.as_u32;
614  inner_ip0->src_address = addr;
615  new_addr0 = inner_ip0->src_address.as_u32;
616 
617  sum0 = icmp0->checksum;
618  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
619  src_address /* changed member */ );
620  icmp0->checksum = ip_csum_fold (sum0);
621 
622  switch (proto)
623  {
624  case NAT_PROTOCOL_ICMP:
625  inner_icmp0 = (icmp46_header_t *) l4_header;
626  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
627 
628  old_id0 = inner_echo0->identifier;
629  new_id0 = port;
630  inner_echo0->identifier = new_id0;
631 
632  sum0 = icmp0->checksum;
633  sum0 =
634  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
635  identifier);
636  icmp0->checksum = ip_csum_fold (sum0);
637  break;
638  case NAT_PROTOCOL_UDP:
639  case NAT_PROTOCOL_TCP:
640  old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
641  new_id0 = port;
642  ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
643 
644  sum0 = icmp0->checksum;
645  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
646  src_port);
647  icmp0->checksum = ip_csum_fold (sum0);
648  break;
649  default:
650  ASSERT (0);
651  }
652  }
653  }
654 
655 out:
656  return next0;
657 }
658 #endif
659 
660 static inline u32
662  vlib_buffer_t * b0,
663  ip4_header_t * ip0,
664  icmp46_header_t * icmp0,
665  u32 sw_if_index0,
666  u32 rx_fib_index0,
668  u32 next0, f64 now,
669  u32 thread_index, snat_session_t ** p_s0)
670 {
671  vlib_main_t *vm = vlib_get_main ();
672 
673  next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
674  next0, thread_index, p_s0, 0);
675  snat_session_t *s0 = *p_s0;
676  if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
677  {
678  /* Accounting */
681  (vm, b0), thread_index);
682  /* Per-user LRU list maintenance */
683  nat44_session_update_lru (sm, s0, thread_index);
684  }
685  return next0;
686 }
687 
688 static int
690  vlib_buffer_t * b,
691  ip4_header_t * ip, u32 rx_fib_index)
692 {
695  u32 old_addr, new_addr;
696  ip_csum_t sum;
697 
698  init_nat_k (&kv, ip->dst_address, 0, 0, 0);
699  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
700  return 1;
701 
702  m = pool_elt_at_index (sm->static_mappings, value.value);
703 
704  old_addr = ip->dst_address.as_u32;
705  new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
706  sum = ip->checksum;
707  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
708  ip->checksum = ip_csum_fold (sum);
709 
710  vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
711  return 0;
712 }
713 
717 {
718  u32 n_left_from, *from;
719  snat_main_t *sm = &snat_main;
720  f64 now = vlib_time_now (vm);
721  u32 thread_index = vm->thread_index;
722  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
723 
724  from = vlib_frame_vector_args (frame);
725  n_left_from = frame->n_vectors;
726 
727  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
728  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
729  vlib_get_buffers (vm, from, b, n_left_from);
730 
731  while (n_left_from >= 2)
732  {
733  vlib_buffer_t *b0, *b1;
736  u32 sw_if_index0, sw_if_index1;
737  ip4_header_t *ip0, *ip1;
738  ip_csum_t sum0, sum1;
739  u32 new_addr0, old_addr0;
740  u16 new_port0, old_port0;
741  u32 new_addr1, old_addr1;
742  u16 new_port1, old_port1;
743  udp_header_t *udp0, *udp1;
744  tcp_header_t *tcp0, *tcp1;
745  icmp46_header_t *icmp0, *icmp1;
746  u32 rx_fib_index0, rx_fib_index1;
747  u32 proto0, proto1;
748  snat_session_t *s0 = 0, *s1 = 0;
749  clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
750  u8 identity_nat0, identity_nat1;
751  ip4_address_t sm_addr0, sm_addr1;
752  u16 sm_port0, sm_port1;
753  u32 sm_fib_index0, sm_fib_index1;
754 
755  b0 = *b;
756  b++;
757  b1 = *b;
758  b++;
759 
760  /* Prefetch next iteration. */
761  if (PREDICT_TRUE (n_left_from >= 4))
762  {
763  vlib_buffer_t *p2, *p3;
764 
765  p2 = *b;
766  p3 = *(b + 1);
767 
768  vlib_prefetch_buffer_header (p2, LOAD);
769  vlib_prefetch_buffer_header (p3, LOAD);
770 
773  }
774 
775  vnet_buffer (b0)->snat.flags = 0;
776  vnet_buffer (b1)->snat.flags = 0;
777 
778  ip0 = vlib_buffer_get_current (b0);
779  udp0 = ip4_next_header (ip0);
780  tcp0 = (tcp_header_t *) udp0;
781  icmp0 = (icmp46_header_t *) udp0;
782 
783  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
784  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
785  sw_if_index0);
786 
787  if (PREDICT_FALSE (ip0->ttl == 1))
788  {
789  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
790  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
791  ICMP4_time_exceeded_ttl_exceeded_in_transit,
792  0);
794  goto trace0;
795  }
796 
797  proto0 = ip_proto_to_nat_proto (ip0->protocol);
798 
799  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
800  {
801  if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
802  {
803  if (!sm->forwarding_enabled)
804  {
805  b0->error =
806  node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
807  next0 = SNAT_OUT2IN_NEXT_DROP;
808  }
809  }
811  thread_index, sw_if_index0, 1);
812 
813  goto trace0;
814  }
815 
816  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
817  {
818  next0 = icmp_out2in_slow_path
819  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
820  next0, now, thread_index, &s0);
822  thread_index, sw_if_index0, 1);
823  goto trace0;
824  }
825 
826  init_nat_k (&kv0, ip0->dst_address,
827  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
828  proto0);
829  if (clib_bihash_search_8_8
830  (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
831  {
832  /* Try to match static mapping by external address and port,
833  destination address and port in packet */
835  (sm, ip0->dst_address,
836  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
837  proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1, 0, 0, 0,
838  0, &identity_nat0, 0))
839  {
840  /*
841  * Send DHCP packets to the ipv4 stack, or we won't
842  * be able to use dhcp client on the outside interface
843  */
844  if (PREDICT_FALSE
845  (proto0 == NAT_PROTOCOL_UDP
846  && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
847  clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
848  {
849  vnet_feature_next (&next0, b0);
850  goto trace0;
851  }
852 
853  if (!sm->forwarding_enabled)
854  {
855  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
856  next0 = SNAT_OUT2IN_NEXT_DROP;
857  }
858  goto trace0;
859  }
860 
861  if (PREDICT_FALSE (identity_nat0))
862  goto trace0;
863 
864  /* Create session initiated by host from external network */
866  sm_addr0, sm_port0,
867  sm_fib_index0,
868  ip0->dst_address,
869  vnet_buffer (b0)->ip.
870  reass.l4_dst_port,
871  rx_fib_index0, proto0, node,
872  thread_index, now);
873  if (!s0)
874  {
875  next0 = SNAT_OUT2IN_NEXT_DROP;
876  goto trace0;
877  }
878  }
879  else
880  s0 = pool_elt_at_index (tsm->sessions, value0.value);
881 
882  old_addr0 = ip0->dst_address.as_u32;
883  ip0->dst_address = s0->in2out.addr;
884  new_addr0 = ip0->dst_address.as_u32;
885  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
886 
887  sum0 = ip0->checksum;
888  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
889  ip4_header_t, dst_address /* changed member */ );
890  ip0->checksum = ip_csum_fold (sum0);
891 
892  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
893  {
894  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
895  {
896  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
897  new_port0 = udp0->dst_port = s0->in2out.port;
898  sum0 = tcp0->checksum;
899  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
900  ip4_header_t,
901  dst_address /* changed member */ );
902 
903  sum0 = ip_csum_update (sum0, old_port0, new_port0,
904  ip4_header_t /* cheat */ ,
905  length /* changed member */ );
906  tcp0->checksum = ip_csum_fold (sum0);
907  }
909  thread_index, sw_if_index0, 1);
910  }
911  else
912  {
913  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
914  {
915  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
916  new_port0 = udp0->dst_port = s0->in2out.port;
917  if (PREDICT_FALSE (udp0->checksum))
918  {
919  sum0 = udp0->checksum;
920  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
921  );
922  sum0 =
923  ip_csum_update (sum0, old_port0, new_port0,
924  ip4_header_t /* cheat */ ,
925  length /* changed member */ );
926  udp0->checksum = ip_csum_fold (sum0);
927  }
928  }
930  thread_index, sw_if_index0, 1);
931  }
932 
933  /* Accounting */
936  thread_index);
937  /* Per-user LRU list maintenance */
938  nat44_session_update_lru (sm, s0, thread_index);
939  trace0:
940 
941  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
942  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
943  {
944  snat_out2in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
945  t->sw_if_index = sw_if_index0;
946  t->next_index = next0;
947  t->session_index = ~0;
948  if (s0)
949  t->session_index =
950  s0 - sm->per_thread_data[thread_index].sessions;
951  }
952 
953  if (next0 == SNAT_OUT2IN_NEXT_DROP)
954  {
956  thread_index, sw_if_index0, 1);
957  }
958 
959 
960  ip1 = vlib_buffer_get_current (b1);
961  udp1 = ip4_next_header (ip1);
962  tcp1 = (tcp_header_t *) udp1;
963  icmp1 = (icmp46_header_t *) udp1;
964 
965  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
966  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
967  sw_if_index1);
968 
969  if (PREDICT_FALSE (ip1->ttl == 1))
970  {
971  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
972  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
973  ICMP4_time_exceeded_ttl_exceeded_in_transit,
974  0);
976  goto trace1;
977  }
978 
979  proto1 = ip_proto_to_nat_proto (ip1->protocol);
980 
981  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
982  {
983  if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
984  {
985  if (!sm->forwarding_enabled)
986  {
987  b1->error =
988  node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
989  next1 = SNAT_OUT2IN_NEXT_DROP;
990  }
991  }
993  thread_index, sw_if_index1, 1);
994  goto trace1;
995  }
996 
997  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
998  {
999  next1 = icmp_out2in_slow_path
1000  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1001  next1, now, thread_index, &s1);
1003  thread_index, sw_if_index1, 1);
1004  goto trace1;
1005  }
1006 
1007  init_nat_k (&kv1, ip1->dst_address,
1008  vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1,
1009  proto1);
1010 
1011  if (clib_bihash_search_8_8
1012  (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
1013  {
1014  /* Try to match static mapping by external address and port,
1015  destination address and port in packet */
1017  (sm, ip1->dst_address,
1018  vnet_buffer (b1)->ip.reass.l4_dst_port, proto1,
1019  rx_fib_index1, &sm_addr1, &sm_port1, &sm_fib_index1, 1, 0,
1020  0, 0, 0, &identity_nat1, 0))
1021  {
1022  /*
1023  * Send DHCP packets to the ipv4 stack, or we won't
1024  * be able to use dhcp client on the outside interface
1025  */
1026  if (PREDICT_FALSE
1027  (proto1 == NAT_PROTOCOL_UDP
1028  && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
1029  clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
1030  {
1031  vnet_feature_next (&next1, b1);
1032  goto trace1;
1033  }
1034 
1035  if (!sm->forwarding_enabled)
1036  {
1037  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1038  next1 = SNAT_OUT2IN_NEXT_DROP;
1039  }
1040  goto trace1;
1041  }
1042 
1043  if (PREDICT_FALSE (identity_nat1))
1044  goto trace1;
1045 
1046  /* Create session initiated by host from external network */
1047  s1 =
1048  create_session_for_static_mapping (sm, b1, sm_addr1, sm_port1,
1049  sm_fib_index1,
1050  ip1->dst_address,
1051  vnet_buffer (b1)->ip.
1052  reass.l4_dst_port,
1053  rx_fib_index1, proto1, node,
1054  thread_index, now);
1055  if (!s1)
1056  {
1057  next1 = SNAT_OUT2IN_NEXT_DROP;
1058  goto trace1;
1059  }
1060  }
1061  else
1062  s1 =
1063  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1064  value1.value);
1065 
1066  old_addr1 = ip1->dst_address.as_u32;
1067  ip1->dst_address = s1->in2out.addr;
1068  new_addr1 = ip1->dst_address.as_u32;
1069  vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1070 
1071  sum1 = ip1->checksum;
1072  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1073  ip4_header_t, dst_address /* changed member */ );
1074  ip1->checksum = ip_csum_fold (sum1);
1075 
1076  if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1077  {
1078  if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1079  {
1080  old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1081  new_port1 = udp1->dst_port = s1->in2out.port;
1082 
1083  sum1 = tcp1->checksum;
1084  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1085  ip4_header_t,
1086  dst_address /* changed member */ );
1087 
1088  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1089  ip4_header_t /* cheat */ ,
1090  length /* changed member */ );
1091  tcp1->checksum = ip_csum_fold (sum1);
1092  }
1094  thread_index, sw_if_index1, 1);
1095  }
1096  else
1097  {
1098  if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1099  {
1100  old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1101  new_port1 = udp1->dst_port = s1->in2out.port;
1102  if (PREDICT_FALSE (udp1->checksum))
1103  {
1104 
1105  sum1 = udp1->checksum;
1106  sum1 =
1107  ip_csum_update (sum1, old_addr1, new_addr1,
1108  ip4_header_t,
1109  dst_address /* changed member */ );
1110  sum1 =
1111  ip_csum_update (sum1, old_port1, new_port1,
1112  ip4_header_t /* cheat */ ,
1113  length /* changed member */ );
1114  udp1->checksum = ip_csum_fold (sum1);
1115  }
1116  }
1118  thread_index, sw_if_index1, 1);
1119  }
1120 
1121  /* Accounting */
1123  vlib_buffer_length_in_chain (vm, b1),
1124  thread_index);
1125  /* Per-user LRU list maintenance */
1126  nat44_session_update_lru (sm, s1, thread_index);
1127  trace1:
1128 
1129  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1130  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1131  {
1132  snat_out2in_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
1133  t->sw_if_index = sw_if_index1;
1134  t->next_index = next1;
1135  t->session_index = ~0;
1136  if (s1)
1137  t->session_index =
1138  s1 - sm->per_thread_data[thread_index].sessions;
1139  }
1140 
1141  if (next1 == SNAT_OUT2IN_NEXT_DROP)
1142  {
1143  vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
1144  thread_index, sw_if_index1, 1);
1145  }
1146 
1147  n_left_from -= 2;
1148  next[0] = next0;
1149  next[1] = next1;
1150  next += 2;
1151  }
1152 
1153  while (n_left_from > 0)
1154  {
1155  vlib_buffer_t *b0;
1156  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1157  u32 sw_if_index0;
1158  ip4_header_t *ip0;
1159  ip_csum_t sum0;
1160  u32 new_addr0, old_addr0;
1161  u16 new_port0, old_port0;
1162  udp_header_t *udp0;
1163  tcp_header_t *tcp0;
1164  icmp46_header_t *icmp0;
1165  u32 rx_fib_index0;
1166  u32 proto0;
1167  snat_session_t *s0 = 0;
1168  clib_bihash_kv_8_8_t kv0, value0;
1169  u8 identity_nat0;
1170  ip4_address_t sm_addr0;
1171  u16 sm_port0;
1172  u32 sm_fib_index0;
1173 
1174  b0 = *b;
1175  ++b;
1176 
1177  vnet_buffer (b0)->snat.flags = 0;
1178 
1179  ip0 = vlib_buffer_get_current (b0);
1180  udp0 = ip4_next_header (ip0);
1181  tcp0 = (tcp_header_t *) udp0;
1182  icmp0 = (icmp46_header_t *) udp0;
1183 
1184  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1185  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1186  sw_if_index0);
1187 
1188  proto0 = ip_proto_to_nat_proto (ip0->protocol);
1189 
1190  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1191  {
1192  if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1193  {
1194  if (!sm->forwarding_enabled)
1195  {
1196  b0->error =
1197  node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1198  next0 = SNAT_OUT2IN_NEXT_DROP;
1199  }
1200  }
1201  vlib_increment_simple_counter (&sm->counters.slowpath.out2in.other,
1202  thread_index, sw_if_index0, 1);
1203  goto trace00;
1204  }
1205 
1206  if (PREDICT_FALSE (ip0->ttl == 1))
1207  {
1208  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1209  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1210  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1211  0);
1213  goto trace00;
1214  }
1215 
1216  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1217  {
1218  next0 = icmp_out2in_slow_path
1219  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1220  next0, now, thread_index, &s0);
1222  thread_index, sw_if_index0, 1);
1223  goto trace00;
1224  }
1225 
1226  init_nat_k (&kv0, ip0->dst_address,
1227  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1228  proto0);
1229 
1230  if (clib_bihash_search_8_8
1231  (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1232  {
1233  /* Try to match static mapping by external address and port,
1234  destination address and port in packet */
1236  (sm, ip0->dst_address,
1237  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1238  proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1, 0, 0, 0,
1239  0, &identity_nat0, 0))
1240  {
1241  /*
1242  * Send DHCP packets to the ipv4 stack, or we won't
1243  * be able to use dhcp client on the outside interface
1244  */
1245  if (PREDICT_FALSE
1246  (proto0 == NAT_PROTOCOL_UDP
1247  && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1248  clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
1249  {
1250  vnet_feature_next (&next0, b0);
1251  goto trace00;
1252  }
1253 
1254  if (!sm->forwarding_enabled)
1255  {
1256  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1257  next0 = SNAT_OUT2IN_NEXT_DROP;
1258  }
1259  goto trace00;
1260  }
1261 
1262  if (PREDICT_FALSE (identity_nat0))
1263  goto trace00;
1264 
1265  /* Create session initiated by host from external network */
1266  s0 = create_session_for_static_mapping (sm, b0,
1267  sm_addr0, sm_port0,
1268  sm_fib_index0,
1269  ip0->dst_address,
1270  vnet_buffer (b0)->ip.
1271  reass.l4_dst_port,
1272  rx_fib_index0, proto0, node,
1273  thread_index, now);
1274  if (!s0)
1275  {
1276  next0 = SNAT_OUT2IN_NEXT_DROP;
1277  goto trace00;
1278  }
1279  }
1280  else
1281  s0 =
1282  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1283  value0.value);
1284 
1285  old_addr0 = ip0->dst_address.as_u32;
1286  ip0->dst_address = s0->in2out.addr;
1287  new_addr0 = ip0->dst_address.as_u32;
1288  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1289 
1290  sum0 = ip0->checksum;
1291  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1292  ip4_header_t, dst_address /* changed member */ );
1293  ip0->checksum = ip_csum_fold (sum0);
1294 
1295  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1296  {
1297  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1298  {
1299  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1300  new_port0 = udp0->dst_port = s0->in2out.port;
1301 
1302  sum0 = tcp0->checksum;
1303  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1304  ip4_header_t,
1305  dst_address /* changed member */ );
1306 
1307  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1308  ip4_header_t /* cheat */ ,
1309  length /* changed member */ );
1310  tcp0->checksum = ip_csum_fold (sum0);
1311  }
1313  thread_index, sw_if_index0, 1);
1314  }
1315  else
1316  {
1317  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1318  {
1319  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1320  new_port0 = udp0->dst_port = s0->in2out.port;
1321  if (PREDICT_FALSE (udp0->checksum))
1322  {
1323  sum0 = udp0->checksum;
1324  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1325  );
1326  sum0 =
1327  ip_csum_update (sum0, old_port0, new_port0,
1328  ip4_header_t /* cheat */ ,
1329  length /* changed member */ );
1330  udp0->checksum = ip_csum_fold (sum0);
1331  }
1332  }
1334  thread_index, sw_if_index0, 1);
1335  }
1336 
1337  /* Accounting */
1339  vlib_buffer_length_in_chain (vm, b0),
1340  thread_index);
1341  /* Per-user LRU list maintenance */
1342  nat44_session_update_lru (sm, s0, thread_index);
1343  trace00:
1344 
1345  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1346  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1347  {
1348  snat_out2in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
1349  t->sw_if_index = sw_if_index0;
1350  t->next_index = next0;
1351  t->session_index = ~0;
1352  if (s0)
1353  t->session_index =
1354  s0 - sm->per_thread_data[thread_index].sessions;
1355  }
1356 
1357  if (next0 == SNAT_OUT2IN_NEXT_DROP)
1358  {
1359  vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
1360  thread_index, sw_if_index0, 1);
1361  }
1362 
1363  n_left_from--;
1364  next[0] = next0;
1365  next++;
1366  }
1367 
1368  vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1369  frame->n_vectors);
1370 
1371  return frame->n_vectors;
1372 }
1373 
1374 /* *INDENT-OFF* */
1376  .name = "nat44-out2in",
1377  .vector_size = sizeof (u32),
1378  .format_trace = format_snat_out2in_trace,
1380 
1381  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1382  .error_strings = snat_out2in_error_strings,
1383 
1384  .runtime_data_bytes = sizeof (snat_runtime_t),
1385 
1386  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1387 
1388  /* edit / add dispositions here */
1389  .next_nodes = {
1390  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1391  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1392  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1393  },
1394 };
1395 /* *INDENT-ON* */
1396 
1399  vlib_frame_t * frame)
1400 {
1401  u32 n_left_from, *from;
1402  snat_main_t *sm = &snat_main;
1403 
1404  from = vlib_frame_vector_args (frame);
1405  n_left_from = frame->n_vectors;
1406 
1407  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1408  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1409  vlib_get_buffers (vm, from, b, n_left_from);
1410  while (n_left_from > 0)
1411  {
1412  vlib_buffer_t *b0;
1413  u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1414  u32 sw_if_index0;
1415  ip4_header_t *ip0;
1416  ip_csum_t sum0;
1417  u32 new_addr0, old_addr0;
1418  u16 new_port0, old_port0;
1419  udp_header_t *udp0;
1420  tcp_header_t *tcp0;
1421  icmp46_header_t *icmp0;
1422  u32 proto0;
1423  u32 rx_fib_index0;
1424  ip4_address_t sm_addr0;
1425  u16 sm_port0;
1426  u32 sm_fib_index0;
1427 
1428  b0 = *b;
1429  b++;
1430 
1431  ip0 = vlib_buffer_get_current (b0);
1432  udp0 = ip4_next_header (ip0);
1433  tcp0 = (tcp_header_t *) udp0;
1434  icmp0 = (icmp46_header_t *) udp0;
1435 
1436  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1437  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1438 
1439  vnet_feature_next (&next0, b0);
1440 
1441  if (PREDICT_FALSE (ip0->ttl == 1))
1442  {
1443  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1444  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1445  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1446  0);
1448  goto trace00;
1449  }
1450 
1451  proto0 = ip_proto_to_nat_proto (ip0->protocol);
1452 
1453  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1454  goto trace00;
1455 
1456  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1457  {
1458  next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1459  rx_fib_index0, node, next0, ~0, 0, 0);
1460  goto trace00;
1461  }
1462 
1464  (sm, ip0->dst_address, udp0->dst_port, rx_fib_index0, proto0,
1465  &sm_addr0, &sm_port0, &sm_fib_index0, 1, 0, 0, 0, 0, 0, 0))
1466  {
1467  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1468  goto trace00;
1469  }
1470 
1471  new_addr0 = sm_addr0.as_u32;
1472  new_port0 = sm_port0;
1473  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm_fib_index0;
1474  old_addr0 = ip0->dst_address.as_u32;
1475  ip0->dst_address.as_u32 = new_addr0;
1476 
1477  sum0 = ip0->checksum;
1478  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1479  ip4_header_t, dst_address /* changed member */ );
1480  ip0->checksum = ip_csum_fold (sum0);
1481 
1482  if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1483  {
1484  old_port0 = udp0->dst_port;
1485  udp0->dst_port = new_port0;
1486 
1487  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1488  {
1489  sum0 = tcp0->checksum;
1490  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1491  ip4_header_t,
1492  dst_address /* changed member */ );
1493  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1494  ip4_header_t /* cheat */ ,
1495  length /* changed member */ );
1496  tcp0->checksum = ip_csum_fold (sum0);
1497  }
1498  else if (udp0->checksum)
1499  {
1500  sum0 = udp0->checksum;
1501  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1502  ip4_header_t,
1503  dst_address /* changed member */ );
1504  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1505  ip4_header_t /* cheat */ ,
1506  length /* changed member */ );
1507  udp0->checksum = ip_csum_fold (sum0);
1508  }
1509  }
1510  else
1511  {
1512  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1513  {
1514  sum0 = tcp0->checksum;
1515  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1516  ip4_header_t,
1517  dst_address /* changed member */ );
1518  tcp0->checksum = ip_csum_fold (sum0);
1519  }
1520  else if (udp0->checksum)
1521  {
1522  sum0 = udp0->checksum;
1523  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1524  ip4_header_t,
1525  dst_address /* changed member */ );
1526  udp0->checksum = ip_csum_fold (sum0);
1527  }
1528  }
1529 
1530  trace00:
1531 
1532  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1533  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1534  {
1535  snat_out2in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
1536  t->sw_if_index = sw_if_index0;
1537  t->next_index = next0;
1538  }
1539 
1540  if (next0 == SNAT_OUT2IN_NEXT_DROP)
1541  {
1542  vlib_increment_simple_counter (&sm->counters.fastpath.out2in.drops,
1543  vm->thread_index, sw_if_index0, 1);
1544  }
1545 
1546  n_left_from--;
1547  next[0] = next0;
1548  next++;
1549  }
1550 
1551  vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1552  frame->n_vectors);
1553 
1554  return frame->n_vectors;
1555 }
1556 
1557 /* *INDENT-OFF* */
1559  .name = "nat44-out2in-fast",
1560  .vector_size = sizeof (u32),
1561  .format_trace = format_snat_out2in_fast_trace,
1563 
1564  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1565  .error_strings = snat_out2in_error_strings,
1566 
1567  .runtime_data_bytes = sizeof (snat_runtime_t),
1568 
1569  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1570 
1571  /* edit / add dispositions here */
1572  .next_nodes = {
1573  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1574  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1575  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1576  },
1577 };
1578 /* *INDENT-ON* */
1579 
1580 /*
1581  * fd.io coding-style-patch-verification: ON
1582  *
1583  * Local Variables:
1584  * eval: (c-set-style "gnu")
1585  * End:
1586  */
vlib_node_registration_t snat_out2in_fast_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_fast_node)
Definition: out2in.c:1558
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:124
static ip_csum_t ip_incremental_checksum_buffer(vlib_main_t *vm, vlib_buffer_t *first_buffer, u32 first_buffer_offset, u32 n_bytes_to_checksum, ip_csum_t sum)
Definition: ip.h:152
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:748
#define CLIB_UNUSED(x)
Definition: clib.h:87
#define ntohs(x)
Definition: af_xdp.bpf.c:29
ip4_address_t src_address
Definition: ip4_packet.h:125
static u8 * format_snat_out2in_fast_trace(u8 *s, va_list *args)
Definition: out2in.c:62
static u32 nat44_session_get_timeout(snat_main_t *sm, snat_session_t *s)
Definition: nat_inlines.h:411
#define nat_elog_notice(nat_elog_str)
Definition: nat.h:1018
static u32 icmp_out2in_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: out2in.c:661
#define PREDICT_TRUE(x)
Definition: clib.h:121
static void init_nat_i2o_kv(clib_bihash_kv_8_8_t *kv, snat_session_t *s, u64 value)
Definition: nat_inlines.h:81
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:333
u32 thread_index
Definition: main.h:249
static void init_nat_i2o_k(clib_bihash_kv_8_8_t *kv, snat_session_t *s)
Definition: nat_inlines.h:74
uword ip_csum_t
Definition: ip_packet.h:244
#define nat_elog_warn(nat_elog_str)
Definition: nat.h:1020
vlib_main_t * vm
Definition: in2out_ed.c:1582
void nat_ha_sadd(ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, ip4_address_t *ehn_addr, u16 ehn_port, u8 proto, u32 fib_index, u16 flags, u32 thread_index, u8 is_resync)
Create session add HA event.
Definition: nat_ha.c:689
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:122
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 increment)
Increment a simple counter.
Definition: counter.h:78
nat_protocol_t
Definition: lib.h:41
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:469
int nat44_o2i_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: out2in.c:105
static_always_inline snat_out2in_error_t icmp_get_key(vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr, u16 *port, nat_protocol_t *nat_proto)
Definition: out2in.c:260
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:402
void snat_ipfix_logging_nat44_ses_create(u32 thread_index, u32 src_ip, u32 nat_src_ip, nat_protocol_t nat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
struct _tcp_header tcp_header_t
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:168
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index, f64 now)
Allocate new NAT session or recycle last used.
Definition: nat.c:505
clib_bihash_8_8_t in2out
Definition: nat.h:416
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:230
u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t *mapping_addr, u16 *mapping_port, u32 *mapping_fib_index, nat_protocol_t *proto, void *d, void *e, u8 *dont_translate)
Get address and port values to be used for ICMP packet translation.
Definition: out2in.c:460
#define static_always_inline
Definition: clib.h:108
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:384
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:22
void nat_syslog_nat44_apmdel(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, nat_protocol_t proto)
Definition: nat_syslog.c:116
int snat_static_mapping_match(snat_main_t *sm, ip4_address_t match_addr, u16 match_port, u32 match_fib_index, nat_protocol_t match_protocol, ip4_address_t *mapping_addr, u16 *mapping_port, u32 *mapping_fib_index, 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, snat_static_mapping_t **out)
Match NAT44 static mapping.
Definition: nat.c:2815
ip4_address_t dst_address
Definition: ip4_packet.h:125
static void init_nat_o2i_kv(clib_bihash_kv_8_8_t *kv, snat_session_t *s, u64 value)
Definition: nat_inlines.h:96
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: inlines.h:53
ip4_main_t * ip4_main
Definition: nat.h:695
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:196
unsigned int u32
Definition: types.h:88
#define foreach_snat_out2in_error
Definition: out2in.c:73
ip4_address_t local_addr
Definition: nat.h:359
#define VLIB_FRAME_SIZE
Definition: node.h:377
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:275
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
snat_out2in_next_t
Definition: out2in.c:95
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:446
void nat_syslog_nat44_apmadd(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, nat_protocol_t proto)
Definition: nat_syslog.c:107
u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t *addr, u16 *port, u32 *fib_index, nat_protocol_t *proto, void *d, void *e, u8 *dont_translate)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:319
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
vl_api_ip_proto_t proto
Definition: acl_types.api:50
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
snat_static_mapping_t * static_mappings
Definition: nat.h:513
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
struct snat_main_s::@91 counters
#define PREDICT_FALSE(x)
Definition: clib.h:120
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:510
vl_api_address_union_t src_address
Definition: ip_types.api:111
struct snat_main_s::@91::@93 slowpath
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:1375
static void init_nat_k(clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port, u32 fib_index, nat_protocol_t proto)
Definition: nat_inlines.h:58
snat_main_t snat_main
Definition: nat.c:39
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
u64 value
the value
Definition: bihash_8_8.h:42
static void nat44_delete_user_with_no_session(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat_inlines.h:253
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
clib_bihash_8_8_t out2in
Definition: nat.h:415
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:339
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
static void nat44_session_update_counters(snat_session_t *s, f64 now, uword bytes, u32 thread_index)
Definition: nat_inlines.h:434
u8 data[]
Packet data.
Definition: buffer.h:181
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:39
#define ARRAY_LEN(x)
Definition: clib.h:67
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
static_always_inline u8 nat44_maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
The NAT44 inline functions.
Definition: inlines.h:26
u8 value
Definition: qos.api:54
#define ASSERT(truth)
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:493
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:448
void snat_ipfix_logging_nat44_ses_delete(u32 thread_index, u32 src_ip, u32 nat_src_ip, nat_protocol_t nat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
void nat_ha_sdel(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 thread_index)
Create session delete HA event.
Definition: nat_ha.c:715
#define vec_elt(v, i)
Get vector value at index i.
static snat_session_t * create_session_for_static_mapping(snat_main_t *sm, vlib_buffer_t *b0, ip4_address_t i2o_addr, u16 i2o_port, u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index, nat_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, f64 now)
Create session for static mapping.
Definition: out2in.c:167
Definition: defs.h:47
struct snat_main_s::@91::@92 fastpath
vl_api_address_t ip
Definition: l2.api:501
snat_out2in_error_t
Definition: out2in.c:81
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:241
static char * snat_out2in_error_strings[]
Definition: out2in.c:89
static int nat_out2in_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index)
Definition: out2in.c:689
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1583
VLIB buffer representation.
Definition: buffer.h:102
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:504
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
NAT syslog logging.
static u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: nat_inlines.h:206
static u8 * format_snat_out2in_trace(u8 *s, va_list *args)
Definition: out2in.c:48
snat_address_t * addresses
Definition: nat.h:523
u16 port
Definition: lb_types.api:72
#define vnet_buffer(b)
Definition: buffer.h:417
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:183
u8 forwarding_enabled
Definition: nat.h:592
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:577
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:190
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:280
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
void snat_free_outside_address_and_port(snat_address_t *addresses, u32 thread_index, ip4_address_t *addr, u16 port, nat_protocol_t protocol)
Free outside address and port pair.
Definition: nat.c:2740
u32 icmp_out2in(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: out2in.c:520
int nat44_i2o_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: in2out.c:189
snat_session_t * sessions
Definition: nat.h:428
static_always_inline void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.h:51
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
Definition: defs.h:46
NAT active-passive HA.