FD.io VPP  v18.10-34-gcce845e
Vector Packet Processing
ip_null_dpo.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  * @brief
17  * The data-path object representing dropping the packet
18  */
19 
20 #include <vnet/dpo/ip_null_dpo.h>
21 #include <vnet/ip/ip.h>
22 
23 /**
24  * @brief A representation of the IP_NULL DPO
25  */
26 typedef struct ip_null_dpo_t_
27 {
28  /**
29  * @brief The action to take on a packet
30  */
32  /**
33  * @brief The next VLIB node
34  */
36  /**
37  * rate limits
38  */
40 
41 /**
42  * @brief the IP_NULL dpos are shared by all routes, hence they are global.
43  * As the neame implies this is only for IP, hence 2.
44  */
45 static ip_null_dpo_t ip_null_dpos[2 * IP_NULL_DPO_ACTION_NUM] = {
46  [0] = {
47  /* proto ip4, no action */
49  },
50  [1] = {
51  /* proto ip4, action send unreach */
53  },
54  [2] = {
55  /* proto ip4, action send unreach */
57  },
58  [3] = {
59  /* proto ip6, no action */
60  .ind_action = IP_NULL_ACTION_NONE,
61  },
62  [4] = {
63  /* proto ip6, action send unreach */
65  },
66  [5] = {
67  /* proto ip6, action send unreach */
69  },
70 };
71 
72 /**
73  * @brief Action strings
74  */
76 
77 void
79  ip_null_dpo_action_t action,
80  dpo_id_t *dpo)
81 {
82  int i;
83 
84  ASSERT((proto == DPO_PROTO_IP4) ||
85  (proto == DPO_PROTO_IP6));
87 
88  i = (proto == DPO_PROTO_IP4 ? 0 : 1);
89 
90  dpo_set(dpo, DPO_IP_NULL, proto, (i*IP_NULL_DPO_ACTION_NUM) + action);
91 }
92 
95 {
96  return (&ip_null_dpos[indi]);
97 }
98 
101 {
102  return (ip_null_dpos[indi].ind_action);
103 }
104 
105 static void
107 {
108  /*
109  * not maintaining a lock count on the ip_null, they are const global and
110  * never die.
111  */
112 }
113 static void
115 {
116 }
117 
118 static u8*
119 format_ip_null_dpo (u8 *s, va_list *ap)
120 {
121  index_t index = va_arg(*ap, index_t);
122  CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
123  const ip_null_dpo_t *ind;
124  dpo_proto_t proto;
125 
126  ind = ip_null_dpo_get(index);
127  proto = (index < IP_NULL_DPO_ACTION_NUM ? DPO_PROTO_IP4 : DPO_PROTO_IP6);
128 
129  return (format(s, "%U-null action:%s",
130  format_dpo_proto, proto,
132 }
133 
134 const static dpo_vft_t ip_null_vft = {
136  .dv_unlock = ip_null_dpo_unlock,
137  .dv_format = format_ip_null_dpo,
138 };
139 
140 /**
141  * @brief The per-protocol VLIB graph nodes that are assigned to a ip_null
142  * object.
143  *
144  * this means that these graph nodes are ones from which a ip_null is the
145  * parent object in the DPO-graph.
146  */
147 const static char* const ip4_null_nodes[] =
148 {
149  "ip4-null",
150  NULL,
151 };
152 const static char* const ip6_null_nodes[] =
153 {
154  "ip6-null",
155  NULL,
156 };
157 
158 const static char* const * const ip_null_nodes[DPO_PROTO_NUM] =
159 {
162 };
163 
164 typedef struct ip_null_dpo_trace_t_
165 {
168 
169 /**
170  * @brief Exit nodes from a IP_NULL
171  */
172 typedef enum ip_null_next_t_
173 {
178 
181  vlib_node_runtime_t * node,
182  vlib_frame_t * frame,
183  u8 is_ip4)
184 {
185  u32 n_left_from, next_index, *from, *to_next;
186  static f64 time_last_seed_change = -1e100;
187  static u32 hash_seeds[3];
188  static uword hash_bitmap[256 / BITS (uword)];
189  f64 time_now;
190 
191  from = vlib_frame_vector_args (frame);
192  n_left_from = frame->n_vectors;
193 
194  time_now = vlib_time_now (vm);
195  if (time_now - time_last_seed_change > 1e-1)
196  {
197  uword i;
199  sizeof (hash_seeds));
200  for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
201  hash_seeds[i] = r[i];
202 
203  /* Mark all hash keys as been not-seen before. */
204  for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
205  hash_bitmap[i] = 0;
206 
207  time_last_seed_change = time_now;
208  }
209 
210  next_index = node->cached_next_index;
211 
212  while (n_left_from > 0)
213  {
214  u32 n_left_to_next;
215 
216  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
217 
218  while (n_left_from > 0 && n_left_to_next > 0)
219  {
220  u32 a0, b0, c0, m0, drop0;
221  vlib_buffer_t *p0;
222  u32 bi0, indi0, next0;
223  const ip_null_dpo_t *ind0;
224  uword bm0;
225 
226  bi0 = from[0];
227  to_next[0] = bi0;
228  from += 1;
229  to_next += 1;
230  n_left_from -= 1;
231  n_left_to_next -= 1;
232 
233  p0 = vlib_get_buffer (vm, bi0);
234 
235  /* lookup dst + src mac */
236  indi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
237  ind0 = ip_null_dpo_get(indi0);
238  next0 = IP_NULL_NEXT_DROP;
239 
240  /*
241  * rate limit - don't DoS the sender.
242  */
243  a0 = hash_seeds[0];
244  b0 = hash_seeds[1];
245  c0 = hash_seeds[2];
246 
247  if (is_ip4)
248  {
250 
251  a0 ^= ip0->dst_address.data_u32;
252  b0 ^= ip0->src_address.data_u32;
253 
254  hash_v3_finalize32 (a0, b0, c0);
255  }
256  else
257  {
259 
260  a0 ^= ip0->dst_address.as_u32[0];
261  b0 ^= ip0->src_address.as_u32[0];
262  c0 ^= ip0->src_address.as_u32[1];
263 
264  hash_v3_mix32 (a0, b0, c0);
265 
266  a0 ^= ip0->dst_address.as_u32[1];
267  b0 ^= ip0->src_address.as_u32[2];
268  c0 ^= ip0->src_address.as_u32[3];
269 
270  hash_v3_finalize32 (a0, b0, c0);
271  }
272 
273  c0 &= BITS (hash_bitmap) - 1;
274  c0 = c0 / BITS (uword);
275  m0 = (uword) 1 << (c0 % BITS (uword));
276 
277  bm0 = hash_bitmap[c0];
278  drop0 = (bm0 & m0) != 0;
279 
280  /* Mark it as seen. */
281  hash_bitmap[c0] = bm0 | m0;
282 
283  if (PREDICT_FALSE(!drop0))
284  {
285  if (is_ip4)
286  {
287  /*
288  * There's a trade-off here. This conditinal statement
289  * versus a graph node per-condition. Given the number
290  * expect number of packets to reach a null route is 0
291  * we favour the run-time cost over the graph complexity
292  */
294  {
295  next0 = IP_NULL_NEXT_ICMP;
297  p0,
298  ICMP4_destination_unreachable,
299  ICMP4_destination_unreachable_destination_unreachable_host,
300  0);
301  }
303  {
304  next0 = IP_NULL_NEXT_ICMP;
306  p0,
307  ICMP4_destination_unreachable,
308  ICMP4_destination_unreachable_host_administratively_prohibited,
309  0);
310  }
311  }
312  else
313  {
315  {
316  next0 = IP_NULL_NEXT_ICMP;
318  p0,
319  ICMP6_destination_unreachable,
320  ICMP6_destination_unreachable_no_route_to_destination,
321  0);
322  }
324  {
325  next0 = IP_NULL_NEXT_ICMP;
327  p0,
328  ICMP6_destination_unreachable,
329  ICMP6_destination_unreachable_destination_administratively_prohibited,
330  0);
331  }
332  }
333  }
334 
335  if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
336  {
337  ip_null_dpo_trace_t *tr = vlib_add_trace (vm, node, p0,
338  sizeof (*tr));
339  tr->ind_index = indi0;
340  }
341  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
342  n_left_to_next, bi0, next0);
343  }
344 
345  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
346  }
347 
348  return frame->n_vectors;
349 }
350 
351 static u8 *
352 format_ip_null_dpo_trace (u8 * s, va_list * args)
353 {
354  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
355  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
356  ip_null_dpo_trace_t *t = va_arg (*args, ip_null_dpo_trace_t *);
357 
358  s = format (s, "%U", format_ip_null_dpo, t->ind_index, 0);
359  return s;
360 }
361 
362 static uword
364  vlib_node_runtime_t * node,
365  vlib_frame_t * frame)
366 {
367  return (ip_null_dpo_switch(vm, node, frame, 1));
368 }
369 
370 /**
371  * @brief
372  */
374  .function = ip4_null_dpo_switch,
375  .name = "ip4-null",
376  .vector_size = sizeof (u32),
377 
378  .format_trace = format_ip_null_dpo_trace,
379  .n_next_nodes = IP_NULL_NEXT_NUM,
380  .next_nodes = {
381  [IP_NULL_NEXT_DROP] = "ip4-drop",
382  [IP_NULL_NEXT_ICMP] = "ip4-icmp-error",
383  },
384 };
385 
386 static uword
388  vlib_node_runtime_t * node,
389  vlib_frame_t * frame)
390 {
391  return (ip_null_dpo_switch(vm, node, frame, 0));
392 }
393 
394 /**
395  * @brief
396  */
398  .function = ip6_null_dpo_switch,
399  .name = "ip6-null",
400  .vector_size = sizeof (u32),
401 
402  .format_trace = format_ip_null_dpo_trace,
403  .n_next_nodes = IP_NULL_NEXT_NUM,
404  .next_nodes = {
405  [IP_NULL_NEXT_DROP] = "ip6-drop",
406  [IP_NULL_NEXT_ICMP] = "ip6-icmp-error",
407  },
408 };
409 
410 void
412 {
413  dpo_register(DPO_IP_NULL, &ip_null_vft, ip_null_nodes);
414 }
enum ip_null_dpo_action_t_ ip_null_dpo_action_t
The IP NULL DPO represents the rubbish bin for IP traffic.
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:404
void ip_null_dpo_add_and_lock(dpo_proto_t proto, ip_null_dpo_action_t action, dpo_id_t *dpo)
Definition: ip_null_dpo.c:78
vlib_node_registration_t ip6_null_dpo_node
(constructor) VLIB_REGISTER_NODE (ip6_null_dpo_node)
Definition: ip_null_dpo.c:397
#define CLIB_UNUSED(x)
Definition: clib.h:81
A virtual function table regisitered for a DPO type.
Definition: dpo.h:399
ip4_address_t src_address
Definition: ip4_packet.h:169
static uword ip4_null_dpo_switch(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip_null_dpo.c:363
#define NULL
Definition: clib.h:57
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
static void ip_null_dpo_unlock(dpo_id_t *dpo)
Definition: ip_null_dpo.c:114
static void * clib_random_buffer_get_data(clib_random_buffer_t *b, uword n_bytes)
Definition: random_buffer.h:78
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define IP_NULL_DPO_ACTION_NUM
Definition: ip_null_dpo.h:48
int i
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
ip6_address_t src_address
Definition: ip6_packet.h:378
#define hash_v3_mix32(a, b, c)
Definition: hash.h:554
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
static const ip_null_dpo_t * ip_null_dpo_get(index_t indi)
Definition: ip_null_dpo.c:94
void dpo_register(dpo_type_t type, const dpo_vft_t *vft, const char *const *const *nodes)
For a given DPO type Register:
Definition: dpo.c:321
#define always_inline
Definition: clib.h:94
static u8 * format_ip_null_dpo(u8 *s, va_list *ap)
Definition: ip_null_dpo.c:119
ip4_address_t dst_address
Definition: ip4_packet.h:169
ip_null_dpo_action_t ip_null_dpo_get_action(index_t indi)
Definition: ip_null_dpo.c:100
unsigned int u32
Definition: types.h:88
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
static u8 * format_ip_null_dpo_trace(u8 *s, va_list *args)
Definition: ip_null_dpo.c:352
void icmp6_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp6.c:446
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:168
void ip_null_dpo_module_init(void)
Definition: ip_null_dpo.c:411
static const char *const ip6_null_nodes[]
Definition: ip_null_dpo.c:152
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:205
#define PREDICT_FALSE(x)
Definition: clib.h:107
static void ip_null_dpo_lock(dpo_id_t *dpo)
Definition: ip_null_dpo.c:106
#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:364
u32 as_u32[4]
Definition: ip6_packet.h:50
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
struct ip_null_dpo_trace_t_ ip_null_dpo_trace_t
u16 n_vectors
Definition: node.h:401
vlib_main_t * vm
Definition: buffer.c:294
static const char *const *const ip_null_nodes[DPO_PROTO_NUM]
Definition: ip_null_dpo.c:158
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
ip_null_next_t_
Exit nodes from a IP_NULL.
Definition: ip_null_dpo.c:172
#define ARRAY_LEN(x)
Definition: clib.h:61
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:455
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:185
ip_null_dpo_action_t ind_action
The action to take on a packet.
Definition: ip_null_dpo.c:31
const char * ip_null_action_strings[]
Action strings.
Definition: ip_null_dpo.c:75
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:513
#define ASSERT(truth)
u32 ind_next_index
The next VLIB node.
Definition: ip_null_dpo.c:35
#define hash_v3_finalize32(a, b, c)
Definition: hash.h:564
The data-path object representing dropping the packet.
Definition: ip_null_dpo.c:26
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
enum ip_null_next_t_ ip_null_next_t
Exit nodes from a IP_NULL.
Definition: defs.h:47
#define DPO_PROTO_NUM
Definition: dpo.h:70
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
u8 * format_dpo_proto(u8 *s, va_list *args)
format a DPO protocol
Definition: dpo.c:177
static const char *const ip4_null_nodes[]
The per-protocol VLIB graph nodes that are assigned to a ip_null object.
Definition: ip_null_dpo.c:147
#define vnet_buffer(b)
Definition: buffer.h:344
vlib_node_registration_t ip4_null_dpo_node
(constructor) VLIB_REGISTER_NODE (ip4_null_dpo_node)
Definition: ip_null_dpo.c:373
struct ip_null_dpo_t_ ip_null_dpo_t
The data-path object representing dropping the packet.
#define IP_NULL_ACTIONS
Definition: ip_null_dpo.h:42
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:116
#define BITS(x)
Definition: clib.h:60
static uword ip6_null_dpo_switch(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip_null_dpo.c:387
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:58
clib_random_buffer_t random_buffer
Definition: main.h:173
ip6_address_t dst_address
Definition: ip6_packet.h:378
static uword ip_null_dpo_switch(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_ip4)
Definition: ip_null_dpo.c:180