FD.io VPP  v19.08.1-401-g8e4ed521a
Vector Packet Processing
icmp4.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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  * ip/icmp4.c: ipv4 icmp
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <vlib/vlib.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/pg/pg.h>
43 
44 static char *icmp_error_strings[] = {
45 #define _(f,s) s,
47 #undef _
48 };
49 
50 static u8 *
51 format_ip4_icmp_type_and_code (u8 * s, va_list * args)
52 {
53  icmp4_type_t type = va_arg (*args, int);
54  u8 code = va_arg (*args, int);
55  char *t = 0;
56 
57 #define _(n,f) case n: t = #f; break;
58 
59  switch (type)
60  {
62 
63  default:
64  break;
65  }
66 
67 #undef _
68 
69  if (!t)
70  return format (s, "unknown 0x%x", type);
71 
72  s = format (s, "%s", t);
73 
74  t = 0;
75  switch ((type << 8) | code)
76  {
77 #define _(a,n,f) case (ICMP4_##a << 8) | (n): t = #f; break;
78 
80 
81 #undef _
82  }
83 
84  if (t)
85  s = format (s, " %s", t);
86 
87  return s;
88 }
89 
90 static u8 *
91 format_ip4_icmp_header (u8 * s, va_list * args)
92 {
93  icmp46_header_t *icmp = va_arg (*args, icmp46_header_t *);
94  u32 max_header_bytes = va_arg (*args, u32);
95 
96  /* Nothing to do. */
97  if (max_header_bytes < sizeof (icmp[0]))
98  return format (s, "ICMP header truncated");
99 
100  s = format (s, "ICMP %U checksum 0x%x",
101  format_ip4_icmp_type_and_code, icmp->type, icmp->code,
102  clib_net_to_host_u16 (icmp->checksum));
103 
104  return s;
105 }
106 
107 static u8 *
108 format_icmp_input_trace (u8 * s, va_list * va)
109 {
110  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
111  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
112  icmp_input_trace_t *t = va_arg (*va, icmp_input_trace_t *);
113 
114  s = format (s, "%U",
115  format_ip4_header, t->packet_data, sizeof (t->packet_data));
116 
117  return s;
118 }
119 
120 typedef enum
121 {
125 
126 typedef struct
127 {
129 
131 
132  /* Vector dispatch table indexed by [icmp type]. */
133  u8 ip4_input_next_index_by_type[256];
134 } icmp4_main_t;
135 
137 
138 static uword
140  vlib_node_runtime_t * node, vlib_frame_t * frame)
141 {
142  icmp4_main_t *im = &icmp4_main;
143  uword n_packets = frame->n_vectors;
144  u32 *from, *to_next;
145  u32 n_left_from, n_left_to_next, next;
146 
147  from = vlib_frame_vector_args (frame);
148  n_left_from = n_packets;
149  next = node->cached_next_index;
150 
151  if (node->flags & VLIB_NODE_FLAG_TRACE)
152  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
153  /* stride */ 1,
154  sizeof (icmp_input_trace_t));
155 
156  while (n_left_from > 0)
157  {
158  vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
159 
160  while (n_left_from > 0 && n_left_to_next > 0)
161  {
162  vlib_buffer_t *p0;
163  ip4_header_t *ip0;
164  icmp46_header_t *icmp0;
165  icmp4_type_t type0;
166  u32 bi0, next0;
167 
168  if (PREDICT_TRUE (n_left_from > 2))
169  {
170  vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
171  p0 = vlib_get_buffer (vm, from[1]);
172  ip0 = vlib_buffer_get_current (p0);
174  }
175 
176  bi0 = to_next[0] = from[0];
177 
178  from += 1;
179  n_left_from -= 1;
180  to_next += 1;
181  n_left_to_next -= 1;
182 
183  p0 = vlib_get_buffer (vm, bi0);
184  ip0 = vlib_buffer_get_current (p0);
185  icmp0 = ip4_next_header (ip0);
186  type0 = icmp0->type;
187  next0 = im->ip4_input_next_index_by_type[type0];
188 
189  p0->error = node->errors[ICMP4_ERROR_UNKNOWN_TYPE];
190 
191  /* Verify speculative enqueue, maybe switch current next frame */
192  vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next,
193  n_left_to_next, bi0, next0);
194  }
195 
196  vlib_put_next_frame (vm, node, next, n_left_to_next);
197  }
198 
199  return frame->n_vectors;
200 }
201 
202 /* *INDENT-OFF* */
204  .function = ip4_icmp_input,
205  .name = "ip4-icmp-input",
206 
207  .vector_size = sizeof (u32),
208 
209  .format_trace = format_icmp_input_trace,
210 
211  .n_errors = ARRAY_LEN (icmp_error_strings),
212  .error_strings = icmp_error_strings,
213 
214  .n_next_nodes = 1,
215  .next_nodes = {
216  [ICMP_INPUT_NEXT_ERROR] = "ip4-punt",
217  },
218 };
219 /* *INDENT-ON* */
220 
221 static uword
223  vlib_node_runtime_t * node, vlib_frame_t * frame)
224 {
225  uword n_packets = frame->n_vectors;
226  u32 *from, *to_next;
227  u32 n_left_from, n_left_to_next, next;
228  ip4_main_t *i4m = &ip4_main;
229  u16 *fragment_ids, *fid;
230  u8 host_config_ttl = i4m->host_config.ttl;
231 
232  from = vlib_frame_vector_args (frame);
233  n_left_from = n_packets;
234  next = node->cached_next_index;
235 
236  if (node->flags & VLIB_NODE_FLAG_TRACE)
237  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
238  /* stride */ 1,
239  sizeof (icmp_input_trace_t));
240 
241  /* Get random fragment IDs for replies. */
242  fid = fragment_ids = clib_random_buffer_get_data (&vm->random_buffer,
243  n_packets *
244  sizeof (fragment_ids[0]));
245 
246  while (n_left_from > 0)
247  {
248  vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
249 
250  while (n_left_from > 2 && n_left_to_next > 2)
251  {
252  vlib_buffer_t *p0, *p1;
253  ip4_header_t *ip0, *ip1;
254  icmp46_header_t *icmp0, *icmp1;
255  u32 bi0, src0, dst0;
256  u32 bi1, src1, dst1;
257  ip_csum_t sum0, sum1;
258 
259  bi0 = to_next[0] = from[0];
260  bi1 = to_next[1] = from[1];
261 
262  from += 2;
263  n_left_from -= 2;
264  to_next += 2;
265  n_left_to_next -= 2;
266 
267  p0 = vlib_get_buffer (vm, bi0);
268  p1 = vlib_get_buffer (vm, bi1);
269  ip0 = vlib_buffer_get_current (p0);
270  ip1 = vlib_buffer_get_current (p1);
271  icmp0 = ip4_next_header (ip0);
272  icmp1 = ip4_next_header (ip1);
273 
274  vnet_buffer (p0)->sw_if_index[VLIB_RX] =
276  vnet_buffer (p1)->sw_if_index[VLIB_RX] =
278 
279  /* Update ICMP checksum. */
280  sum0 = icmp0->checksum;
281  sum1 = icmp1->checksum;
282 
283  ASSERT (icmp0->type == ICMP4_echo_request);
284  ASSERT (icmp1->type == ICMP4_echo_request);
285  sum0 = ip_csum_update (sum0, ICMP4_echo_request, ICMP4_echo_reply,
286  icmp46_header_t, type);
287  sum1 = ip_csum_update (sum1, ICMP4_echo_request, ICMP4_echo_reply,
288  icmp46_header_t, type);
289  icmp0->type = ICMP4_echo_reply;
290  icmp1->type = ICMP4_echo_reply;
291 
292  icmp0->checksum = ip_csum_fold (sum0);
293  icmp1->checksum = ip_csum_fold (sum1);
294 
295  src0 = ip0->src_address.data_u32;
296  src1 = ip1->src_address.data_u32;
297  dst0 = ip0->dst_address.data_u32;
298  dst1 = ip1->dst_address.data_u32;
299 
300  /* Swap source and destination address.
301  Does not change checksum. */
302  ip0->src_address.data_u32 = dst0;
303  ip1->src_address.data_u32 = dst1;
304  ip0->dst_address.data_u32 = src0;
305  ip1->dst_address.data_u32 = src1;
306 
307  /* Update IP checksum. */
308  sum0 = ip0->checksum;
309  sum1 = ip1->checksum;
310 
311  sum0 = ip_csum_update (sum0, ip0->ttl, host_config_ttl,
312  ip4_header_t, ttl);
313  sum1 = ip_csum_update (sum1, ip1->ttl, host_config_ttl,
314  ip4_header_t, ttl);
315  ip0->ttl = host_config_ttl;
316  ip1->ttl = host_config_ttl;
317 
318  /* New fragment id. */
319  sum0 = ip_csum_update (sum0, ip0->fragment_id, fid[0],
320  ip4_header_t, fragment_id);
321  sum1 = ip_csum_update (sum1, ip1->fragment_id, fid[1],
322  ip4_header_t, fragment_id);
323  ip0->fragment_id = fid[0];
324  ip1->fragment_id = fid[1];
325  fid += 2;
326 
327  ip0->checksum = ip_csum_fold (sum0);
328  ip1->checksum = ip_csum_fold (sum1);
329 
330  ASSERT (ip0->checksum == ip4_header_checksum (ip0));
331  ASSERT (ip1->checksum == ip4_header_checksum (ip1));
332 
333  p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
334  p1->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
335  }
336 
337  while (n_left_from > 0 && n_left_to_next > 0)
338  {
339  vlib_buffer_t *p0;
340  ip4_header_t *ip0;
341  icmp46_header_t *icmp0;
342  u32 bi0, src0, dst0;
343  ip_csum_t sum0;
344 
345  bi0 = to_next[0] = from[0];
346 
347  from += 1;
348  n_left_from -= 1;
349  to_next += 1;
350  n_left_to_next -= 1;
351 
352  p0 = vlib_get_buffer (vm, bi0);
353  ip0 = vlib_buffer_get_current (p0);
354  icmp0 = ip4_next_header (ip0);
355 
356  vnet_buffer (p0)->sw_if_index[VLIB_RX] =
358 
359  /* Update ICMP checksum. */
360  sum0 = icmp0->checksum;
361 
362  ASSERT (icmp0->type == ICMP4_echo_request);
363  sum0 = ip_csum_update (sum0, ICMP4_echo_request, ICMP4_echo_reply,
364  icmp46_header_t, type);
365  icmp0->type = ICMP4_echo_reply;
366  icmp0->checksum = ip_csum_fold (sum0);
367 
368  src0 = ip0->src_address.data_u32;
369  dst0 = ip0->dst_address.data_u32;
370  ip0->src_address.data_u32 = dst0;
371  ip0->dst_address.data_u32 = src0;
372 
373  /* Update IP checksum. */
374  sum0 = ip0->checksum;
375 
376  sum0 = ip_csum_update (sum0, ip0->ttl, host_config_ttl,
377  ip4_header_t, ttl);
378  ip0->ttl = host_config_ttl;
379 
380  sum0 = ip_csum_update (sum0, ip0->fragment_id, fid[0],
381  ip4_header_t, fragment_id);
382  ip0->fragment_id = fid[0];
383  fid += 1;
384 
385  ip0->checksum = ip_csum_fold (sum0);
386 
387  ASSERT (ip0->checksum == ip4_header_checksum (ip0));
388 
389  p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
390  }
391 
392  vlib_put_next_frame (vm, node, next, n_left_to_next);
393  }
394 
396  ICMP4_ERROR_ECHO_REPLIES_SENT, frame->n_vectors);
397 
398  return frame->n_vectors;
399 }
400 
401 /* *INDENT-OFF* */
403  .function = ip4_icmp_echo_request,
404  .name = "ip4-icmp-echo-request",
405 
406  .vector_size = sizeof (u32),
407 
408  .format_trace = format_icmp_input_trace,
409 
410  .n_next_nodes = 1,
411  .next_nodes = {
412  [0] = "ip4-load-balance",
413  },
414 };
415 /* *INDENT-ON* */
416 
417 typedef enum
418 {
423 
424 static u8
426 {
427  switch (type)
428  {
429  case ICMP4_destination_unreachable:
430  return ICMP4_ERROR_DEST_UNREACH_SENT;
431  case ICMP4_time_exceeded:
432  return ICMP4_ERROR_TTL_EXPIRE_SENT;
433  case ICMP4_parameter_problem:
434  return ICMP4_ERROR_PARAM_PROBLEM_SENT;
435  default:
436  return ICMP4_ERROR_DROP;
437  }
438 }
439 
440 static uword
442  vlib_node_runtime_t * node, vlib_frame_t * frame)
443 {
444  u32 *from, *to_next;
445  uword n_left_from, n_left_to_next;
446  ip4_icmp_error_next_t next_index;
447  ip4_main_t *im = &ip4_main;
448  ip_lookup_main_t *lm = &im->lookup_main;
449 
450  from = vlib_frame_vector_args (frame);
451  n_left_from = frame->n_vectors;
452  next_index = node->cached_next_index;
453 
454  if (node->flags & VLIB_NODE_FLAG_TRACE)
455  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
456  /* stride */ 1,
457  sizeof (icmp_input_trace_t));
458 
459  while (n_left_from > 0)
460  {
461  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
462 
463  while (n_left_from > 0 && n_left_to_next > 0)
464  {
465  /*
466  * Duplicate first buffer and free the original chain. Keep
467  * as much of the original packet as possible, within the
468  * minimum MTU. We chat "a little" here by keeping whatever
469  * is available in the first buffer.
470  */
471 
472  u32 pi0 = ~0;
473  u32 org_pi0 = from[0];
475  u8 error0 = ICMP4_ERROR_NONE;
476  vlib_buffer_t *p0, *org_p0;
477  ip4_header_t *ip0, *out_ip0;
478  icmp46_header_t *icmp0;
479  u32 sw_if_index0, if_add_index0;
480  ip_csum_t sum;
481 
482  org_p0 = vlib_get_buffer (vm, org_pi0);
483  p0 = vlib_buffer_copy_no_chain (vm, org_p0, &pi0);
484  if (!p0 || pi0 == ~0) /* Out of buffers */
485  continue;
486 
487  /* Speculatively enqueue p0 to the current next frame */
488  to_next[0] = pi0;
489  from += 1;
490  to_next += 1;
491  n_left_from -= 1;
492  n_left_to_next -= 1;
493 
494  ip0 = vlib_buffer_get_current (p0);
495  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
496 
497  /* Add IP header and ICMPv4 header including a 4 byte data field */
499  -sizeof (ip4_header_t) -
500  sizeof (icmp46_header_t) - 4);
501 
502  p0->current_length =
503  p0->current_length > 576 ? 576 : p0->current_length;
504  out_ip0 = vlib_buffer_get_current (p0);
505  icmp0 = (icmp46_header_t *) & out_ip0[1];
506 
507  /* Fill ip header fields */
508  out_ip0->ip_version_and_header_length = 0x45;
509  out_ip0->tos = 0;
510  out_ip0->length = clib_host_to_net_u16 (p0->current_length);
511  out_ip0->fragment_id = 0;
512  out_ip0->flags_and_fragment_offset = 0;
513  out_ip0->ttl = 0xff;
514  out_ip0->protocol = IP_PROTOCOL_ICMP;
515  out_ip0->dst_address = ip0->src_address;
516  if_add_index0 = ~0;
518  > sw_if_index0))
519  if_add_index0 =
520  lm->if_address_pool_index_by_sw_if_index[sw_if_index0];
521  if (PREDICT_TRUE (if_add_index0 != ~0))
522  {
523  ip_interface_address_t *if_add =
524  pool_elt_at_index (lm->if_address_pool, if_add_index0);
525  ip4_address_t *if_ip =
527  out_ip0->src_address = *if_ip;
528  }
529  else
530  {
531  /* interface has no IP4 address - should not happen */
532  next0 = IP4_ICMP_ERROR_NEXT_DROP;
533  error0 = ICMP4_ERROR_DROP;
534  }
535  out_ip0->checksum = ip4_header_checksum (out_ip0);
536 
537  /* Fill icmp header fields */
538  icmp0->type = vnet_buffer (p0)->ip.icmp.type;
539  icmp0->code = vnet_buffer (p0)->ip.icmp.code;
540  *((u32 *) (icmp0 + 1)) =
541  clib_host_to_net_u32 (vnet_buffer (p0)->ip.icmp.data);
542  icmp0->checksum = 0;
543  sum =
544  ip_incremental_checksum (0, icmp0,
545  p0->current_length -
546  sizeof (ip4_header_t));
547  icmp0->checksum = ~ip_csum_fold (sum);
548 
549  /* Update error status */
550  if (error0 == ICMP4_ERROR_NONE)
551  error0 = icmp4_icmp_type_to_error (icmp0->type);
552 
553  vlib_error_count (vm, node->node_index, error0, 1);
554 
555  /* Verify speculative enqueue, maybe switch current next frame */
556  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
557  to_next, n_left_to_next,
558  pi0, next0);
559  }
560  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
561  }
562 
563  /*
564  * push the original buffers to error-drop, so that
565  * they can get the error counters handled, then freed
566  */
568  vlib_frame_vector_args (frame),
570  frame->n_vectors);
571 
572  return frame->n_vectors;
573 }
574 
575 /* *INDENT-OFF* */
577  .function = ip4_icmp_error,
578  .name = "ip4-icmp-error",
579  .vector_size = sizeof (u32),
580 
581  .n_errors = ARRAY_LEN (icmp_error_strings),
582  .error_strings = icmp_error_strings,
583 
584  .n_next_nodes = IP4_ICMP_ERROR_N_NEXT,
585  .next_nodes = {
586  [IP4_ICMP_ERROR_NEXT_DROP] = "ip4-drop",
587  [IP4_ICMP_ERROR_NEXT_LOOKUP] = "ip4-lookup",
588  },
589 
590  .format_trace = format_icmp_input_trace,
591 };
592 /* *INDENT-ON* */
593 
594 
595 static uword
597 {
598  icmp46_header_t *h = va_arg (*args, icmp46_header_t *);
600  u32 i;
601 
603  cm->type_and_code_by_name, &i))
604  {
605  h->type = (i >> 8) & 0xff;
606  h->code = (i >> 0) & 0xff;
607  }
609  cm->type_by_name, &i))
610  {
611  h->type = i;
612  h->code = 0;
613  }
614  else
615  return 0;
616 
617  return 1;
618 }
619 
620 static void
622  pg_stream_t * s,
623  pg_edit_group_t * g, u32 * packets, u32 n_packets)
624 {
626  u32 ip_offset, icmp_offset;
627 
628  icmp_offset = g->start_byte_offset;
629  ip_offset = (g - 1)->start_byte_offset;
630 
631  while (n_packets >= 1)
632  {
633  vlib_buffer_t *p0;
634  ip4_header_t *ip0;
635  icmp46_header_t *icmp0;
636  u32 len0;
637 
638  p0 = vlib_get_buffer (vm, packets[0]);
639  n_packets -= 1;
640  packets += 1;
641 
642  ASSERT (p0->current_data == 0);
643  ip0 = (void *) (p0->data + ip_offset);
644  icmp0 = (void *) (p0->data + icmp_offset);
645 
646  /* if IP length has been specified, then calculate the length based on buffer */
647  if (ip0->length == 0)
648  len0 = vlib_buffer_length_in_chain (vm, p0) - icmp_offset;
649  else
650  len0 = clib_net_to_host_u16 (ip0->length) - icmp_offset;
651 
652  icmp0->checksum =
653  ~ip_csum_fold (ip_incremental_checksum (0, icmp0, len0));
654  }
655 }
656 
657 typedef struct
658 {
662 
663 always_inline void
665 {
666  /* Initialize fields that are not bit fields in the IP header. */
667 #define _(f) pg_edit_init (&p->f, icmp46_header_t, f);
668  _(type);
669  _(code);
670  _(checksum);
671 #undef _
672 }
673 
674 static uword
675 unformat_pg_icmp_header (unformat_input_t * input, va_list * args)
676 {
677  pg_stream_t *s = va_arg (*args, pg_stream_t *);
679  u32 group_index;
680 
681  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (icmp46_header_t),
682  &group_index);
684 
686 
687  {
688  icmp46_header_t tmp;
689 
690  if (!unformat (input, "ICMP %U", unformat_icmp_type_and_code, &tmp))
691  goto error;
692 
693  pg_edit_set_fixed (&p->type, tmp.type);
694  pg_edit_set_fixed (&p->code, tmp.code);
695  }
696 
697  /* Parse options. */
698  while (1)
699  {
700  if (unformat (input, "checksum %U",
702  ;
703 
704  /* Can't parse input: try next protocol level. */
705  else
706  break;
707  }
708 
709  if (!unformat_user (input, unformat_pg_payload, s))
710  goto error;
711 
713  {
714  pg_edit_group_t *g = pg_stream_get_group (s, group_index);
716  g->edit_function_opaque = 0;
717  }
718 
719  return 1;
720 
721 error:
722  /* Free up any edits we may have added. */
723  pg_free_edit_group (s);
724  return 0;
725 }
726 
727 void
729 {
730  icmp4_main_t *im = &icmp4_main;
731  u32 old_next_index;
732 
733  ASSERT ((int) type < ARRAY_LEN (im->ip4_input_next_index_by_type));
734  old_next_index = im->ip4_input_next_index_by_type[type];
735 
737  = vlib_node_add_next (vm, ip4_icmp_input_node.index, node_index);
738 
739  if (old_next_index &&
740  (old_next_index != im->ip4_input_next_index_by_type[type]))
741  clib_warning ("WARNING: changed next_by_type[%d]", (int) type);
742 }
743 
744 static clib_error_t *
746 {
747  ip_main_t *im = &ip_main;
748  ip_protocol_info_t *pi;
750  clib_error_t *error;
751 
753 
754  if (error)
755  return error;
756 
757  pi = ip_get_protocol_info (im, IP_PROTOCOL_ICMP);
760 
761  cm->type_by_name = hash_create_string (0, sizeof (uword));
762 #define _(n,t) hash_set_mem (cm->type_by_name, #t, (n));
764 #undef _
765 
766  cm->type_and_code_by_name = hash_create_string (0, sizeof (uword));
767 #define _(a,n,t) hash_set_mem (cm->type_by_name, #t, (n) | (ICMP4_##a << 8));
769 #undef _
770 
773  sizeof (cm->ip4_input_next_index_by_type));
774 
775  ip4_icmp_register_type (vm, ICMP4_echo_request,
777 
778  return 0;
779 }
780 
782 
783 /*
784  * fd.io coding-style-patch-verification: ON
785  *
786  * Local Variables:
787  * eval: (c-set-style "gnu")
788  * End:
789  */
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
Definition: edit.h:64
ip4_icmp_error_next_t
Definition: icmp4.c:417
static uword ip4_icmp_error(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: icmp4.c:441
#define CLIB_UNUSED(x)
Definition: clib.h:82
ip4_address_t src_address
Definition: ip4_packet.h:170
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:143
static u8 * format_icmp_input_trace(u8 *s, va_list *va)
Definition: icmp4.c:108
Definition: pg.h:318
static void pg_edit_set_fixed(pg_edit_t *e, u64 value)
Definition: edit.h:153
format_function_t format_ip4_header
Definition: format.h:83
#define PREDICT_TRUE(x)
Definition: clib.h:112
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:110
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static void * clib_random_buffer_get_data(clib_random_buffer_t *b, uword n_bytes)
Definition: random_buffer.h:78
void(* edit_function)(struct pg_main_t *pg, struct pg_stream_t *s, struct pg_edit_group_t *g, u32 *buffers, u32 n_buffers)
Definition: pg.h:73
static char * icmp_error_strings[]
Definition: icmp4.c:44
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
u8 data[0]
Packet data.
Definition: buffer.h:181
int i
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
uword unformat_pg_edit(unformat_input_t *input, va_list *args)
Definition: edit.c:106
ip_lookup_main_t lookup_main
Definition: ip4.h:107
uword ip_csum_t
Definition: ip_packet.h:219
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u16 flags_and_fragment_offset
Definition: ip4_packet.h:151
Definition: ip.h:107
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:366
pg_edit_t code
Definition: icmp4.c:659
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1092
unsigned char u8
Definition: types.h:56
u32 start_byte_offset
Definition: pg.h:67
static pg_edit_group_t * pg_stream_get_group(pg_stream_t *s, u32 group_index)
Definition: pg.h:225
unformat_function_t * unformat_pg_edit
Definition: ip.h:88
#define vlib_prefetch_buffer_with_index(vm, bi, type)
Prefetch buffer metadata by buffer index The first 64 bytes of buffer contains most header informatio...
Definition: buffer_funcs.h:440
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
u32 local_interface_sw_if_index
Definition: vnet.h:54
#define always_inline
Definition: clib.h:98
static uword unformat_icmp_type_and_code(unformat_input_t *input, va_list *args)
Definition: icmp4.c:596
ip4_address_t dst_address
Definition: ip4_packet.h:170
struct ip4_main_t::@214 host_config
Template information for VPP generated packets.
uword unformat_pg_payload(unformat_input_t *input, va_list *args)
Definition: edit.c:127
pg_edit_type_t type
Definition: edit.h:66
static_always_inline void vlib_buffer_enqueue_to_single_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 next_index, u32 count)
Definition: buffer_node.h:452
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
static void * pg_create_edit_group(pg_stream_t *s, int n_edit_bytes, int n_packet_bytes, u32 *group_index)
Definition: pg.h:231
#define vlib_call_init_function(vm, x)
Definition: init.h:270
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
void ip4_icmp_register_type(vlib_main_t *vm, icmp4_type_t type, u32 node_index)
Definition: icmp4.c:728
static clib_error_t * icmp4_init(vlib_main_t *vm)
Definition: icmp4.c:745
vnet_crypto_main_t * cm
Definition: quic_crypto.c:41
static vlib_buffer_t * vlib_buffer_copy_no_chain(vlib_main_t *vm, vlib_buffer_t *b, u32 *di)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:134
pg_edit_t type
Definition: icmp4.c:659
format_function_t * format_header
Definition: ip.h:79
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
static uword unformat_pg_icmp_header(unformat_input_t *input, va_list *args)
Definition: icmp4.c:675
vnet_main_t vnet_main
Definition: misc.c:43
static u8 * format_ip4_icmp_type_and_code(u8 *s, va_list *args)
Definition: icmp4.c:51
u32 node_index
Node index.
Definition: node.h:496
icmp4_main_t icmp4_main
Definition: icmp4.c:136
#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:338
static void icmp4_pg_edit_function(pg_main_t *pg, pg_stream_t *s, pg_edit_group_t *g, u32 *packets, u32 n_packets)
Definition: icmp4.c:621
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
u16 n_vectors
Definition: node.h:397
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
vlib_main_t * vm
Definition: buffer.c:323
ip_main_t ip_main
Definition: ip_init.c:42
static u8 * format_ip4_icmp_header(u8 *s, va_list *args)
Definition: icmp4.c:91
u8 ttl
Definition: fib_types.api:26
#define clib_warning(format, args...)
Definition: error.h:59
uword * type_by_name
Definition: icmp4.c:130
uword * type_and_code_by_name
Definition: icmp4.c:128
icmp4_type_t
icmp_input_next_t
Definition: icmp4.c:120
#define ARRAY_LEN(x)
Definition: clib.h:62
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:456
static uword ip4_icmp_echo_request(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: icmp4.c:222
pg_edit_t checksum
Definition: icmp4.c:660
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:150
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
#define ASSERT(truth)
static vlib_node_registration_t ip4_icmp_echo_request_node
(constructor) VLIB_REGISTER_NODE (ip4_icmp_echo_request_node)
Definition: icmp4.c:402
ip_dscp_t tos
Definition: ip4_packet.h:141
IPv4 main type.
Definition: ip4.h:105
uword unformat_vlib_number_by_name(unformat_input_t *input, va_list *args)
Definition: format.c:157
static void pg_free_edit_group(pg_stream_t *s)
Definition: pg.h:284
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:248
uword edit_function_opaque
Definition: pg.h:79
Definition: pg.h:94
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:47
#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
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:269
vlib_node_registration_t ip4_icmp_error_node
(constructor) VLIB_REGISTER_NODE (ip4_icmp_error_node)
Definition: icmp4.c:576
uword unformat_pg_number(unformat_input_t *input, va_list *args)
Definition: edit.c:85
static vlib_node_registration_t ip4_icmp_input_node
(constructor) VLIB_REGISTER_NODE (ip4_icmp_input_node)
Definition: icmp4.c:203
#define vnet_buffer(b)
Definition: buffer.h:365
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1076
u8 ip4_input_next_index_by_type[256]
Definition: icmp4.c:133
u16 flags
Copy of main node flags.
Definition: node.h:509
u8 packet_data[64]
Definition: icmp4.h:43
u8 ip_version_and_header_length
Definition: ip4_packet.h:138
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:199
static uword ip4_icmp_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: icmp4.c:139
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
static u8 icmp4_icmp_type_to_error(u8 type)
Definition: icmp4.c:425
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
static void pg_icmp_header_init(pg_icmp46_header_t *p)
Definition: icmp4.c:664
u8 ttl
TTL to use for host generated packets.
Definition: ip4.h:158
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:293
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 u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:247
clib_random_buffer_t random_buffer
Definition: main.h:212
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:275
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
Definition: defs.h:46