FD.io VPP  v21.06
Vector Packet Processing
nat44_ed_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 
24 #include <nat/nat44-ed/nat44_ed.h>
26 
27 #define foreach_nat44_classify_error \
28 _(NEXT_IN2OUT, "next in2out") \
29 _(NEXT_OUT2IN, "next out2in") \
30 _(FRAG_CACHED, "fragment cached")
31 
32 typedef enum
33 {
34 #define _(sym,str) NAT44_CLASSIFY_ERROR_##sym,
36 #undef _
39 
40 typedef enum
41 {
47 
48 typedef struct
49 {
53 
54 static u8 *
55 format_nat44_classify_trace (u8 * s, va_list * args)
56 {
57  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
58  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
59  nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *);
60  char *next;
61 
62  if (t->cached)
63  s = format (s, "nat44-classify: fragment cached");
64  else
65  {
66  next = t->next_in2out ? "nat44-ed-in2out" : "nat44-ed-out2in";
67  s = format (s, "nat44-classify: next %s", next);
68  }
69 
70  return s;
71 }
72 
73 static inline uword
77 {
78  u32 n_left_from, *from, *to_next;
80  snat_main_t *sm = &snat_main;
82  u32 next_in2out = 0, next_out2in = 0;
83 
84  from = vlib_frame_vector_args (frame);
85  n_left_from = frame->n_vectors;
86  next_index = node->cached_next_index;
87 
88  while (n_left_from > 0)
89  {
90  u32 n_left_to_next;
91 
92  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
93 
94  while (n_left_from > 0 && n_left_to_next > 0)
95  {
96  u32 bi0;
97  vlib_buffer_t *b0;
99  ip4_header_t *ip0;
100  snat_address_t *ap;
101  clib_bihash_kv_8_8_t kv0, value0;
102 
103  /* speculatively enqueue b0 to the current next frame */
104  bi0 = from[0];
105  to_next[0] = bi0;
106  from += 1;
107  to_next += 1;
108  n_left_from -= 1;
109  n_left_to_next -= 1;
110 
111  b0 = vlib_get_buffer (vm, bi0);
112  ip0 = vlib_buffer_get_current (b0);
113 
114  vec_foreach (ap, sm->addresses)
115  {
116  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
117  {
118  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
119  goto enqueue0;
120  }
121  }
122 
124  {
125  init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
126  /* try to classify the fragment based on IP header alone */
127  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
128  &kv0, &value0))
129  {
130  m = pool_elt_at_index (sm->static_mappings, value0.value);
131  if (m->local_addr.as_u32 != m->external_addr.as_u32)
132  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
133  goto enqueue0;
134  }
135  init_nat_k (&kv0, ip0->dst_address,
136  vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
138  if (!clib_bihash_search_8_8
139  (&sm->static_mapping_by_external, &kv0, &value0))
140  {
141  m = pool_elt_at_index (sm->static_mappings, value0.value);
142  if (m->local_addr.as_u32 != m->external_addr.as_u32)
143  next0 = NAT_NEXT_OUT2IN_CLASSIFY;
144  }
145  }
146 
147  enqueue0:
149  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
150  {
152  vlib_add_trace (vm, node, b0, sizeof (*t));
153  t->cached = 0;
154  t->next_in2out = next0 == NAT_NEXT_IN2OUT_CLASSIFY ? 1 : 0;
155  }
156 
157  next_in2out += next0 == NAT_NEXT_IN2OUT_CLASSIFY;
158  next_out2in += next0 == NAT_NEXT_OUT2IN_CLASSIFY;
159 
160  /* verify speculative enqueue, maybe switch current next frame */
161  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
162  to_next, n_left_to_next,
163  bi0, next0);
164  }
165 
166  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
167  }
168 
170  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
172  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
173  return frame->n_vectors;
174 }
175 
176 static inline uword
180 {
181  u32 n_left_from, *from, *to_next;
183  snat_main_t *sm = &snat_main;
185  u32 next_in2out = 0, next_out2in = 0;
186 
187  from = vlib_frame_vector_args (frame);
188  n_left_from = frame->n_vectors;
189  next_index = node->cached_next_index;
190 
191  while (n_left_from > 0)
192  {
193  u32 n_left_to_next;
194 
195  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
196 
197  while (n_left_from > 0 && n_left_to_next > 0)
198  {
199  u32 bi0;
200  vlib_buffer_t *b0;
202  u32 sw_if_index0, rx_fib_index0;
203  ip4_header_t *ip0;
204  snat_address_t *ap;
205  clib_bihash_kv_8_8_t kv0, value0;
206  clib_bihash_kv_16_8_t ed_kv0, ed_value0;
207 
208  /* speculatively enqueue b0 to the current next frame */
209  bi0 = from[0];
210  to_next[0] = bi0;
211  from += 1;
212  to_next += 1;
213  n_left_from -= 1;
214  n_left_to_next -= 1;
215 
216  b0 = vlib_get_buffer (vm, bi0);
217  ip0 = vlib_buffer_get_current (b0);
218 
219  u32 arc_next;
220  vnet_feature_next (&arc_next, b0);
221  vnet_buffer2 (b0)->nat.arc_next = arc_next;
222 
223  if (ip0->protocol != IP_PROTOCOL_ICMP)
224  {
225  /* process leading fragment/whole packet (with L4 header) */
226  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
227  rx_fib_index0 =
229  sw_if_index0);
230  init_ed_k (&ed_kv0, ip0->src_address,
231  vnet_buffer (b0)->ip.reass.l4_src_port,
232  ip0->dst_address,
233  vnet_buffer (b0)->ip.reass.l4_dst_port,
234  rx_fib_index0, ip0->protocol);
235  /* process whole packet */
236  if (!clib_bihash_search_16_8 (&sm->flow_hash, &ed_kv0,
237  &ed_value0))
238  {
239  ASSERT (vm->thread_index ==
240  ed_value_get_thread_index (&ed_value0));
242  &sm->per_thread_data[vm->thread_index];
243  snat_session_t *s = pool_elt_at_index (
244  tsm->sessions, ed_value_get_session_index (&ed_value0));
245  clib_bihash_kv_16_8_t i2o_kv;
246  nat_6t_flow_to_ed_k (&i2o_kv, &s->i2o);
247  vnet_buffer2 (b0)->nat.cached_session_index =
248  ed_value_get_session_index (&ed_value0);
249  if (i2o_kv.key[0] == ed_kv0.key[0] &&
250  i2o_kv.key[1] == ed_kv0.key[1])
251  {
253  }
254  else
255  {
257  }
258 
259  goto enqueue0;
260  }
261  /* session doesn't exist so continue in code */
262  }
263 
264  vec_foreach (ap, sm->addresses)
265  {
266  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
267  {
269  goto enqueue0;
270  }
271  }
272 
274  {
275  init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
276  /* try to classify the fragment based on IP header alone */
277  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
278  &kv0, &value0))
279  {
280  m = pool_elt_at_index (sm->static_mappings, value0.value);
281  if (m->local_addr.as_u32 != m->external_addr.as_u32)
283  goto enqueue0;
284  }
285  init_nat_k (&kv0, ip0->dst_address,
286  vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
288  if (!clib_bihash_search_8_8
289  (&sm->static_mapping_by_external, &kv0, &value0))
290  {
291  m = pool_elt_at_index (sm->static_mappings, value0.value);
292  if (m->local_addr.as_u32 != m->external_addr.as_u32)
294  }
295  }
296 
297  enqueue0:
299  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
300  {
302  vlib_add_trace (vm, node, b0, sizeof (*t));
303  t->cached = 0;
304  t->next_in2out = next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH ? 1 : 0;
305  }
306 
307  next_in2out += next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH;
308  next_out2in += next0 == NAT_NEXT_OUT2IN_ED_FAST_PATH;
309 
310  /* verify speculative enqueue, maybe switch current next frame */
311  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
312  to_next, n_left_to_next,
313  bi0, next0);
314  }
315 
316  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
317  }
318 
320  NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
322  NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
323  return frame->n_vectors;
324 }
325 
329 {
331 }
332 
334  .name = "nat44-ed-classify",
335  .vector_size = sizeof (u32),
336  .sibling_of = "nat-default",
337  .format_trace = format_nat44_classify_trace,
339 };
340 
344 {
346 }
347 
349  .name = "nat44-handoff-classify",
350  .vector_size = sizeof (u32),
351  .sibling_of = "nat-default",
352  .format_trace = format_nat44_classify_trace,
354 };
355 
356 /*
357  * fd.io coding-style-patch-verification: ON
358  *
359  * Local Variables:
360  * eval: (c-set-style "gnu")
361  * End:
362  */
ip4_address_t external_addr
Definition: nat44_ed.h:415
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:133
#define CLIB_UNUSED(x)
Definition: clib.h:90
ip4_address_t src_address
Definition: ip4_packet.h:125
#define vnet_buffer2(b)
Definition: buffer.h:499
nat44_classify_error_t
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:998
u32 thread_index
Definition: main.h:213
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: nat44_ei.c:3048
#define VLIB_NODE_FN(node)
Definition: node.h:202
nat44_classify_next_t
vlib_node_registration_t nat44_ed_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_classify_node)
unsigned char u8
Definition: types.h:56
unsigned int u32
Definition: types.h:88
static uword nat44_ed_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:24
ip4_address_t dst_address
Definition: ip4_packet.h:125
static_always_inline void nat_6t_flow_to_ed_k(clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
#define foreach_nat44_classify_error
description fragment has unexpected format
Definition: map.api:433
static uword nat44_handoff_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ip4_address_t local_addr
Definition: nat44_ed.h:413
vl_api_fib_path_type_t type
Definition: fib_types.api:123
u16 * next
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
snat_main_t snat_main
Definition: nat44_ed.c:41
snat_static_mapping_t * static_mappings
Definition: nat44_ed.h:528
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
#define PREDICT_FALSE(x)
Definition: clib.h:124
clib_bihash_8_8_t static_mapping_by_external
Definition: nat44_ed.h:525
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
u32 node_index
Node index.
Definition: node.h:479
#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:395
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1244
u64 value
the value
Definition: bihash_8_8.h:44
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:388
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
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)
static u8 * format_nat44_classify_trace(u8 *s, va_list *args)
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:41
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:498
#define ASSERT(truth)
vlib_put_next_frame(vm, node, next_index, 0)
nat44_ei_hairpin_src_next_t next_index
ip4_address_t addr
Definition: nat44_ed.h:352
static u32 ed_value_get_session_index(clib_bihash_kv_16_8_t *value)
static u32 ed_value_get_thread_index(clib_bihash_kv_16_8_t *value)
vl_api_address_t ip
Definition: l2.api:558
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
VLIB buffer representation.
Definition: buffer.h:111
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat44_ed.h:519
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
snat_address_t * addresses
Definition: nat44_ed.h:542
#define vnet_buffer(b)
Definition: buffer.h:437
#define vec_foreach(var, vec)
Vector iterator.
u16 flags
Copy of main node flags.
Definition: node.h:492
clib_bihash_16_8_t flow_hash
Definition: nat44_ed.h:535
vlib_node_registration_t nat44_handoff_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_handoff_classify_node)
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:292
snat_session_t * sessions
Definition: nat44_ed.h:468
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)
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
Definition: defs.h:46
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127