FD.io VPP  v19.04.1-1-ge4a0f9f
Vector Packet Processing
nat44_classify.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief Classify for one armed NAT44 (in+out interface)
18  */
19 
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/fib/ip4_fib.h>
23 #include <nat/nat.h>
24 #include <nat/nat_reass.h>
25 #include <nat/nat_inlines.h>
26 
27 #define foreach_nat44_classify_error \
28 _(MAX_REASS, "Maximum reassemblies exceeded") \
29 _(MAX_FRAG, "Maximum fragments per reassembly exceeded") \
30 _(NEXT_IN2OUT, "next in2out") \
31 _(NEXT_OUT2IN, "next out2in") \
32 _(FRAG_CACHED, "fragment cached")
33 
34 typedef enum
35 {
36 #define _(sym,str) NAT44_CLASSIFY_ERROR_##sym,
38 #undef _
41 
42 static char *nat44_classify_error_strings[] = {
43 #define _(sym,string) string,
45 #undef _
46 };
47 
48 typedef enum
49 {
55 
56 typedef struct
57 {
61 
62 static u8 *
63 format_nat44_classify_trace (u8 * s, va_list * args)
64 {
65  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67  nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *);
68  char *next;
69 
70  if (t->cached)
71  s = format (s, "nat44-classify: fragment cached");
72  else
73  {
74  next = t->next_in2out ? "nat44-in2out" : "nat44-out2in";
75  s = format (s, "nat44-classify: next %s", next);
76  }
77 
78  return s;
79 }
80 
81 static inline uword
83  vlib_node_runtime_t * node,
84  vlib_frame_t * frame, int is_ed)
85 {
86  u32 n_left_from, *from, *to_next;
87  nat44_classify_next_t next_index;
88  snat_main_t *sm = &snat_main;
90  u32 thread_index = vm->thread_index;
91  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
92  u32 *fragments_to_drop = 0;
93  u32 *fragments_to_loopback = 0;
94  u32 next_in2out = 0, next_out2in = 0, frag_cached = 0;
95 
96  from = vlib_frame_vector_args (frame);
97  n_left_from = frame->n_vectors;
98  next_index = node->cached_next_index;
99 
100  while (n_left_from > 0)
101  {
102  u32 n_left_to_next;
103 
104  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
105 
106  while (n_left_from > 0 && n_left_to_next > 0)
107  {
108  u32 bi0;
109  vlib_buffer_t *b0;
110  u32 next0 = NAT44_CLASSIFY_NEXT_IN2OUT, sw_if_index0, rx_fib_index0;
111  ip4_header_t *ip0;
112  snat_address_t *ap;
113  snat_session_key_t m_key0;
114  clib_bihash_kv_8_8_t kv0, value0;
115  clib_bihash_kv_16_8_t ed_kv0, ed_value0;
116  udp_header_t *udp0;
117  nat_reass_ip4_t *reass0;
118  u8 cached0 = 0;
119 
120  /* speculatively enqueue b0 to the current next frame */
121  bi0 = from[0];
122  to_next[0] = bi0;
123  from += 1;
124  to_next += 1;
125  n_left_from -= 1;
126  n_left_to_next -= 1;
127 
128  b0 = vlib_get_buffer (vm, bi0);
129  ip0 = vlib_buffer_get_current (b0);
130  udp0 = ip4_next_header (ip0);
131 
132  if (is_ed && ip0->protocol != IP_PROTOCOL_ICMP)
133  {
134  if (!ip4_is_fragment (ip0) || ip4_is_first_fragment (ip0))
135  {
136  /* process leading fragment/whole packet (with L4 header) */
137  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
138  rx_fib_index0 =
140  sw_if_index0);
141  make_ed_kv (&ed_kv0, &ip0->src_address, &ip0->dst_address,
142  ip0->protocol, rx_fib_index0, udp0->src_port,
143  udp0->dst_port);
144  if (ip4_is_fragment (ip0))
145  {
147  ip0->dst_address,
148  ip0->fragment_id,
149  ip0->protocol,
150  1,
151  &fragments_to_drop);
152  if (PREDICT_FALSE (!reass0))
153  {
154  next0 = NAT44_CLASSIFY_NEXT_DROP;
155  b0->error =
156  node->errors[NAT44_CLASSIFY_ERROR_MAX_REASS];
157  nat_log_notice ("maximum reassemblies exceeded");
158  goto enqueue0;
159  }
160  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &ed_kv0,
161  &ed_value0))
162  {
163  /* session exists so classify as IN2OUT,
164  * save this information for future fragments and set
165  * past fragments to be looped over and reprocessed */
166  reass0->sess_index = ed_value0.value;
167  reass0->classify_next =
169  nat_ip4_reass_get_frags (reass0,
170  &fragments_to_loopback);
171  goto enqueue0;
172  }
173  else
174  {
175  /* session doesn't exist so continue in the code,
176  * save this information for future fragments and set
177  * past fragments to be looped over and reprocessed */
178  reass0->flags |=
180  nat_ip4_reass_get_frags (reass0,
181  &fragments_to_loopback);
182  }
183  }
184  else
185  {
186  /* process whole packet */
187  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &ed_kv0,
188  &ed_value0))
189  goto enqueue0;
190  /* session doesn't exist so continue in code */
191  }
192  }
193  else
194  {
195  /* process non-first fragment */
197  ip0->dst_address,
198  ip0->fragment_id,
199  ip0->protocol,
200  1,
201  &fragments_to_drop);
202  if (PREDICT_FALSE (!reass0))
203  {
204  next0 = NAT44_CLASSIFY_NEXT_DROP;
205  b0->error =
206  node->errors[NAT44_CLASSIFY_ERROR_MAX_REASS];
207  nat_log_notice ("maximum reassemblies exceeded");
208  goto enqueue0;
209  }
210  /* check if first fragment has arrived */
211  if (reass0->classify_next == NAT_REASS_IP4_CLASSIFY_NONE &&
212  !(reass0->flags & NAT_REASS_FLAG_CLASSIFY_ED_CONTINUE))
213  {
214  /* first fragment still hasn't arrived, cache this fragment */
216  (thread_index, reass0, bi0, &fragments_to_drop))
217  {
218  b0->error =
219  node->errors[NAT44_CLASSIFY_ERROR_MAX_FRAG];
221  ("maximum fragments per reassembly exceeded");
222  next0 = NAT44_CLASSIFY_NEXT_DROP;
223  goto enqueue0;
224  }
225  cached0 = 1;
226  goto enqueue0;
227  }
228  if (reass0->classify_next ==
230  goto enqueue0;
231  /* flag NAT_REASS_FLAG_CLASSIFY_ED_CONTINUE is set
232  * so keep the default next0 and continue in code to
233  * potentially find other classification for this packet */
234  }
235  }
236 
237  /* *INDENT-OFF* */
238  vec_foreach (ap, sm->addresses)
239  {
240  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
241  {
243  goto enqueue0;
244  }
245  }
246  /* *INDENT-ON* */
247 
249  {
250  m_key0.addr = ip0->dst_address;
251  m_key0.port = 0;
252  m_key0.protocol = 0;
253  m_key0.fib_index = 0;
254  kv0.key = m_key0.as_u64;
255  /* try to classify the fragment based on IP header alone */
256  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
257  &kv0, &value0))
258  {
259  m = pool_elt_at_index (sm->static_mappings, value0.value);
260  if (m->local_addr.as_u32 != m->external_addr.as_u32)
262  goto enqueue0;
263  }
264  if (!ip4_is_fragment (ip0) || ip4_is_first_fragment (ip0))
265  {
266  /* process leading fragment/whole packet (with L4 header) */
267  m_key0.port = clib_net_to_host_u16 (udp0->dst_port);
268  m_key0.protocol = ip_proto_to_snat_proto (ip0->protocol);
269  kv0.key = m_key0.as_u64;
270  if (!clib_bihash_search_8_8
271  (&sm->static_mapping_by_external, &kv0, &value0))
272  {
273  m =
275  if (m->local_addr.as_u32 != m->external_addr.as_u32)
277  }
278  if (ip4_is_fragment (ip0))
279  {
281  ip0->dst_address,
282  ip0->fragment_id,
283  ip0->protocol,
284  1,
285  &fragments_to_drop);
286  if (PREDICT_FALSE (!reass0))
287  {
288  next0 = NAT44_CLASSIFY_NEXT_DROP;
289  b0->error =
290  node->errors[NAT44_CLASSIFY_ERROR_MAX_REASS];
291  nat_log_notice ("maximum reassemblies exceeded");
292  goto enqueue0;
293  }
294  /* save classification for future fragments and set past
295  * fragments to be looped over and reprocessed */
296  if (next0 == NAT44_CLASSIFY_NEXT_OUT2IN)
297  reass0->classify_next =
299  else
300  reass0->classify_next =
302  nat_ip4_reass_get_frags (reass0,
303  &fragments_to_loopback);
304  }
305  }
306  else
307  {
308  /* process non-first fragment */
310  ip0->dst_address,
311  ip0->fragment_id,
312  ip0->protocol,
313  1,
314  &fragments_to_drop);
315  if (PREDICT_FALSE (!reass0))
316  {
317  next0 = NAT44_CLASSIFY_NEXT_DROP;
318  b0->error =
319  node->errors[NAT44_CLASSIFY_ERROR_MAX_REASS];
320  nat_log_notice ("maximum reassemblies exceeded");
321  goto enqueue0;
322  }
323  if (reass0->classify_next == NAT_REASS_IP4_CLASSIFY_NONE)
324  /* first fragment still hasn't arrived */
325  {
327  (thread_index, reass0, bi0, &fragments_to_drop))
328  {
329  b0->error =
330  node->errors[NAT44_CLASSIFY_ERROR_MAX_FRAG];
332  ("maximum fragments per reassembly exceeded");
333  next0 = NAT44_CLASSIFY_NEXT_DROP;
334  goto enqueue0;
335  }
336  cached0 = 1;
337  goto enqueue0;
338  }
339  else if (reass0->classify_next ==
342  else if (reass0->classify_next ==
345  }
346  }
347 
348  enqueue0:
350  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
351  {
353  vlib_add_trace (vm, node, b0, sizeof (*t));
354  t->cached = cached0;
355  if (!cached0)
356  t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
357  }
358 
359  if (cached0)
360  {
361  n_left_to_next++;
362  to_next--;
363  frag_cached++;
364  }
365  else
366  {
367  next_in2out += next0 == NAT44_CLASSIFY_NEXT_IN2OUT;
368  next_out2in += next0 == NAT44_CLASSIFY_NEXT_OUT2IN;
369 
370  /* verify speculative enqueue, maybe switch current next frame */
371  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
372  to_next, n_left_to_next,
373  bi0, next0);
374  }
375 
376  if (n_left_from == 0 && vec_len (fragments_to_loopback))
377  {
378  from = vlib_frame_vector_args (frame);
379  u32 len = vec_len (fragments_to_loopback);
380  if (len <= VLIB_FRAME_SIZE)
381  {
382  clib_memcpy_fast (from, fragments_to_loopback,
383  sizeof (u32) * len);
384  n_left_from = len;
385  vec_reset_length (fragments_to_loopback);
386  }
387  else
388  {
389  clib_memcpy_fast (from, fragments_to_loopback +
390  (len - VLIB_FRAME_SIZE),
391  sizeof (u32) * VLIB_FRAME_SIZE);
392  n_left_from = VLIB_FRAME_SIZE;
393  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
394  }
395  }
396  }
397 
398  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
399  }
400 
401  nat_send_all_to_node (vm, fragments_to_drop, node, 0,
403 
404  vec_free (fragments_to_drop);
405 
407  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
409  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
411  NAT44_CLASSIFY_ERROR_FRAG_CACHED, frag_cached);
412 
413  return frame->n_vectors;
414 }
415 
417  vlib_node_runtime_t * node,
418  vlib_frame_t * frame)
419 {
420  return nat44_classify_node_fn_inline (vm, node, frame, 0);
421 }
422 
423 /* *INDENT-OFF* */
425  .name = "nat44-classify",
426  .vector_size = sizeof (u32),
427  .format_trace = format_nat44_classify_trace,
428  .type = VLIB_NODE_TYPE_INTERNAL,
430  .error_strings = nat44_classify_error_strings,
431  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
432  .next_nodes = {
433  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
434  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
435  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
436  },
437 };
438 /* *INDENT-ON* */
439 
441  vlib_node_runtime_t * node,
442  vlib_frame_t * frame)
443 {
444  return nat44_classify_node_fn_inline (vm, node, frame, 1);
445 }
446 
447 /* *INDENT-OFF* */
449  .name = "nat44-ed-classify",
450  .vector_size = sizeof (u32),
451  .format_trace = format_nat44_classify_trace,
452  .type = VLIB_NODE_TYPE_INTERNAL,
453  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
454  .next_nodes = {
455  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-ed-in2out",
456  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-ed-out2in",
457  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
458  },
459 };
460 /* *INDENT-ON* */
461 
463  vlib_node_runtime_t * node,
464  vlib_frame_t * frame)
465 {
466  return nat44_classify_node_fn_inline (vm, node, frame, 0);
467 }
468 
469 /* *INDENT-OFF* */
471  .name = "nat44-det-classify",
472  .vector_size = sizeof (u32),
473  .format_trace = format_nat44_classify_trace,
474  .type = VLIB_NODE_TYPE_INTERNAL,
475  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
476  .next_nodes = {
477  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
478  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
479  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
480  },
481 };
482 /* *INDENT-ON* */
483 
485  vlib_node_runtime_t * node,
486  vlib_frame_t * frame)
487 {
488  return nat44_classify_node_fn_inline (vm, node, frame, 0);
489 }
490 
491 /* *INDENT-OFF* */
493  .name = "nat44-handoff-classify",
494  .vector_size = sizeof (u32),
495  .format_trace = format_nat44_classify_trace,
496  .type = VLIB_NODE_TYPE_INTERNAL,
497  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
498  .next_nodes = {
499  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff",
500  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff",
501  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
502  },
503 };
504 
505 /* *INDENT-ON* */
506 
507 /*
508  * fd.io coding-style-patch-verification: ON
509  *
510  * Local Variables:
511  * eval: (c-set-style "gnu")
512  * End:
513  */
ip4_address_t external_addr
Definition: nat.h:333
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
nat44_classify_next_t
int nat_ip4_reass_add_fragment(u32 thread_index, nat_reass_ip4_t *reass, u32 bi, u32 **bi_to_drop)
Cache fragment.
Definition: nat_reass.c:392
#define CLIB_UNUSED(x)
Definition: clib.h:82
ip4_address_t src_address
Definition: ip4_packet.h:170
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
vlib_node_registration_t nat44_ed_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_classify_node)
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:956
u32 thread_index
Definition: main.h:197
static uword nat44_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_ed)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static u8 * format_nat44_classify_trace(u8 *s, va_list *args)
#define VLIB_NODE_FN(node)
Definition: node.h:201
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:469
unsigned char u8
Definition: types.h:56
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:213
ip4_address_t dst_address
Definition: ip4_packet.h:170
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
#define NAT_REASS_FLAG_CLASSIFY_ED_CONTINUE
Definition: nat_reass.h:34
ip4_address_t local_addr
Definition: nat.h:331
#define VLIB_FRAME_SIZE
Definition: node.h:376
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
u64 key
the key
Definition: bihash_8_8.h:33
u16 protocol
Definition: nat.h:54
snat_static_mapping_t * static_mappings
Definition: nat.h:458
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:111
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:455
vlib_node_registration_t nat44_handoff_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_handoff_classify_node)
u32 node_index
Node index.
Definition: node.h:495
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:368
#define nat_log_notice(...)
Definition: nat.h:722
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1180
u8 len
Definition: ip_types.api:49
snat_main_t snat_main
Definition: nat.c:39
u64 value
the value
Definition: bihash_8_8.h:34
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:395
vlib_main_t * vm
Definition: buffer.c:312
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:31
#define ARRAY_LEN(x)
Definition: clib.h:62
ip4_address_t addr
Definition: nat.h:52
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:465
vlib_node_registration_t nat44_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_classify_node)
static void make_ed_kv(clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr, ip4_address_t *r_addr, u8 proto, u32 fib_index, u16 l_port, u16 r_port)
Definition: nat_inlines.h:321
static char * nat44_classify_error_strings[]
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:514
ip4_address_t addr
Definition: nat.h:246
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
static int ip4_is_first_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:220
static u32 ip_proto_to_snat_proto(u8 ip_proto)
The NAT inline functions.
Definition: nat_inlines.h:27
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:449
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
snat_address_t * addresses
Definition: nat.h:465
nat_reass_ip4_t * nat_ip4_reass_find_or_create(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto, u8 reset_timeout, u32 **bi_to_drop)
Find or create reassembly.
Definition: nat_reass.c:274
vlib_node_registration_t nat44_det_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_det_classify_node)
nat44_classify_error_t
#define vnet_buffer(b)
Definition: buffer.h:369
#define vec_foreach(var, vec)
Vector iterator.
u16 flags
Copy of main node flags.
Definition: node.h:508
static void nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: nat_inlines.h:105
clib_bihash_16_8_t in2out_ed
Definition: nat.h:390
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:424
NAT plugin virtual fragmentation reassembly.
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
#define foreach_nat44_classify_error
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
Definition: defs.h:46
u16 fib_index
Definition: nat.h:54
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128