FD.io VPP  v16.12-rc0-308-g931be3a
Vector Packet Processing
icmp6.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/icmp6.c: ip6 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 u8 * format_ip6_icmp_type_and_code (u8 * s, va_list * args)
45 {
46  icmp6_type_t type = va_arg (*args, int);
47  u8 code = va_arg (*args, int);
48  char * t = 0;
49 
50 #define _(n,f) case n: t = #f; break;
51 
52  switch (type)
53  {
55 
56  default:
57  break;
58  }
59 
60 #undef _
61 
62  if (! t)
63  return format (s, "unknown 0x%x", type);
64 
65  s = format (s, "%s", t);
66 
67  t = 0;
68  switch ((type << 8) | code)
69  {
70 #define _(a,n,f) case (ICMP6_##a << 8) | (n): t = #f; break;
71 
73 
74 #undef _
75  }
76 
77  if (t)
78  s = format (s, " %s", t);
79 
80  return s;
81 }
82 
83 static u8 * format_icmp6_header (u8 * s, va_list * args)
84 {
85  icmp46_header_t * icmp = va_arg (*args, icmp46_header_t *);
86  u32 max_header_bytes = va_arg (*args, u32);
87 
88  /* Nothing to do. */
89  if (max_header_bytes < sizeof (icmp[0]))
90  return format (s, "ICMP header truncated");
91 
92  s = format (s, "ICMP %U checksum 0x%x",
93  format_ip6_icmp_type_and_code, icmp->type, icmp->code,
94  clib_net_to_host_u16 (icmp->checksum));
95 
96  if (max_header_bytes >=
97  sizeof(icmp6_neighbor_solicitation_or_advertisement_header_t) &&
98  (icmp->type == ICMP6_neighbor_solicitation ||
99  icmp->type == ICMP6_neighbor_advertisement))
100  {
101  icmp6_neighbor_solicitation_or_advertisement_header_t *icmp6_nd =
102  (icmp6_neighbor_solicitation_or_advertisement_header_t *) icmp;
103  s = format (s, "\n target address %U",
104  format_ip6_address, &icmp6_nd->target_address);
105  }
106 
107  return s;
108 }
109 
110 u8 * format_icmp6_input_trace (u8 * s, va_list * va)
111 {
112  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
113  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
114  icmp6_input_trace_t * t = va_arg (*va, icmp6_input_trace_t *);
115 
116  s = format (s, "%U",
118  t->packet_data, sizeof (t->packet_data));
119 
120  return s;
121 }
122 
123 static char * icmp_error_strings[] = {
124 #define _(f,s) s,
126 #undef _
127 };
128 
129 typedef enum {
133 
134 typedef struct {
136 
138 
139  /* Vector dispatch table indexed by [icmp type]. */
140  u8 input_next_index_by_type[256];
141 
142  /* Max valid code indexed by icmp type. */
143  u8 max_valid_code_by_type[256];
144 
145  /* hop_limit must be >= this value for this icmp type. */
146  u8 min_valid_hop_limit_by_type[256];
147 
148  u8 min_valid_length_by_type[256];
149 } icmp6_main_t;
150 
152 
153 static uword
155  vlib_node_runtime_t * node,
156  vlib_frame_t * frame)
157 {
158  icmp6_main_t * im = &icmp6_main;
159  u32 * from, * to_next;
160  u32 n_left_from, n_left_to_next, next_index;
161 
162  from = vlib_frame_vector_args (frame);
163  n_left_from = frame->n_vectors;
164  next_index = node->cached_next_index;
165 
166  if (node->flags & VLIB_NODE_FLAG_TRACE)
167  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
168  /* stride */ 1,
169  sizeof (icmp6_input_trace_t));
170 
171  while (n_left_from > 0)
172  {
173  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
174 
175  while (n_left_from > 0 && n_left_to_next > 0)
176  {
177  vlib_buffer_t * b0;
178  ip6_header_t * ip0;
179  icmp46_header_t * icmp0;
180  icmp6_type_t type0;
181  u32 bi0, next0, error0, len0;
182 
183  bi0 = to_next[0] = from[0];
184 
185  from += 1;
186  n_left_from -= 1;
187  to_next += 1;
188  n_left_to_next -= 1;
189 
190  b0 = vlib_get_buffer (vm, bi0);
191  ip0 = vlib_buffer_get_current (b0);
192  icmp0 = ip6_next_header (ip0);
193  type0 = icmp0->type;
194 
195  error0 = ICMP6_ERROR_NONE;
196 
197  next0 = im->input_next_index_by_type[type0];
198  error0 = next0 == ICMP_INPUT_NEXT_DROP ? ICMP6_ERROR_UNKNOWN_TYPE : error0;
199 
200  /* Check code is valid for type. */
201  error0 = icmp0->code > im->max_valid_code_by_type[type0] ? ICMP6_ERROR_INVALID_CODE_FOR_TYPE : error0;
202 
203  /* Checksum is already validated by ip6_local node so we don't need to check that. */
204 
205  /* Check that hop limit == 255 for certain types. */
206  error0 = ip0->hop_limit < im->min_valid_hop_limit_by_type[type0] ? ICMP6_ERROR_INVALID_HOP_LIMIT_FOR_TYPE : error0;
207 
208  len0 = clib_net_to_host_u16 (ip0->payload_length);
209  error0 = len0 < im->min_valid_length_by_type[type0] ? ICMP6_ERROR_LENGTH_TOO_SMALL_FOR_TYPE : error0;
210 
211  b0->error = node->errors[error0];
212 
213  next0 = error0 != ICMP6_ERROR_NONE ? ICMP_INPUT_NEXT_DROP : next0;
214 
215  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
216  to_next, n_left_to_next,
217  bi0, next0);
218  }
219 
220  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
221  }
222 
223  return frame->n_vectors;
224 }
225 
227  .function = ip6_icmp_input,
228  .name = "ip6-icmp-input",
229 
230  .vector_size = sizeof (u32),
231 
232  .format_trace = format_icmp6_input_trace,
233 
234  .n_errors = ARRAY_LEN (icmp_error_strings),
235  .error_strings = icmp_error_strings,
236 
237  .n_next_nodes = 1,
238  .next_nodes = {
239  [ICMP_INPUT_NEXT_DROP] = "error-drop",
240  },
241 };
242 
243 typedef enum {
248 
249 static uword
251  vlib_node_runtime_t * node,
252  vlib_frame_t * frame)
253 {
254  u32 * from, * to_next;
255  u32 n_left_from, n_left_to_next, next_index;
256  ip6_main_t * im = &ip6_main;
257 
258  from = vlib_frame_vector_args (frame);
259  n_left_from = frame->n_vectors;
260  next_index = node->cached_next_index;
261 
262  if (node->flags & VLIB_NODE_FLAG_TRACE)
263  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
264  /* stride */ 1,
265  sizeof (icmp6_input_trace_t));
266 
267  while (n_left_from > 0)
268  {
269  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
270 
271  while (n_left_from > 2 && n_left_to_next > 2)
272  {
273  vlib_buffer_t * p0, * p1;
274  ip6_header_t * ip0, * ip1;
275  icmp46_header_t * icmp0, * icmp1;
276  ip6_address_t tmp0, tmp1;
277  ip_csum_t sum0, sum1;
278  u32 bi0, bi1;
279  u32 fib_index0, fib_index1;
282 
283  bi0 = to_next[0] = from[0];
284  bi1 = to_next[1] = from[1];
285 
286  from += 2;
287  n_left_from -= 2;
288  to_next += 2;
289  n_left_to_next -= 2;
290 
291  p0 = vlib_get_buffer (vm, bi0);
292  p1 = vlib_get_buffer (vm, bi1);
293  ip0 = vlib_buffer_get_current (p0);
294  ip1 = vlib_buffer_get_current (p1);
295  icmp0 = ip6_next_header (ip0);
296  icmp1 = ip6_next_header (ip1);
297 
298  /* Check icmp type to echo reply and update icmp checksum. */
299  sum0 = icmp0->checksum;
300  sum1 = icmp1->checksum;
301 
302  ASSERT (icmp0->type == ICMP6_echo_request);
303  ASSERT (icmp1->type == ICMP6_echo_request);
304  sum0 = ip_csum_update (sum0, ICMP6_echo_request, ICMP6_echo_reply,
305  icmp46_header_t, type);
306  sum1 = ip_csum_update (sum1, ICMP6_echo_request, ICMP6_echo_reply,
307  icmp46_header_t, type);
308 
309  icmp0->checksum = ip_csum_fold (sum0);
310  icmp1->checksum = ip_csum_fold (sum1);
311 
312  icmp0->type = ICMP6_echo_reply;
313  icmp1->type = ICMP6_echo_reply;
314 
315  /* Swap source and destination address. */
316  tmp0 = ip0->src_address;
317  tmp1 = ip1->src_address;
318 
319  ip0->src_address = ip0->dst_address;
320  ip1->src_address = ip1->dst_address;
321 
322  ip0->dst_address = tmp0;
323  ip1->dst_address = tmp1;
324 
325  /* New hop count. */
326  ip0->hop_limit = im->host_config.ttl;
327  ip1->hop_limit = im->host_config.ttl;
328 
330  {
331  ethernet_header_t *eth0;
332  u8 tmp_mac[6];
333  /* For link local, reuse current MAC header by sawpping
334  * SMAC to DMAC instead of IP6 lookup since link local
335  * is not in the IP6 FIB */
336  vlib_buffer_reset (p0);
337  eth0 = vlib_buffer_get_current (p0);
338  clib_memcpy (tmp_mac, eth0->dst_address, 6);
339  clib_memcpy (eth0->dst_address, eth0->src_address, 6);
340  clib_memcpy (eth0->src_address, tmp_mac, 6);
341  vnet_buffer(p0)->sw_if_index[VLIB_TX] =
342  vnet_buffer (p0)->sw_if_index[VLIB_RX];
344  }
345  else
346  {
347  /* Determine the correct lookup fib indices... */
348  fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
349  vnet_buffer (p0)->sw_if_index[VLIB_RX]);
350  vnet_buffer (p0)->sw_if_index[VLIB_TX] = fib_index0;
351  }
352 
354  {
355  ethernet_header_t *eth1;
356  u8 tmp_mac[6];
357  /* For link local, reuse current MAC header by sawpping
358  * SMAC to DMAC instead of IP6 lookup since link local
359  * is not in the IP6 FIB */
360  vlib_buffer_reset (p1);
361  eth1 = vlib_buffer_get_current (p1);
362  clib_memcpy (tmp_mac, eth1->dst_address, 6);
363  clib_memcpy (eth1->dst_address, eth1->src_address, 6);
364  clib_memcpy (eth1->src_address, tmp_mac, 6);
365  vnet_buffer(p1)->sw_if_index[VLIB_TX] =
366  vnet_buffer (p1)->sw_if_index[VLIB_RX];
368  }
369  else
370  {
371  /* Determine the correct lookup fib indices... */
372  fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
373  vnet_buffer (p1)->sw_if_index[VLIB_RX]);
374  vnet_buffer (p1)->sw_if_index[VLIB_TX] = fib_index1;
375  }
376 
377  vnet_buffer (p0)->sw_if_index[VLIB_RX]
379  vnet_buffer (p1)->sw_if_index[VLIB_RX]
381 
382  /* verify speculative enqueues, maybe switch current next frame */
383  /* if next0==next1==next_index then nothing special needs to be done */
384  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
385  to_next, n_left_to_next,
386  bi0, bi1, next0, next1);
387  }
388 
389  while (n_left_from > 0 && n_left_to_next > 0)
390  {
391  vlib_buffer_t * p0;
392  ip6_header_t * ip0;
393  icmp46_header_t * icmp0;
394  u32 bi0;
395  ip6_address_t tmp0;
396  ip_csum_t sum0;
397  u32 fib_index0;
399 
400  bi0 = to_next[0] = from[0];
401 
402  from += 1;
403  n_left_from -= 1;
404  to_next += 1;
405  n_left_to_next -= 1;
406 
407  p0 = vlib_get_buffer (vm, bi0);
408  ip0 = vlib_buffer_get_current (p0);
409  icmp0 = ip6_next_header (ip0);
410 
411  /* Check icmp type to echo reply and update icmp checksum. */
412  sum0 = icmp0->checksum;
413 
414  ASSERT (icmp0->type == ICMP6_echo_request);
415  sum0 = ip_csum_update (sum0, ICMP6_echo_request, ICMP6_echo_reply,
416  icmp46_header_t, type);
417 
418  icmp0->checksum = ip_csum_fold (sum0);
419 
420  icmp0->type = ICMP6_echo_reply;
421 
422  /* Swap source and destination address. */
423  tmp0 = ip0->src_address;
424  ip0->src_address = ip0->dst_address;
425  ip0->dst_address = tmp0;
426 
427  ip0->hop_limit = im->host_config.ttl;
428 
430  {
431  ethernet_header_t *eth0;
432  u8 tmp_mac[6];
433  /* For link local, reuse current MAC header by sawpping
434  * SMAC to DMAC instead of IP6 lookup since link local
435  * is not in the IP6 FIB */
436  vlib_buffer_reset (p0);
437  eth0 = vlib_buffer_get_current (p0);
438  clib_memcpy (tmp_mac, eth0->dst_address, 6);
439  clib_memcpy (eth0->dst_address, eth0->src_address, 6);
440  clib_memcpy (eth0->src_address, tmp_mac, 6);
441  vnet_buffer(p0)->sw_if_index[VLIB_TX] =
442  vnet_buffer (p0)->sw_if_index[VLIB_RX];
444  }
445  else
446  {
447  fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
448  vnet_buffer (p0)->sw_if_index[VLIB_RX]);
449  vnet_buffer (p0)->sw_if_index[VLIB_TX] = fib_index0;
450  }
451  vnet_buffer (p0)->sw_if_index[VLIB_RX]
453 
454  /* Verify speculative enqueue, maybe switch current next frame */
455  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
456  to_next, n_left_to_next,
457  bi0, next0);
458  }
459 
460  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
461  }
462 
464  ICMP6_ERROR_ECHO_REPLIES_SENT,
465  frame->n_vectors);
466 
467  return frame->n_vectors;
468 }
469 
471  .function = ip6_icmp_echo_request,
472  .name = "ip6-icmp-echo-request",
473 
474  .vector_size = sizeof (u32),
475 
476  .format_trace = format_icmp6_input_trace,
477 
478  .n_next_nodes = ICMP6_ECHO_REQUEST_N_NEXT,
479  .next_nodes = {
480  [ICMP6_ECHO_REQUEST_NEXT_LOOKUP] = "ip6-lookup",
481  [ICMP6_ECHO_REQUEST_NEXT_OUTPUT] = "interface-output",
482  },
483 };
484 
485 typedef enum {
490 
491 void
493 {
494  vnet_buffer(b)->ip.icmp.type = type;
495  vnet_buffer(b)->ip.icmp.code = code;
496  vnet_buffer(b)->ip.icmp.data = data;
497 }
498 
499 static u8
501 {
502  switch (type) {
503  case ICMP6_destination_unreachable:
504  return ICMP6_ERROR_DEST_UNREACH_SENT;
505  case ICMP6_packet_too_big:
506  return ICMP6_ERROR_PACKET_TOO_BIG_SENT;
507  case ICMP6_time_exceeded:
508  return ICMP6_ERROR_TTL_EXPIRE_SENT;
509  case ICMP6_parameter_problem:
510  return ICMP6_ERROR_PARAM_PROBLEM_SENT;
511  default:
512  return ICMP6_ERROR_DROP;
513  }
514 }
515 
516 static uword
518  vlib_node_runtime_t * node,
519  vlib_frame_t * frame)
520 {
521  u32 * from, * to_next;
522  uword n_left_from, n_left_to_next;
523  ip6_icmp_error_next_t next_index;
524  ip6_main_t *im = &ip6_main;
525  ip_lookup_main_t * lm = &im->lookup_main;
526 
527  from = vlib_frame_vector_args(frame);
528  n_left_from = frame->n_vectors;
529  next_index = node->cached_next_index;
530 
531  if (node->flags & VLIB_NODE_FLAG_TRACE)
532  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
533  /* stride */ 1, sizeof (icmp6_input_trace_t));
534 
535  while (n_left_from > 0)
536  {
537  vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
538 
539  while (n_left_from > 0 && n_left_to_next > 0)
540  {
541  u32 pi0 = from[0];
543  u8 error0 = ICMP6_ERROR_NONE;
544  vlib_buffer_t * p0;
545  ip6_header_t * ip0, * out_ip0;
546  icmp46_header_t * icmp0;
547  u32 sw_if_index0, if_add_index0;
548  int bogus_length;
549 
550  /* Speculatively enqueue p0 to the current next frame */
551  to_next[0] = pi0;
552  from += 1;
553  to_next += 1;
554  n_left_from -= 1;
555  n_left_to_next -= 1;
556 
557  p0 = vlib_get_buffer(vm, pi0);
558  ip0 = vlib_buffer_get_current(p0);
559  sw_if_index0 = vnet_buffer(p0)->sw_if_index[VLIB_RX];
560 
561  /* RFC4443 says to keep as much of the original packet as possible
562  * within the minimum MTU. We cheat "a little" here by keeping whatever fits
563  * in the first buffer, to be more efficient */
565  { /* clear current_length of all other buffers in chain */
566  vlib_buffer_t *b = p0;
568  while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
569  {
570  b = vlib_get_buffer (vm, b->next_buffer);
571  b->current_length = 0;
572  }
573  }
574  p0->current_length = p0->current_length > 1280 ? 1280 : p0->current_length;
575 
576  /* Add IP header and ICMPv6 header including a 4 byte data field */
578  -sizeof(ip6_header_t)-sizeof(icmp46_header_t)-4);
579  out_ip0 = vlib_buffer_get_current(p0);
580  icmp0 = (icmp46_header_t *) &out_ip0[1];
581 
582  /* Fill ip header fields */
584  clib_host_to_net_u32(0x6<<28);
585 
586  out_ip0->payload_length = clib_host_to_net_u16(p0->current_length - sizeof(ip6_header_t));
587  out_ip0->protocol = IP_PROTOCOL_ICMP6;
588  out_ip0->hop_limit = 0xff;
589  out_ip0->dst_address = ip0->src_address;
590  if_add_index0 =
591  lm->if_address_pool_index_by_sw_if_index[sw_if_index0];
592  if (PREDICT_TRUE(if_add_index0 != ~0))
593  {
594  ip_interface_address_t *if_add =
595  pool_elt_at_index(lm->if_address_pool, if_add_index0);
596  ip6_address_t *if_ip =
598  out_ip0->src_address = *if_ip;
599  }
600  else /* interface has no IP6 address - should not happen */
601  {
602  next0 = IP6_ICMP_ERROR_NEXT_DROP;
603  error0 = ICMP6_ERROR_DROP;
604  }
605 
606  /* Fill icmp header fields */
607  icmp0->type = vnet_buffer(p0)->ip.icmp.type;
608  icmp0->code = vnet_buffer(p0)->ip.icmp.code;
609  *((u32 *)(icmp0 + 1)) = clib_host_to_net_u32(vnet_buffer(p0)->ip.icmp.data);
610  icmp0->checksum = 0;
611  icmp0->checksum = ip6_tcp_udp_icmp_compute_checksum(
612  vm, p0, out_ip0, &bogus_length);
613 
614 
615 
616  /* Update error status */
617  if (error0 == ICMP6_ERROR_NONE)
618  error0 = icmp6_icmp_type_to_error(icmp0->type);
619  vlib_error_count(vm, node->node_index, error0, 1);
620 
621  /* Verify speculative enqueue, maybe switch current next frame */
622  vlib_validate_buffer_enqueue_x1(vm, node, next_index,
623  to_next, n_left_to_next,
624  pi0, next0);
625  }
626  vlib_put_next_frame(vm, node, next_index, n_left_to_next);
627  }
628 
629  return frame->n_vectors;
630 }
631 
633  .function = ip6_icmp_error,
634  .name = "ip6-icmp-error",
635  .vector_size = sizeof (u32),
636 
637  .n_errors = ARRAY_LEN (icmp_error_strings),
638  .error_strings = icmp_error_strings,
639 
640  .n_next_nodes = IP6_ICMP_ERROR_N_NEXT,
641  .next_nodes = {
642  [IP6_ICMP_ERROR_NEXT_DROP] = "error-drop",
643  [IP6_ICMP_ERROR_NEXT_LOOKUP] = "ip6-lookup",
644  },
645 
646  .format_trace = format_icmp6_input_trace,
647 };
648 
649 
650 static uword unformat_icmp_type_and_code (unformat_input_t * input, va_list * args)
651 {
652  icmp46_header_t * h = va_arg (*args, icmp46_header_t *);
653  icmp6_main_t * cm = &icmp6_main;
654  u32 i;
655 
657  cm->type_and_code_by_name, &i))
658  {
659  h->type = (i >> 8) & 0xff;
660  h->code = (i >> 0) & 0xff;
661  }
663  cm->type_by_name, &i))
664  {
665  h->type = i;
666  h->code = 0;
667  }
668  else
669  return 0;
670 
671  return 1;
672 }
673 
674 static void
676  pg_stream_t * s,
677  pg_edit_group_t * g,
678  u32 * packets,
679  u32 n_packets)
680 {
681  vlib_main_t * vm = pg->vlib_main;
682  u32 ip_offset, icmp_offset;
683  int bogus_length;
684 
685  icmp_offset = g->start_byte_offset;
686  ip_offset = (g-1)->start_byte_offset;
687 
688  while (n_packets >= 1)
689  {
690  vlib_buffer_t * p0;
691  ip6_header_t * ip0;
692  icmp46_header_t * icmp0;
693 
694  p0 = vlib_get_buffer (vm, packets[0]);
695  n_packets -= 1;
696  packets += 1;
697 
698  ASSERT (p0->current_data == 0);
699  ip0 = (void *) (p0->data + ip_offset);
700  icmp0 = (void *) (p0->data + icmp_offset);
701 
702  icmp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
703  &bogus_length);
704  ASSERT (bogus_length == 0);
705  }
706 }
707 
708 typedef struct {
709  pg_edit_t type, code;
710  pg_edit_t checksum;
712 
713 always_inline void
715 {
716  /* Initialize fields that are not bit fields in the IP header. */
717 #define _(f) pg_edit_init (&p->f, icmp46_header_t, f);
718  _ (type);
719  _ (code);
720  _ (checksum);
721 #undef _
722 }
723 
724 static uword
725 unformat_pg_icmp_header (unformat_input_t * input, va_list * args)
726 {
727  pg_stream_t * s = va_arg (*args, pg_stream_t *);
728  pg_icmp46_header_t * p;
729  u32 group_index;
730 
731  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (icmp46_header_t),
732  &group_index);
734 
736 
737  {
738  icmp46_header_t tmp;
739 
740  if (! unformat (input, "ICMP %U", unformat_icmp_type_and_code, &tmp))
741  goto error;
742 
743  pg_edit_set_fixed (&p->type, tmp.type);
744  pg_edit_set_fixed (&p->code, tmp.code);
745  }
746 
747  /* Parse options. */
748  while (1)
749  {
750  if (unformat (input, "checksum %U",
753  ;
754 
755  /* Can't parse input: try next protocol level. */
756  else
757  break;
758  }
759 
760  if (! unformat_user (input, unformat_pg_payload, s))
761  goto error;
762 
764  {
765  pg_edit_group_t * g = pg_stream_get_group (s, group_index);
767  g->edit_function_opaque = 0;
768  }
769 
770  return 1;
771 
772  error:
773  /* Free up any edits we may have added. */
774  pg_free_edit_group (s);
775  return 0;
776 }
777 
779 {
780  icmp6_main_t * im = &icmp6_main;
781 
782  ASSERT ((int) type < ARRAY_LEN (im->input_next_index_by_type));
784  = vlib_node_add_next (vm, ip6_icmp_input_node.index, node_index);
785 }
786 
787 static clib_error_t *
789 {
790  ip_main_t * im = &ip_main;
791  ip_protocol_info_t * pi;
792  icmp6_main_t * cm = &icmp6_main;
793  clib_error_t * error;
794 
796 
797  if (error)
798  return error;
799 
800  pi = ip_get_protocol_info (im, IP_PROTOCOL_ICMP6);
803 
804  cm->type_by_name = hash_create_string (0, sizeof (uword));
805 #define _(n,t) hash_set_mem (cm->type_by_name, #t, (n));
807 #undef _
808 
809  cm->type_and_code_by_name = hash_create_string (0, sizeof (uword));
810 #define _(a,n,t) hash_set_mem (cm->type_by_name, #t, (n) | (ICMP6_##a << 8));
812 #undef _
813 
814  memset (cm->input_next_index_by_type,
816  sizeof (cm->input_next_index_by_type));
817  memset (cm->max_valid_code_by_type, 0, sizeof (cm->max_valid_code_by_type));
818 
819 #define _(a,n,t) cm->max_valid_code_by_type[ICMP6_##a] = clib_max (cm->max_valid_code_by_type[ICMP6_##a], n);
821 #undef _
822 
823  memset (cm->min_valid_hop_limit_by_type, 0, sizeof (cm->min_valid_hop_limit_by_type));
824  cm->min_valid_hop_limit_by_type[ICMP6_router_solicitation] = 255;
825  cm->min_valid_hop_limit_by_type[ICMP6_router_advertisement] = 255;
826  cm->min_valid_hop_limit_by_type[ICMP6_neighbor_solicitation] = 255;
827  cm->min_valid_hop_limit_by_type[ICMP6_neighbor_advertisement] = 255;
828  cm->min_valid_hop_limit_by_type[ICMP6_redirect] = 255;
829 
830  memset (cm->min_valid_length_by_type, sizeof (icmp46_header_t), sizeof (cm->min_valid_length_by_type));
831  cm->min_valid_length_by_type[ICMP6_router_solicitation] = sizeof (icmp6_neighbor_discovery_header_t);
832  cm->min_valid_length_by_type[ICMP6_router_advertisement] = sizeof (icmp6_router_advertisement_header_t);
833  cm->min_valid_length_by_type[ICMP6_neighbor_solicitation]
834  = sizeof (icmp6_neighbor_solicitation_or_advertisement_header_t);
835  cm->min_valid_length_by_type[ICMP6_neighbor_advertisement]
836  = sizeof (icmp6_neighbor_solicitation_or_advertisement_header_t);
837  cm->min_valid_length_by_type[ICMP6_redirect] = sizeof (icmp6_redirect_header_t);
838 
839  icmp6_register_type (vm, ICMP6_echo_request, ip6_icmp_echo_request_node.index);
840 
842 }
843 
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:457
Definition: edit.h:64
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
static char * icmp_error_strings[]
Definition: icmp6.c:123
uword * type_and_code_by_name
Definition: icmp6.c:135
static u8 * format_icmp6_header(u8 *s, va_list *args)
Definition: icmp6.c:83
format_function_t format_ip6_address
Definition: format.h:94
static clib_error_t * ip6_neighbor_init(vlib_main_t *vm)
static u8 * format_ip6_icmp_type_and_code(u8 *s, va_list *args)
Definition: icmp6.c:44
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:347
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
Definition: pg.h:304
static void pg_edit_set_fixed(pg_edit_t *e, u64 value)
Definition: edit.h:153
#define PREDICT_TRUE(x)
Definition: clib.h:98
u8 packet_data[64]
Definition: icmp6.h:63
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:55
static uword ip6_icmp_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: icmp6.c:154
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
u8 ttl
Definition: ip6.h:192
u8 src_address[6]
Definition: packet.h:54
icmp6_echo_request_next_t
Definition: icmp6.c:243
u8 input_next_index_by_type[256]
Definition: icmp6.c:140
uword unformat_pg_edit(unformat_input_t *input, va_list *args)
Definition: edit.c:106
uword ip_csum_t
Definition: ip_packet.h:86
Definition: ip.h:109
vlib_error_t * errors
Definition: node.h:419
pg_edit_t code
Definition: icmp4.c:630
ip6_address_t src_address
Definition: ip6_packet.h:300
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1063
u8 min_valid_hop_limit_by_type[256]
Definition: icmp6.c:146
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:216
ip6_icmp_error_next_t
Definition: icmp6.c:485
vlib_node_registration_t ip6_icmp_error_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_error_node)
Definition: icmp6.c:632
struct ip6_main_t::@158 host_config
static vlib_node_registration_t ip6_icmp_echo_request_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_echo_request_node)
Definition: icmp6.c:470
icmp6_main_t icmp6_main
Definition: icmp6.c:151
uword * type_by_name
Definition: icmp6.c:137
unformat_function_t * unformat_pg_edit
Definition: ip.h:91
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u32 local_interface_sw_if_index
Definition: vnet.h:70
#define always_inline
Definition: clib.h:84
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:190
u8 dst_address[6]
Definition: packet.h:53
uword unformat_pg_payload(unformat_input_t *input, va_list *args)
Definition: edit.c:127
pg_edit_type_t type
Definition: edit.h:66
icmp_input_next_t
Definition: icmp6.c:129
static clib_error_t * icmp6_init(vlib_main_t *vm)
Definition: icmp6.c:788
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
static void * pg_create_edit_group(pg_stream_t *s, int n_edit_bytes, int n_packet_bytes, u32 *group_index)
Definition: pg.h:222
#define vlib_call_init_function(vm, x)
Definition: init.h:161
#define hash_create_string(elts, value_bytes)
Definition: hash.h:652
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:97
void icmp6_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp6.c:492
static uword ip6_icmp_echo_request(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: icmp6.c:250
static uword unformat_icmp_type_and_code(unformat_input_t *input, va_list *args)
Definition: icmp6.c:650
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:136
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
pg_edit_t type
Definition: icmp4.c:630
format_function_t * format_header
Definition: ip.h:82
#define PREDICT_FALSE(x)
Definition: clib.h:97
vnet_main_t vnet_main
Definition: misc.c:43
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
static void vlib_buffer_reset(vlib_buffer_t *b)
Reset current header & length to state they were in when packet was received.
Definition: buffer.h:217
#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:216
#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:350
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:121
u8 min_valid_length_by_type[256]
Definition: icmp6.c:148
static uword ip6_icmp_error(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: icmp6.c:517
vlib_node_registration_t ip6_icmp_input_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_input_node)
Definition: icmp6.c:226
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
u16 n_vectors
Definition: node.h:344
ip_main_t ip_main
Definition: ip_init.c:42
static uword unformat_pg_icmp_header(unformat_input_t *input, va_list *args)
Definition: icmp6.c:725
u8 * format_icmp6_input_trace(u8 *s, va_list *va)
Definition: icmp6.c:110
#define clib_memcpy(a, b, c)
Definition: string.h:64
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:203
u8 max_valid_code_by_type[256]
Definition: icmp6.c:143
uword unformat_vlib_number_by_name(unformat_input_t *input, va_list *args)
Definition: format.c:157
#define ARRAY_LEN(x)
Definition: clib.h:59
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:304
pg_edit_t checksum
Definition: icmp4.c:631
static void icmp6_pg_edit_function(pg_main_t *pg, pg_stream_t *s, pg_edit_group_t *g, u32 *packets, u32 n_packets)
Definition: icmp6.c:675
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:354
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:1105
u16 cached_next_index
Definition: node.h:463
#define ASSERT(truth)
vlib_main_t * vlib_main
Definition: pg.h:307
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:333
ip6_main_t ip6_main
Definition: ip6_forward.c:2655
ip_lookup_main_t lookup_main
Definition: ip6.h:132
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:117
static void pg_free_edit_group(pg_stream_t *s)
Definition: pg.h:275
static u8 icmp6_icmp_type_to_error(u8 type)
Definition: icmp6.c:500
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
uword edit_function_opaque
Definition: pg.h:79
Definition: pg.h:96
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:112
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:287
Definition: defs.h:47
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:45
u16 payload_length
Definition: ip6_packet.h:291
static uword ip6_address_is_link_local_unicast(ip6_address_t *a)
Definition: ip6_packet.h:262
void icmp6_register_type(vlib_main_t *vm, icmp6_type_t type, u32 node_index)
Definition: icmp6.c:778
unsigned char u8
Definition: types.h:56
icmp6_type_t
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:133
static void pg_icmp_header_init(pg_icmp46_header_t *p)
Definition: icmp6.c:714
uword unformat_pg_number(unformat_input_t *input, va_list *args)
Definition: edit.c:85
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u8 data[0]
Packet data.
Definition: buffer.h:154
struct _unformat_input_t unformat_input_t
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:431
format_function_t format_ip6_header
Definition: format.h:97
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
u32 * fib_index_by_sw_if_index
Definition: ip6.h:141
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:138
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:300