FD.io VPP  v20.05-21-gb1500e9ff
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 *fragments_to_drop = 0;
88  u32 next_in2out = 0, next_out2in = 0;
89 
90  from = vlib_frame_vector_args (frame);
91  n_left_from = frame->n_vectors;
92  next_index = node->cached_next_index;
93 
94  while (n_left_from > 0)
95  {
96  u32 n_left_to_next;
97 
98  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
99 
100  while (n_left_from > 0 && n_left_to_next > 0)
101  {
102  u32 bi0;
103  vlib_buffer_t *b0;
105  ip4_header_t *ip0;
106  snat_address_t *ap;
107  snat_session_key_t m_key0;
108  clib_bihash_kv_8_8_t kv0, value0;
109 
110  /* speculatively enqueue b0 to the current next frame */
111  bi0 = from[0];
112  to_next[0] = bi0;
113  from += 1;
114  to_next += 1;
115  n_left_from -= 1;
116  n_left_to_next -= 1;
117 
118  b0 = vlib_get_buffer (vm, bi0);
119  ip0 = vlib_buffer_get_current (b0);
120 
121  /* *INDENT-OFF* */
122  vec_foreach (ap, sm->addresses)
123  {
124  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
125  {
127  goto enqueue0;
128  }
129  }
130  /* *INDENT-ON* */
131 
133  {
134  m_key0.addr = ip0->dst_address;
135  m_key0.port = 0;
136  m_key0.protocol = 0;
137  m_key0.fib_index = 0;
138  kv0.key = m_key0.as_u64;
139  /* try to classify the fragment based on IP header alone */
140  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
141  &kv0, &value0))
142  {
143  m = pool_elt_at_index (sm->static_mappings, value0.value);
144  if (m->local_addr.as_u32 != m->external_addr.as_u32)
146  goto enqueue0;
147  }
148  m_key0.port =
149  clib_net_to_host_u16 (vnet_buffer (b0)->ip.reass.l4_dst_port);
150  m_key0.protocol = ip_proto_to_nat_proto (ip0->protocol);
151  kv0.key = m_key0.as_u64;
152  if (!clib_bihash_search_8_8
153  (&sm->static_mapping_by_external, &kv0, &value0))
154  {
155  m = pool_elt_at_index (sm->static_mappings, value0.value);
156  if (m->local_addr.as_u32 != m->external_addr.as_u32)
158  }
159  }
160 
161  enqueue0:
163  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
164  {
166  vlib_add_trace (vm, node, b0, sizeof (*t));
167  t->cached = 0;
168  t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
169  }
170 
171  next_in2out += next0 == NAT44_CLASSIFY_NEXT_IN2OUT;
172  next_out2in += next0 == NAT44_CLASSIFY_NEXT_OUT2IN;
173 
174  /* verify speculative enqueue, maybe switch current next frame */
175  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
176  to_next, n_left_to_next,
177  bi0, next0);
178  }
179 
180  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
181  }
182 
183  nat_send_all_to_node (vm, fragments_to_drop, node, 0,
185 
186  vec_free (fragments_to_drop);
187 
189  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
191  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
192  return frame->n_vectors;
193 }
194 
195 static inline uword
199 {
200  u32 n_left_from, *from, *to_next;
201  nat44_classify_next_t next_index;
202  snat_main_t *sm = &snat_main;
204  u32 *fragments_to_drop = 0;
205  u32 next_in2out = 0, next_out2in = 0;
206 
207  from = vlib_frame_vector_args (frame);
208  n_left_from = frame->n_vectors;
209  next_index = node->cached_next_index;
210 
211  while (n_left_from > 0)
212  {
213  u32 n_left_to_next;
214 
215  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
216 
217  while (n_left_from > 0 && n_left_to_next > 0)
218  {
219  u32 bi0;
220  vlib_buffer_t *b0;
222  ip4_header_t *ip0;
223  snat_address_t *ap;
224  snat_session_key_t m_key0;
225  clib_bihash_kv_8_8_t kv0, value0;
226 
227  /* speculatively enqueue b0 to the current next frame */
228  bi0 = from[0];
229  to_next[0] = bi0;
230  from += 1;
231  to_next += 1;
232  n_left_from -= 1;
233  n_left_to_next -= 1;
234 
235  b0 = vlib_get_buffer (vm, bi0);
236  ip0 = vlib_buffer_get_current (b0);
237 
238  /* *INDENT-OFF* */
239  vec_foreach (ap, sm->addresses)
240  {
241  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
242  {
243  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
244  goto enqueue0;
245  }
246  }
247  /* *INDENT-ON* */
248 
250  {
251  m_key0.addr = ip0->dst_address;
252  m_key0.port = 0;
253  m_key0.protocol = 0;
254  m_key0.fib_index = 0;
255  kv0.key = m_key0.as_u64;
256  /* try to classify the fragment based on IP header alone */
257  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
258  &kv0, &value0))
259  {
260  m = pool_elt_at_index (sm->static_mappings, value0.value);
261  if (m->local_addr.as_u32 != m->external_addr.as_u32)
262  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
263  goto enqueue0;
264  }
265  m_key0.port =
266  clib_net_to_host_u16 (vnet_buffer (b0)->ip.reass.l4_dst_port);
267  m_key0.protocol = ip_proto_to_nat_proto (ip0->protocol);
268  kv0.key = m_key0.as_u64;
269  if (!clib_bihash_search_8_8
270  (&sm->static_mapping_by_external, &kv0, &value0))
271  {
272  m = pool_elt_at_index (sm->static_mappings, value0.value);
273  if (m->local_addr.as_u32 != m->external_addr.as_u32)
274  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
275  }
276  }
277 
278  enqueue0:
280  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
281  {
283  vlib_add_trace (vm, node, b0, sizeof (*t));
284  t->cached = 0;
285  t->next_in2out = next0 == NAT_NEXT_IN2OUT_CLASSIFY ? 1 : 0;
286  }
287 
288  next_in2out += next0 == NAT_NEXT_IN2OUT_CLASSIFY;
289  next_out2in += next0 == NAT_NEXT_OUT2IN_CLASSIFY;
290 
291  /* verify speculative enqueue, maybe switch current next frame */
292  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
293  to_next, n_left_to_next,
294  bi0, next0);
295  }
296 
297  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
298  }
299 
300  nat_send_all_to_node (vm, fragments_to_drop, node, 0, NAT_NEXT_DROP);
301 
302  vec_free (fragments_to_drop);
303 
305  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
307  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
308  return frame->n_vectors;
309 }
310 
311 static inline uword
315 {
316  u32 n_left_from, *from, *to_next;
317  nat44_classify_next_t next_index;
318  snat_main_t *sm = &snat_main;
320  u32 thread_index = vm->thread_index;
321  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
322  u32 *fragments_to_drop = 0;
323  u32 next_in2out = 0, next_out2in = 0;
324 
325  from = vlib_frame_vector_args (frame);
326  n_left_from = frame->n_vectors;
327  next_index = node->cached_next_index;
328 
329  while (n_left_from > 0)
330  {
331  u32 n_left_to_next;
332 
333  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
334 
335  while (n_left_from > 0 && n_left_to_next > 0)
336  {
337  u32 bi0;
338  vlib_buffer_t *b0;
340  u32 sw_if_index0, rx_fib_index0;
341  ip4_header_t *ip0;
342  snat_address_t *ap;
343  snat_session_key_t m_key0;
344  clib_bihash_kv_8_8_t kv0, value0;
345  clib_bihash_kv_16_8_t ed_kv0, ed_value0;
346 
347  /* speculatively enqueue b0 to the current next frame */
348  bi0 = from[0];
349  to_next[0] = bi0;
350  from += 1;
351  to_next += 1;
352  n_left_from -= 1;
353  n_left_to_next -= 1;
354 
355  b0 = vlib_get_buffer (vm, bi0);
356  ip0 = vlib_buffer_get_current (b0);
357 
358  u32 arc_next;
359  vnet_feature_next (&arc_next, b0);
360  vnet_buffer2 (b0)->nat.arc_next = arc_next;
361 
362  if (ip0->protocol != IP_PROTOCOL_ICMP)
363  {
364  /* process leading fragment/whole packet (with L4 header) */
365  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
366  rx_fib_index0 =
368  sw_if_index0);
369  make_ed_kv (&ip0->src_address, &ip0->dst_address,
370  ip0->protocol, rx_fib_index0,
371  vnet_buffer (b0)->ip.reass.l4_src_port,
372  vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL,
373  &ed_kv0);
374  /* process whole packet */
375  if (!clib_bihash_search_16_8
376  (&tsm->in2out_ed, &ed_kv0, &ed_value0))
377  goto enqueue0;
378  /* session doesn't exist so continue in code */
379  }
380 
381  /* *INDENT-OFF* */
382  vec_foreach (ap, sm->addresses)
383  {
384  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
385  {
387  goto enqueue0;
388  }
389  }
390  /* *INDENT-ON* */
391 
393  {
394  m_key0.addr = ip0->dst_address;
395  m_key0.port = 0;
396  m_key0.protocol = 0;
397  m_key0.fib_index = 0;
398  kv0.key = m_key0.as_u64;
399  /* try to classify the fragment based on IP header alone */
400  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
401  &kv0, &value0))
402  {
403  m = pool_elt_at_index (sm->static_mappings, value0.value);
404  if (m->local_addr.as_u32 != m->external_addr.as_u32)
406  goto enqueue0;
407  }
408  m_key0.port =
409  clib_net_to_host_u16 (vnet_buffer (b0)->ip.reass.l4_dst_port);
410  m_key0.protocol = ip_proto_to_nat_proto (ip0->protocol);
411  kv0.key = m_key0.as_u64;
412  if (!clib_bihash_search_8_8
413  (&sm->static_mapping_by_external, &kv0, &value0))
414  {
415  m = pool_elt_at_index (sm->static_mappings, value0.value);
416  if (m->local_addr.as_u32 != m->external_addr.as_u32)
418  }
419  }
420 
421  enqueue0:
423  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
424  {
426  vlib_add_trace (vm, node, b0, sizeof (*t));
427  t->cached = 0;
428  t->next_in2out = next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH ? 1 : 0;
429  }
430 
431  next_in2out += next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH;
432  next_out2in += next0 == NAT_NEXT_OUT2IN_ED_FAST_PATH;
433 
434  /* verify speculative enqueue, maybe switch current next frame */
435  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
436  to_next, n_left_to_next,
437  bi0, next0);
438  }
439 
440  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
441  }
442 
443  nat_send_all_to_node (vm, fragments_to_drop, node, 0,
445 
446  vec_free (fragments_to_drop);
447 
449  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
451  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
452  return frame->n_vectors;
453 }
454 
458 {
460 }
461 
462 /* *INDENT-OFF* */
464  .name = "nat44-classify",
465  .vector_size = sizeof (u32),
466  .format_trace = format_nat44_classify_trace,
469  .error_strings = nat44_classify_error_strings,
470  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
471  .next_nodes = {
472  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
473  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
474  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
475  },
476 };
477 /* *INDENT-ON* */
478 
482 {
484 }
485 
486 /* *INDENT-OFF* */
488  .name = "nat44-ed-classify",
489  .vector_size = sizeof (u32),
490  .sibling_of = "nat-default",
491  .format_trace = format_nat44_classify_trace,
493 };
494 /* *INDENT-ON* */
495 
499 {
501 }
502 
503 /* *INDENT-OFF* */
505  .name = "nat44-det-classify",
506  .vector_size = sizeof (u32),
507  .format_trace = format_nat44_classify_trace,
509  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
510  .next_nodes = {
511  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
512  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
513  [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
514  },
515 };
516 /* *INDENT-ON* */
517 
521 {
523 }
524 
525 /* *INDENT-OFF* */
527  .name = "nat44-handoff-classify",
528  .vector_size = sizeof (u32),
529  .sibling_of = "nat-default",
530  .format_trace = format_nat44_classify_trace,
532 };
533 
534 /* *INDENT-ON* */
535 
536 /*
537  * fd.io coding-style-patch-verification: ON
538  *
539  * Local Variables:
540  * eval: (c-set-style "gnu")
541  * End:
542  */
ip4_address_t external_addr
Definition: nat.h:401
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:86
ip4_address_t src_address
Definition: ip4_packet.h:170
#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:218
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:170
unsigned int u32
Definition: types.h:88
ip4_address_t local_addr
Definition: nat.h:399
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
u64 key
the key
Definition: bihash_8_8.h:41
u16 protocol
Definition: nat.h:80
snat_static_mapping_t * static_mappings
Definition: nat.h:545
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:118
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:542
vlib_node_registration_t nat44_handoff_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_handoff_classify_node)
u32 node_index
Node index.
Definition: node.h:498
#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:338
vlib_main_t * vm
Definition: in2out_ed.c:1599
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
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:41
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:399
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
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:66
ip4_address_t addr
Definition: nat.h:78
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:1599
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:517
ip4_address_t addr
Definition: nat.h:314
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:55
vl_api_address_t ip
Definition: l2.api:501
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:536
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
snat_address_t * addresses
Definition: nat.h:552
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:417
#define vec_foreach(var, vec)
Vector iterator.
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1600
u16 flags
Copy of main node flags.
Definition: node.h:511
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:185
clib_bihash_16_8_t in2out_ed
Definition: nat.h:458
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:304
#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 void make_ed_kv(ip4_address_t *l_addr, ip4_address_t *r_addr, u8 proto, u32 fib_index, u16 l_port, u16 r_port, u64 value, clib_bihash_kv_16_8_t *kv)
Definition: nat_inlines.h:447
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
u16 fib_index
Definition: nat.h:80
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128