FD.io VPP  v20.09-64-g4f7b92f0a
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_inlines.h>
25 
26 #define foreach_nat44_classify_error \
27 _(NEXT_IN2OUT, "next in2out") \
28 _(NEXT_OUT2IN, "next out2in") \
29 _(FRAG_CACHED, "fragment cached")
30 
31 typedef enum
32 {
33 #define _(sym,str) NAT44_CLASSIFY_ERROR_##sym,
35 #undef _
38 
39 static char *nat44_classify_error_strings[] = {
40 #define _(sym,string) string,
42 #undef _
43 };
44 
45 typedef enum
46 {
52 
53 typedef struct
54 {
58 
59 static u8 *
60 format_nat44_classify_trace (u8 * s, va_list * args)
61 {
62  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
63  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
64  nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *);
65  char *next;
66 
67  if (t->cached)
68  s = format (s, "nat44-classify: fragment cached");
69  else
70  {
71  next = t->next_in2out ? "nat44-in2out" : "nat44-out2in";
72  s = format (s, "nat44-classify: next %s", next);
73  }
74 
75  return s;
76 }
77 
78 static inline uword
82 {
83  u32 n_left_from, *from, *to_next;
84  nat44_classify_next_t next_index;
85  snat_main_t *sm = &snat_main;
87  u32 next_in2out = 0, next_out2in = 0;
88 
89  from = vlib_frame_vector_args (frame);
90  n_left_from = frame->n_vectors;
91  next_index = node->cached_next_index;
92 
93  while (n_left_from > 0)
94  {
95  u32 n_left_to_next;
96 
97  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
98 
99  while (n_left_from > 0 && n_left_to_next > 0)
100  {
101  u32 bi0;
102  vlib_buffer_t *b0;
104  ip4_header_t *ip0;
105  snat_address_t *ap;
106  clib_bihash_kv_8_8_t kv0, value0;
107 
108  /* speculatively enqueue b0 to the current next frame */
109  bi0 = from[0];
110  to_next[0] = bi0;
111  from += 1;
112  to_next += 1;
113  n_left_from -= 1;
114  n_left_to_next -= 1;
115 
116  b0 = vlib_get_buffer (vm, bi0);
117  ip0 = vlib_buffer_get_current (b0);
118 
119  /* *INDENT-OFF* */
120  vec_foreach (ap, sm->addresses)
121  {
122  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
123  {
125  goto enqueue0;
126  }
127  }
128  /* *INDENT-ON* */
129 
131  {
132  init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
133  /* try to classify the fragment based on IP header alone */
134  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
135  &kv0, &value0))
136  {
137  m = pool_elt_at_index (sm->static_mappings, value0.value);
138  if (m->local_addr.as_u32 != m->external_addr.as_u32)
140  goto enqueue0;
141  }
142  init_nat_k (&kv0, ip0->dst_address,
143  vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
145  if (!clib_bihash_search_8_8
146  (&sm->static_mapping_by_external, &kv0, &value0))
147  {
148  m = pool_elt_at_index (sm->static_mappings, value0.value);
149  if (m->local_addr.as_u32 != m->external_addr.as_u32)
151  }
152  }
153 
154  enqueue0:
156  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
157  {
159  vlib_add_trace (vm, node, b0, sizeof (*t));
160  t->cached = 0;
161  t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
162  }
163 
164  next_in2out += next0 == NAT44_CLASSIFY_NEXT_IN2OUT;
165  next_out2in += next0 == NAT44_CLASSIFY_NEXT_OUT2IN;
166 
167  /* verify speculative enqueue, maybe switch current next frame */
168  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
169  to_next, n_left_to_next,
170  bi0, next0);
171  }
172 
173  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
174  }
175 
177  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
179  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
180  return frame->n_vectors;
181 }
182 
183 static inline uword
187 {
188  u32 n_left_from, *from, *to_next;
189  nat44_classify_next_t next_index;
190  snat_main_t *sm = &snat_main;
192  u32 next_in2out = 0, next_out2in = 0;
193 
194  from = vlib_frame_vector_args (frame);
195  n_left_from = frame->n_vectors;
196  next_index = node->cached_next_index;
197 
198  while (n_left_from > 0)
199  {
200  u32 n_left_to_next;
201 
202  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
203 
204  while (n_left_from > 0 && n_left_to_next > 0)
205  {
206  u32 bi0;
207  vlib_buffer_t *b0;
209  ip4_header_t *ip0;
210  snat_address_t *ap;
211  clib_bihash_kv_8_8_t kv0, value0;
212 
213  /* speculatively enqueue b0 to the current next frame */
214  bi0 = from[0];
215  to_next[0] = bi0;
216  from += 1;
217  to_next += 1;
218  n_left_from -= 1;
219  n_left_to_next -= 1;
220 
221  b0 = vlib_get_buffer (vm, bi0);
222  ip0 = vlib_buffer_get_current (b0);
223 
224  /* *INDENT-OFF* */
225  vec_foreach (ap, sm->addresses)
226  {
227  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
228  {
229  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
230  goto enqueue0;
231  }
232  }
233  /* *INDENT-ON* */
234 
236  {
237  init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
238  /* try to classify the fragment based on IP header alone */
239  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
240  &kv0, &value0))
241  {
242  m = pool_elt_at_index (sm->static_mappings, value0.value);
243  if (m->local_addr.as_u32 != m->external_addr.as_u32)
244  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
245  goto enqueue0;
246  }
247  init_nat_k (&kv0, ip0->dst_address,
248  vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
250  if (!clib_bihash_search_8_8
251  (&sm->static_mapping_by_external, &kv0, &value0))
252  {
253  m = pool_elt_at_index (sm->static_mappings, value0.value);
254  if (m->local_addr.as_u32 != m->external_addr.as_u32)
255  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
256  }
257  }
258 
259  enqueue0:
261  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
262  {
264  vlib_add_trace (vm, node, b0, sizeof (*t));
265  t->cached = 0;
266  t->next_in2out = next0 == NAT_NEXT_IN2OUT_CLASSIFY ? 1 : 0;
267  }
268 
269  next_in2out += next0 == NAT_NEXT_IN2OUT_CLASSIFY;
270  next_out2in += next0 == NAT_NEXT_OUT2IN_CLASSIFY;
271 
272  /* verify speculative enqueue, maybe switch current next frame */
273  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
274  to_next, n_left_to_next,
275  bi0, next0);
276  }
277 
278  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
279  }
280 
282  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
284  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
285  return frame->n_vectors;
286 }
287 
288 static inline uword
292 {
293  u32 n_left_from, *from, *to_next;
294  nat44_classify_next_t next_index;
295  snat_main_t *sm = &snat_main;
297  u32 thread_index = vm->thread_index;
298  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
299  u32 next_in2out = 0, next_out2in = 0;
300 
301  from = vlib_frame_vector_args (frame);
302  n_left_from = frame->n_vectors;
303  next_index = node->cached_next_index;
304 
305  while (n_left_from > 0)
306  {
307  u32 n_left_to_next;
308 
309  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
310 
311  while (n_left_from > 0 && n_left_to_next > 0)
312  {
313  u32 bi0;
314  vlib_buffer_t *b0;
316  u32 sw_if_index0, rx_fib_index0;
317  ip4_header_t *ip0;
318  snat_address_t *ap;
319  clib_bihash_kv_8_8_t kv0, value0;
320  clib_bihash_kv_16_8_t ed_kv0, ed_value0;
321 
322  /* speculatively enqueue b0 to the current next frame */
323  bi0 = from[0];
324  to_next[0] = bi0;
325  from += 1;
326  to_next += 1;
327  n_left_from -= 1;
328  n_left_to_next -= 1;
329 
330  b0 = vlib_get_buffer (vm, bi0);
331  ip0 = vlib_buffer_get_current (b0);
332 
333  u32 arc_next;
334  vnet_feature_next (&arc_next, b0);
335  vnet_buffer2 (b0)->nat.arc_next = arc_next;
336 
337  if (ip0->protocol != IP_PROTOCOL_ICMP)
338  {
339  /* process leading fragment/whole packet (with L4 header) */
340  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
341  rx_fib_index0 =
343  sw_if_index0);
344  init_ed_k (&ed_kv0, ip0->src_address,
345  vnet_buffer (b0)->ip.reass.l4_src_port,
346  ip0->dst_address,
347  vnet_buffer (b0)->ip.reass.l4_dst_port,
348  rx_fib_index0, ip0->protocol);
349  /* process whole packet */
350  if (!clib_bihash_search_16_8
351  (&tsm->in2out_ed, &ed_kv0, &ed_value0))
352  goto enqueue0;
353  /* session doesn't exist so continue in code */
354  }
355 
356  /* *INDENT-OFF* */
357  vec_foreach (ap, sm->addresses)
358  {
359  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
360  {
362  goto enqueue0;
363  }
364  }
365  /* *INDENT-ON* */
366 
368  {
369  init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
370  /* try to classify the fragment based on IP header alone */
371  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
372  &kv0, &value0))
373  {
374  m = pool_elt_at_index (sm->static_mappings, value0.value);
375  if (m->local_addr.as_u32 != m->external_addr.as_u32)
377  goto enqueue0;
378  }
379  init_nat_k (&kv0, ip0->dst_address,
380  vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
382  if (!clib_bihash_search_8_8
383  (&sm->static_mapping_by_external, &kv0, &value0))
384  {
385  m = pool_elt_at_index (sm->static_mappings, value0.value);
386  if (m->local_addr.as_u32 != m->external_addr.as_u32)
388  }
389  }
390 
391  enqueue0:
393  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
394  {
396  vlib_add_trace (vm, node, b0, sizeof (*t));
397  t->cached = 0;
398  t->next_in2out = next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH ? 1 : 0;
399  }
400 
401  next_in2out += next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH;
402  next_out2in += next0 == NAT_NEXT_OUT2IN_ED_FAST_PATH;
403 
404  /* verify speculative enqueue, maybe switch current next frame */
405  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
406  to_next, n_left_to_next,
407  bi0, next0);
408  }
409 
410  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
411  }
412 
414  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
416  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
417  return frame->n_vectors;
418 }
419 
423 {
425 }
426 
427 /* *INDENT-OFF* */
429  .name = "nat44-classify",
430  .vector_size = sizeof (u32),
431  .format_trace = format_nat44_classify_trace,
434  .error_strings = nat44_classify_error_strings,
435  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
436  .next_nodes = {
437  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
438  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
439  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
440  },
441 };
442 /* *INDENT-ON* */
443 
447 {
449 }
450 
451 /* *INDENT-OFF* */
453  .name = "nat44-ed-classify",
454  .vector_size = sizeof (u32),
455  .sibling_of = "nat-default",
456  .format_trace = format_nat44_classify_trace,
458 };
459 /* *INDENT-ON* */
460 
464 {
466 }
467 
468 /* *INDENT-OFF* */
470  .name = "nat44-handoff-classify",
471  .vector_size = sizeof (u32),
472  .sibling_of = "nat-default",
473  .format_trace = format_nat44_classify_trace,
475 };
476 
477 /* *INDENT-ON* */
478 
479 /*
480  * fd.io coding-style-patch-verification: ON
481  *
482  * Local Variables:
483  * eval: (c-set-style "gnu")
484  * End:
485  */
ip4_address_t external_addr
Definition: nat.h:361
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
#define CLIB_UNUSED(x)
Definition: clib.h:87
ip4_address_t src_address
Definition: ip4_packet.h:125
#define vnet_buffer2(b)
Definition: buffer.h:482
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:989
u32 thread_index
Definition: main.h:249
vlib_main_t * vm
Definition: in2out_ed.c:1582
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:202
unsigned char u8
Definition: types.h:56
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:22
ip4_address_t dst_address
Definition: ip4_packet.h:125
unsigned int u32
Definition: types.h:88
ip4_address_t local_addr
Definition: nat.h:359
vl_api_fib_path_type_t type
Definition: fib_types.api:123
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
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
#define PREDICT_FALSE(x)
Definition: clib.h:120
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:510
vlib_node_registration_t nat44_handoff_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_handoff_classify_node)
u32 node_index
Node index.
Definition: node.h:487
#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:224
#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:391
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
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
static uword nat44_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
snat_main_t snat_main
Definition: nat.c:39
u64 value
the value
Definition: bihash_8_8.h:42
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:396
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:39
#define ARRAY_LEN(x)
Definition: clib.h:67
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:483
vlib_node_registration_t nat44_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_classify_node)
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
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:510
ip4_address_t addr
Definition: nat.h:296
vl_api_address_t ip
Definition: l2.api:501
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1583
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:504
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
snat_address_t * addresses
Definition: nat.h:523
static void init_ed_k(clib_bihash_kv_16_8_t *kv, ip4_address_t l_addr, u16 l_port, ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto)
Definition: nat_inlines.h:473
nat44_classify_error_t
#define vnet_buffer(b)
Definition: buffer.h:417
#define vec_foreach(var, vec)
Vector iterator.
u16 flags
Copy of main node flags.
Definition: node.h:500
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
clib_bihash_16_8_t in2out_ed
Definition: nat.h:419
#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
static uword nat44_handoff_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static uword nat44_ed_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: defs.h:46
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128