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