FD.io VPP  v17.01-9-ge7dcee4
Vector Packet Processing
ping.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 #include <vnet/ip/ping.h>
17 #include <vnet/fib/ip6_fib.h>
18 #include <vnet/fib/ip4_fib.h>
19 #include <vnet/fib/fib_entry.h>
20 
21 /**
22  * @file
23  * @brief IPv4 and IPv6 ICMP Ping.
24  *
25  * This file contains code to suppport IPv4 or IPv6 ICMP ECHO_REQUEST to
26  * network hosts.
27  *
28  */
29 
30 
31 u8 *
32 format_icmp_echo_trace (u8 * s, va_list * va)
33 {
34  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
35  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
36  icmp_echo_trace_t *t = va_arg (*va, icmp_echo_trace_t *);
37 
38  s = format (s, "ICMP echo id %d seq %d%s",
39  clib_net_to_host_u16 (t->id),
40  clib_net_to_host_u16 (t->seq), t->bound ? "" : " (unknown)");
41 
42  return s;
43 }
44 
45 /*
46  * If we can find the ping run by an ICMP ID, then we send the signal
47  * to the CLI process referenced by that ping run, alongside with
48  * a freshly made copy of the packet.
49  * I opted for a packet copy to keep the main packet processing path
50  * the same as for all the other nodes.
51  *
52  */
53 
54 static int
56  u8 event_type, vlib_buffer_t * b0)
57 {
58  ping_main_t *pm = &ping_main;
59  u16 net_icmp_id = 0;
60  u32 bi0_copy = 0;
61 
62  switch (event_type)
63  {
64  case PING_RESPONSE_IP4:
65  {
66  icmp4_echo_request_header_t *h0 = vlib_buffer_get_current (b0);
67  net_icmp_id = h0->icmp_echo.id;
68  }
69  break;
70  case PING_RESPONSE_IP6:
71  {
72  icmp6_echo_request_header_t *h0 = vlib_buffer_get_current (b0);
73  net_icmp_id = h0->icmp_echo.id;
74  }
75  break;
76  default:
77  return 0;
78  }
79 
81  clib_net_to_host_u16 (net_icmp_id));
82  if (!p)
83  return 0;
84 
85  ping_run_t *pr = vec_elt_at_index (pm->ping_runs, p[0]);
86  if (vlib_buffer_alloc (vm, &bi0_copy, 1) == 1)
87  {
88  void *dst = vlib_buffer_get_current (vlib_get_buffer (vm, bi0_copy));
90  }
91  /* If buffer_alloc failed, bi0_copy == 0 - just signaling an event. */
92 
93  vlib_process_signal_event (vm, pr->cli_process_id, event_type, bi0_copy);
94  return 1;
95 }
96 
97 /*
98  * Process ICMPv6 echo replies
99  */
100 static uword
102  vlib_node_runtime_t * node, vlib_frame_t * frame)
103 {
104  u32 n_left_from, *from;
105 
106  from = vlib_frame_vector_args (frame); /* array of buffer indices */
107  n_left_from = frame->n_vectors; /* number of buffer indices */
108 
109  while (n_left_from > 0)
110  {
111  u32 bi0;
112  vlib_buffer_t *b0;
113  u32 next0;
114 
115  bi0 = from[0];
116  b0 = vlib_get_buffer (vm, bi0);
117 
120 
122  {
123  icmp6_echo_request_header_t *h0 = vlib_buffer_get_current (b0);
124  icmp_echo_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
125  tr->id = h0->icmp_echo.id;
126  tr->seq = h0->icmp_echo.seq;
127  tr->bound = (next0 == ICMP6_ECHO_REPLY_NEXT_DROP);
128  }
129 
130  /* push this pkt to the next graph node */
131  vlib_set_next_frame_buffer (vm, node, next0, bi0);
132 
133  from += 1;
134  n_left_from -= 1;
135  }
136 
137  return frame->n_vectors;
138 }
139 
140 /* *INDENT-OFF* */
142 {
143  .function = ip6_icmp_echo_reply_node_fn,
144  .name = "ip6-icmp-echo-reply",
145  .vector_size = sizeof (u32),
146  .format_trace = format_icmp_echo_trace,
147  .n_next_nodes = ICMP6_ECHO_REPLY_N_NEXT,
148  .next_nodes = {
149  [ICMP6_ECHO_REPLY_NEXT_DROP] = "error-drop",
150  [ICMP6_ECHO_REPLY_NEXT_PUNT] = "error-punt",
151  },
152 };
153 /* *INDENT-ON* */
154 
155 /*
156  * Process ICMPv4 echo replies
157  */
158 static uword
160  vlib_node_runtime_t * node, vlib_frame_t * frame)
161 {
162  u32 n_left_from, *from;
163 
164  from = vlib_frame_vector_args (frame); /* array of buffer indices */
165  n_left_from = frame->n_vectors; /* number of buffer indices */
166 
167  while (n_left_from > 0)
168  {
169  u32 bi0;
170  vlib_buffer_t *b0;
171  u32 next0;
172 
173  bi0 = from[0];
174  b0 = vlib_get_buffer (vm, bi0);
175 
178 
180  {
181  icmp4_echo_request_header_t *h0 = vlib_buffer_get_current (b0);
182  icmp_echo_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
183  tr->id = h0->icmp_echo.id;
184  tr->seq = h0->icmp_echo.seq;
185  tr->bound = (next0 == ICMP4_ECHO_REPLY_NEXT_DROP);
186  }
187 
188  /* push this pkt to the next graph node */
189  vlib_set_next_frame_buffer (vm, node, next0, bi0);
190 
191  from += 1;
192  n_left_from -= 1;
193  }
194 
195  return frame->n_vectors;
196 }
197 
198 /* *INDENT-OFF* */
200 {
201  .function = ip4_icmp_echo_reply_node_fn,
202  .name = "ip4-icmp-echo-reply",
203  .vector_size = sizeof (u32),
204  .format_trace = format_icmp_echo_trace,
205  .n_next_nodes = ICMP4_ECHO_REPLY_N_NEXT,
206  .next_nodes = {
207  [ICMP4_ECHO_REPLY_NEXT_DROP] = "error-drop",
208  [ICMP4_ECHO_REPLY_NEXT_PUNT] = "error-punt",
209  },
210 };
211 /* *INDENT-ON* */
212 
215 
216 /* get first interface address */
217 static ip6_address_t *
219 {
220  ip_lookup_main_t *lm = &im->lookup_main;
221  ip_interface_address_t *ia = 0;
222  ip6_address_t *result = 0;
223 
224  /* *INDENT-OFF* */
225  foreach_ip_interface_address (lm, ia, sw_if_index,
226  1 /* honor unnumbered */ ,
227  ({
228  ip6_address_t * a =
230  result = a;
231  break;
232  }));
233  /* *INDENT-ON* */
234  return result;
235 }
236 
237 /* Fill in the ICMP ECHO structure, return the safety-checked and possibly shrunk data_len */
238 static u16
239 init_icmp46_echo_request (icmp46_echo_request_t * icmp46_echo,
240  u16 seq_host, u16 id_host, u16 data_len)
241 {
242  int i;
243  icmp46_echo->seq = clib_host_to_net_u16 (seq_host);
244  icmp46_echo->id = clib_host_to_net_u16 (id_host);
245 
246  for (i = 0; i < sizeof (icmp46_echo->data); i++)
247  {
248  icmp46_echo->data[i] = i % 256;
249  }
250 
251  if (data_len > sizeof (icmp46_echo_request_t))
252  {
253  data_len = sizeof (icmp46_echo_request_t);
254  }
255  return data_len;
256 }
257 
260  u32 table_id, ip6_address_t * pa6,
261  u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len,
262  u8 verbose)
263 {
264  icmp6_echo_request_header_t *h0;
265  u32 bi0 = 0;
266  int bogus_length = 0;
267  vlib_buffer_t *p0;
268  vlib_frame_t *f;
269  u32 *to_next;
270 
271  if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
272  return SEND_PING_ALLOC_FAIL;
273 
274  p0 = vlib_get_buffer (vm, bi0);
275 
276  /*
277  * if the user did not provide a source interface, use the any interface
278  * that the destination resolves via.
279  */
280  if (~0 == sw_if_index)
281  {
282  fib_node_index_t fib_entry_index;
283  u32 fib_index;
284 
285  fib_index = ip6_fib_index_from_table_id (table_id);
286 
287  if (~0 == fib_index)
288  {
289  vlib_buffer_free (vm, &bi0, 1);
290  return SEND_PING_NO_TABLE;
291  }
292 
293  fib_entry_index = ip6_fib_table_lookup (fib_index, pa6, 128);
294  sw_if_index = fib_entry_get_resolving_interface (fib_entry_index);
295  /*
296  * Set the TX interface to force ip-lookup to use its table ID
297  */
298  vnet_buffer (p0)->sw_if_index[VLIB_TX] = fib_index;
299  }
300  else
301  {
302  /*
303  * force an IP lookup in the table bound to the user's chosen
304  * source interface.
305  */
306  vnet_buffer (p0)->sw_if_index[VLIB_TX] =
308  }
309 
310  if (~0 == sw_if_index)
311  {
312  vlib_buffer_free (vm, &bi0, 1);
313  return SEND_PING_NO_INTERFACE;
314  }
315 
316  vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index;
317 
318  h0 = vlib_buffer_get_current (p0);
319 
320  /* Fill in ip6 header fields */
321  h0->ip6.ip_version_traffic_class_and_flow_label =
322  clib_host_to_net_u32 (0x6 << 28);
323  h0->ip6.payload_length = 0; /* Set below */
324  h0->ip6.protocol = IP_PROTOCOL_ICMP6;
325  h0->ip6.hop_limit = 255;
326  h0->ip6.dst_address = *pa6;
327  h0->ip6.src_address = *pa6;
328 
329  /* Fill in the correct source now */
330  ip6_address_t *a = ip6_interface_first_address (im, sw_if_index);
331  h0->ip6.src_address = a[0];
332 
333  /* Fill in icmp fields */
334  h0->icmp.type = ICMP6_echo_request;
335  h0->icmp.code = 0;
336  h0->icmp.checksum = 0;
337 
338  data_len =
339  init_icmp46_echo_request (&h0->icmp_echo, seq_host, id_host, data_len);
340  h0->icmp_echo.time_sent = vlib_time_now (vm);
341 
342  /* Fix up the lengths */
343  h0->ip6.payload_length =
344  clib_host_to_net_u16 (data_len + sizeof (icmp46_header_t));
345 
346  p0->current_length = clib_net_to_host_u16 (h0->ip6.payload_length) +
347  STRUCT_OFFSET_OF (icmp6_echo_request_header_t, icmp);
348 
349  /* Calculate the ICMP checksum */
350  h0->icmp.checksum = 0;
351  h0->icmp.checksum =
352  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip6, &bogus_length);
353 
354  /* Enqueue the packet right now */
355  f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
356  to_next = vlib_frame_vector_args (f);
357  to_next[0] = bi0;
358  f->n_vectors = 1;
360 
361  return SEND_PING_OK;
362 }
363 
366  ip4_main_t * im,
367  u32 table_id,
368  ip4_address_t * pa4,
369  u32 sw_if_index,
370  u16 seq_host, u16 id_host, u16 data_len, u8 verbose)
371 {
372  icmp4_echo_request_header_t *h0;
373  u32 bi0 = 0;
374  ip_lookup_main_t *lm = &im->lookup_main;
375  vlib_buffer_t *p0;
376  vlib_frame_t *f;
377  u32 *to_next;
378  u32 if_add_index0;
379 
380  if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
381  return SEND_PING_ALLOC_FAIL;
382 
383  p0 = vlib_get_buffer (vm, bi0);
384 
385  /*
386  * if the user did not provide a source interface, use the any interface
387  * that the destination resolves via.
388  */
389  if (~0 == sw_if_index)
390  {
391  fib_node_index_t fib_entry_index;
392  u32 fib_index;
393 
394  fib_index = ip4_fib_index_from_table_id (table_id);
395 
396  if (~0 == fib_index)
397  {
398  vlib_buffer_free (vm, &bi0, 1);
399  return SEND_PING_NO_TABLE;
400  }
401 
402  fib_entry_index =
403  ip4_fib_table_lookup (ip4_fib_get (fib_index), pa4, 32);
404  sw_if_index = fib_entry_get_resolving_interface (fib_entry_index);
405  /*
406  * Set the TX interface to force ip-lookup to use the user's table ID
407  */
408  vnet_buffer (p0)->sw_if_index[VLIB_TX] = fib_index;
409  }
410  else
411  {
412  /*
413  * force an IP lookup in the table bound to the user's chosen
414  * source interface.
415  */
416  vnet_buffer (p0)->sw_if_index[VLIB_TX] =
418  }
419 
420  if (~0 == sw_if_index)
421  {
422  vlib_buffer_free (vm, &bi0, 1);
423  return SEND_PING_NO_INTERFACE;
424  }
425 
426  vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index;
427 
428  h0 = vlib_buffer_get_current (p0);
429 
430  /* Fill in ip4 header fields */
431  h0->ip4.checksum = 0;
432  h0->ip4.ip_version_and_header_length = 0x45;
433  h0->ip4.tos = 0;
434  h0->ip4.length = 0; /* Set below */
435  h0->ip4.fragment_id = 0;
436  h0->ip4.flags_and_fragment_offset = 0;
437  h0->ip4.ttl = 0xff;
438  h0->ip4.protocol = IP_PROTOCOL_ICMP;
439  h0->ip4.dst_address = *pa4;
440  h0->ip4.src_address = *pa4;
441 
442  /* Fill in the correct source now */
443  if_add_index0 = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
444  if (PREDICT_TRUE (if_add_index0 != ~0))
445  {
446  ip_interface_address_t *if_add =
447  pool_elt_at_index (lm->if_address_pool, if_add_index0);
448  ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add);
449  h0->ip4.src_address = *if_ip;
450  if (verbose)
451  {
452  vlib_cli_output (vm, "Source address: %U",
453  format_ip4_address, &h0->ip4.src_address);
454  }
455  }
456 
457  /* Fill in icmp fields */
458  h0->icmp.type = ICMP4_echo_request;
459  h0->icmp.code = 0;
460  h0->icmp.checksum = 0;
461 
462  data_len =
463  init_icmp46_echo_request (&h0->icmp_echo, seq_host, id_host, data_len);
464  h0->icmp_echo.time_sent = vlib_time_now (vm);
465 
466  /* Fix up the lengths */
467  h0->ip4.length =
468  clib_host_to_net_u16 (data_len + sizeof (icmp46_header_t) +
469  sizeof (ip4_header_t));
470 
471  p0->current_length = clib_net_to_host_u16 (h0->ip4.length);
472 
473  /* Calculate the IP and ICMP checksums */
474  h0->ip4.checksum = ip4_header_checksum (&(h0->ip4));
475  h0->icmp.checksum =
476  ~ip_csum_fold (ip_incremental_checksum (0, &(h0->icmp),
477  p0->current_length -
478  sizeof (ip4_header_t)));
479 
480  /* Enqueue the packet right now */
481  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
482  to_next = vlib_frame_vector_args (f);
483  to_next[0] = bi0;
484  f->n_vectors = 1;
486 
487  return SEND_PING_OK;
488 }
489 
490 
491 static void
493 {
494  vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
495  icmp6_echo_request_header_t *h0 = vlib_buffer_get_current (b0);
496  f64 rtt = vlib_time_now (vm) - h0->icmp_echo.time_sent;
497 
498  vlib_cli_output (vm,
499  "%d bytes from %U: icmp_seq=%d ttl=%d time=%.4f ms",
500  clib_host_to_net_u16 (h0->ip6.payload_length),
502  &h0->ip6.src_address,
503  clib_host_to_net_u16 (h0->icmp_echo.seq),
504  h0->ip6.hop_limit, rtt * 1000.0);
505 }
506 
507 static void
509 {
510  vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
511  icmp4_echo_request_header_t *h0 = vlib_buffer_get_current (b0);
512  f64 rtt = vlib_time_now (vm) - h0->icmp_echo.time_sent;
513  u32 rcvd_icmp_len =
514  clib_host_to_net_u16 (h0->ip4.length) -
515  (4 * (0xF & h0->ip4.ip_version_and_header_length));
516 
517  vlib_cli_output (vm,
518  "%d bytes from %U: icmp_seq=%d ttl=%d time=%.4f ms",
519  rcvd_icmp_len,
521  &h0->ip4.src_address,
522  clib_host_to_net_u16 (h0->icmp_echo.seq),
523  h0->ip4.ttl, rtt * 1000.0);
524 }
525 
526 
527 /*
528  * Perform the ping run with the given parameters in the current CLI process.
529  * Depending on whether pa4 or pa6 is set, runs IPv4 or IPv6 ping.
530  * The amusing side effect is of course if both are set, then both pings are sent.
531  * This behavior can be used to ping a dualstack host over IPv4 and IPv6 at once.
532  */
533 
534 static void
536  ip6_address_t * pa6, u32 sw_if_index,
537  f64 ping_interval, u32 ping_repeat, u32 data_len,
538  u32 verbose)
539 {
540  int i;
541  ping_main_t *pm = &ping_main;
542  uword curr_proc = vlib_current_process (vm);
543  u32 n_replies = 0;
544  u32 n_requests = 0;
545  ping_run_t *pr = 0;
546  u32 ping_run_index = 0;
547  u16 icmp_id;
548 
549  static u32 rand_seed = 0;
550 
551  if (PREDICT_FALSE (!rand_seed))
552  rand_seed = random_default_seed ();
553 
554  icmp_id = random_u32 (&rand_seed) & 0xffff;
555 
556  while (hash_get (pm->ping_run_by_icmp_id, icmp_id))
557  {
558  vlib_cli_output (vm, "ICMP ID collision at %d, incrementing", icmp_id);
559  icmp_id++;
560  }
561  pool_get (pm->ping_runs, pr);
562  ping_run_index = pr - pm->ping_runs;
563  pr->cli_process_id = curr_proc;
564  pr->icmp_id = icmp_id;
565  hash_set (pm->ping_run_by_icmp_id, icmp_id, ping_run_index);
566  for (i = 1; i <= ping_repeat; i++)
567  {
568  f64 sleep_interval;
569  f64 time_ping_sent = vlib_time_now (vm);
570  /* Reset pr: running ping in other process could have changed pm->ping_runs */
571  pr = vec_elt_at_index (pm->ping_runs, ping_run_index);
572  pr->curr_seq = i;
573  if (pa6 &&
574  (SEND_PING_OK ==
575  send_ip6_ping (vm, ping_main.ip6_main, table_id, pa6, sw_if_index,
576  i, icmp_id, data_len, verbose)))
577  {
578  n_requests++;
579  }
580  if (pa4 &&
581  (SEND_PING_OK ==
582  send_ip4_ping (vm, ping_main.ip4_main, table_id, pa4, sw_if_index,
583  i, icmp_id, data_len, verbose)))
584  {
585  n_requests++;
586  }
587  while ((i <= ping_repeat)
588  &&
589  ((sleep_interval =
590  time_ping_sent + ping_interval - vlib_time_now (vm)) > 0.0))
591  {
592  uword event_type, *event_data = 0;
593  vlib_process_wait_for_event_or_clock (vm, sleep_interval);
594  event_type = vlib_process_get_events (vm, &event_data);
595  switch (event_type)
596  {
597  case ~0: /* no events => timeout */
598  break;
599  case PING_RESPONSE_IP6:
600  {
601  int i;
602  for (i = 0; i < vec_len (event_data); i++)
603  {
604  u32 bi0 = event_data[0];
605  print_ip6_icmp_reply (vm, bi0);
606  n_replies++;
607  if (0 != bi0)
608  {
609  vlib_buffer_free (vm, &bi0, 1);
610  }
611  }
612  }
613  break;
614  case PING_RESPONSE_IP4:
615  {
616  int i;
617  for (i = 0; i < vec_len (event_data); i++)
618  {
619  u32 bi0 = event_data[0];
620  print_ip4_icmp_reply (vm, bi0);
621  n_replies++;
622  if (0 != bi0)
623  {
624  vlib_buffer_free (vm, &bi0, 1);
625  }
626  }
627  }
628  break;
629  default:
630  /* someone pressed a key, abort */
631  vlib_cli_output (vm, "Aborted due to a keypress.");
632  i = 1 + ping_repeat;
633  break;
634  }
635  }
636  }
637  vlib_cli_output (vm, "\n");
638  {
639  float loss =
640  (0 ==
641  n_requests) ? 0 : 100.0 * ((float) n_requests -
642  (float) n_replies) / (float) n_requests;
643  vlib_cli_output (vm,
644  "Statistics: %u sent, %u received, %f%% packet loss\n",
645  n_requests, n_replies, loss);
646  /* Reset pr: running ping in other process could have changed pm->ping_runs */
647  pr = vec_elt_at_index (pm->ping_runs, ping_run_index);
648  hash_unset (pm->ping_run_by_icmp_id, icmp_id);
649  pool_put (pm->ping_runs, pr);
650  }
651 }
652 
653 
654 
655 
656 
657 static clib_error_t *
659  unformat_input_t * input, vlib_cli_command_t * cmd)
660 {
661  ip4_address_t a4;
662  ip6_address_t a6;
663  clib_error_t *error = 0;
664  u32 ping_repeat = 5;
665  u8 ping_ip4, ping_ip6;
666  vnet_main_t *vnm = vnet_get_main ();
667  u32 data_len = PING_DEFAULT_DATA_LEN;
668  u32 verbose = 0;
669  f64 ping_interval = PING_DEFAULT_INTERVAL;
670  u32 sw_if_index, table_id;
671 
672  table_id = 0;
673  ping_ip4 = ping_ip6 = 0;
674  sw_if_index = ~0;
675 
676  if (unformat (input, "%U", unformat_ip4_address, &a4))
677  {
678  ping_ip4 = 1;
679  }
680  else if (unformat (input, "%U", unformat_ip6_address, &a6))
681  {
682  ping_ip6 = 1;
683  }
684  else if (unformat (input, "ipv4"))
685  {
686  if (unformat (input, "%U", unformat_ip4_address, &a4))
687  {
688  ping_ip4 = 1;
689  }
690  else
691  {
692  error =
694  "expecting IPv4 address but got `%U'",
695  format_unformat_error, input);
696  }
697  }
698  else if (unformat (input, "ipv6"))
699  {
700  if (unformat (input, "%U", unformat_ip6_address, &a6))
701  {
702  ping_ip6 = 1;
703  }
704  else
705  {
706  error =
708  "expecting IPv6 address but got `%U'",
709  format_unformat_error, input);
710  }
711  }
712  else
713  {
714  error =
716  "expecting IP4/IP6 address `%U'. Usage: ping <addr> [source <intf>] [size <datasz>] [repeat <count>] [verbose]",
717  format_unformat_error, input);
718  goto done;
719  }
720 
721  /* allow for the second AF in the same ping */
722  if (!ping_ip4 && (unformat (input, "ipv4")))
723  {
724  if (unformat (input, "%U", unformat_ip4_address, &a4))
725  {
726  ping_ip4 = 1;
727  }
728  }
729  else if (!ping_ip6 && (unformat (input, "ipv6")))
730  {
731  if (unformat (input, "%U", unformat_ip6_address, &a6))
732  {
733  ping_ip6 = 1;
734  }
735  }
736 
737  /* parse the rest of the parameters in a cycle */
738  while (!unformat_eof (input, NULL))
739  {
740  if (unformat (input, "source"))
741  {
742  if (!unformat_user
743  (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
744  {
745  error =
747  "unknown interface `%U'",
748  format_unformat_error, input);
749  goto done;
750  }
751  }
752  else if (unformat (input, "size"))
753  {
754  if (!unformat (input, "%u", &data_len))
755  {
756  error =
758  "expecting size but got `%U'",
759  format_unformat_error, input);
760  goto done;
761  }
762  }
763  else if (unformat (input, "table-id"))
764  {
765  if (!unformat (input, "du", &table_id))
766  {
767  error =
769  "expecting table-id but got `%U'",
770  format_unformat_error, input);
771  goto done;
772  }
773  }
774  else if (unformat (input, "interval"))
775  {
776  if (!unformat (input, "%f", &ping_interval))
777  {
778  error =
780  "expecting interval (floating point number) got `%U'",
781  format_unformat_error, input);
782  goto done;
783  }
784  }
785  else if (unformat (input, "repeat"))
786  {
787  if (!unformat (input, "%u", &ping_repeat))
788  {
789  error =
791  "expecting repeat count but got `%U'",
792  format_unformat_error, input);
793  goto done;
794  }
795  }
796  else if (unformat (input, "verbose"))
797  {
798  verbose = 1;
799  }
800  else
801  {
802  error = clib_error_return (0, "unknown input `%U'",
803  format_unformat_error, input);
804  goto done;
805  }
806  }
807 
808  run_ping_ip46_address (vm, table_id, ping_ip4 ? &a4 : NULL,
809  ping_ip6 ? &a6 : NULL, sw_if_index, ping_interval,
810  ping_repeat, data_len, verbose);
811 done:
812  return error;
813 }
814 
815 /*?
816  * This command sends an ICMP ECHO_REQUEST to network hosts. The address
817  * can be an IPv4 or IPv6 address (or both at the same time).
818  *
819  * @cliexpar
820  * @parblock
821  * Example of how ping an IPv4 address:
822  * @cliexstart{ping 172.16.1.2 source GigabitEthernet2/0/0 repeat 2}
823  * 64 bytes from 172.16.1.2: icmp_seq=1 ttl=64 time=.1090 ms
824  * 64 bytes from 172.16.1.2: icmp_seq=2 ttl=64 time=.0914 ms
825  *
826  * Statistics: 2 sent, 2 received, 0% packet loss
827  * @cliexend
828  *
829  * Example of how ping both an IPv4 address and IPv6 address at the same time:
830  * @cliexstart{ping 172.16.1.2 ipv6 fe80::24a5:f6ff:fe9c:3a36 source GigabitEthernet2/0/0 repeat 2 verbose}
831  * Adjacency index: 10, sw_if_index: 1
832  * Adj: ip6-discover-neighbor
833  * Adj Interface: 0
834  * Forced set interface: 1
835  * Adjacency index: 0, sw_if_index: 4294967295
836  * Adj: ip4-miss
837  * Adj Interface: 0
838  * Forced set interface: 1
839  * Source address: 172.16.1.1
840  * 64 bytes from 172.16.1.2: icmp_seq=1 ttl=64 time=.1899 ms
841  * Adjacency index: 10, sw_if_index: 1
842  * Adj: ip6-discover-neighbor
843  * Adj Interface: 0
844  * Forced set interface: 1
845  * Adjacency index: 0, sw_if_index: 4294967295
846  * Adj: ip4-miss
847  * Adj Interface: 0
848  * Forced set interface: 1
849  * Source address: 172.16.1.1
850  * 64 bytes from 172.16.1.2: icmp_seq=2 ttl=64 time=.0910 ms
851  *
852  * Statistics: 4 sent, 2 received, 50% packet loss
853  * @cliexend
854  * @endparblock
855 ?*/
856 /* *INDENT-OFF* */
857 VLIB_CLI_COMMAND (ping_command, static) =
858 {
859  .path = "ping",
860  .function = ping_ip_address,
861  .short_help = "ping {<ip-addr> | ipv4 <ip4-addr> | ipv6 <ip6-addr>}"
862  " [ipv4 <ip4-addr> | ipv6 <ip6-addr>] [source <interface>]"
863  " [size <pktsize>] [interval <sec>] [repeat <cnt>] [table-id <id>]"
864  " [verbose]",
865 };
866 /* *INDENT-ON* */
867 
868 static clib_error_t *
870 {
871  ping_main_t *pm = &ping_main;
872  pm->ip6_main = &ip6_main;
873  pm->ip4_main = &ip4_main;
874  icmp6_register_type (vm, ICMP6_echo_reply, ip6_icmp_echo_reply_node.index);
875  ip4_icmp_register_type (vm, ICMP4_echo_reply,
877  return 0;
878 }
879 
881 
882 /*
883  * fd.io coding-style-patch-verification: ON
884  *
885  * Local Variables:
886  * eval: (c-set-style "gnu")
887  * End:
888  */
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
Definition: lookup.h:460
char * ip6_lookup_next_nodes[]
Definition: ping.c:213
char * ip4_lookup_next_nodes[]
Definition: ping.c:214
#define hash_set(h, key, value)
Definition: hash.h:254
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 send_ip46_ping_result_t send_ip6_ping(vlib_main_t *vm, ip6_main_t *im, u32 table_id, ip6_address_t *pa6, u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len, u8 verbose)
Definition: ping.c:259
#define IP6_LOOKUP_NEXT_NODES
Definition: lookup.h:123
static uword random_default_seed(void)
Default random seed (unix/linux user-mode)
Definition: random.h:91
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:684
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
format_function_t format_ip6_address
Definition: format.h:95
static void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:383
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:375
static uword vlib_current_process(vlib_main_t *vm)
Definition: node_funcs.h:410
#define PREDICT_TRUE(x)
Definition: clib.h:98
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
static u16 init_icmp46_echo_request(icmp46_echo_request_t *icmp46_echo, u16 seq_host, u16 id_host, u16 data_len)
Definition: ping.c:239
ip4_main_t * ip4_main
Definition: ping.h:50
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:62
ip_lookup_main_t lookup_main
Definition: ip4.h:97
unformat_function_t unformat_vnet_sw_interface
static void print_ip6_icmp_reply(vlib_main_t *vm, u32 bi0)
Definition: ping.c:492
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
format_function_t format_ip4_address
Definition: format.h:79
u8 * format_icmp_echo_trace(u8 *s, va_list *va)
Definition: ping.c:32
send_ip46_ping_result_t
Definition: ping.h:29
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:511
static uword ip4_icmp_echo_reply_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ping.c:159
static void run_ping_ip46_address(vlib_main_t *vm, u32 table_id, ip4_address_t *pa4, ip6_address_t *pa6, u32 sw_if_index, f64 ping_interval, u32 ping_repeat, u32 data_len, u32 verbose)
Definition: ping.c:535
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:212
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:527
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
static send_ip46_ping_result_t send_ip4_ping(vlib_main_t *vm, ip4_main_t *im, u32 table_id, ip4_address_t *pa4, u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len, u8 verbose)
Definition: ping.c:365
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static int signal_ip46_icmp_reply_event(vlib_main_t *vm, u8 event_type, vlib_buffer_t *b0)
Definition: ping.c:55
ping_run_t * ping_runs
Definition: ping.h:51
#define IP4_LOOKUP_NEXT_NODES
Definition: lookup.h:111
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
u32 ip6_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip6_fib.c:445
unformat_function_t unformat_ip4_address
Definition: format.h:76
void ip4_icmp_register_type(vlib_main_t *vm, icmp4_type_t type, u32 node_index)
Definition: icmp4.c:731
static clib_error_t * ping_cli_init(vlib_main_t *vm)
Definition: ping.c:869
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:931
static ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
Definition: ping.c:218
static u32 ip6_fib_index_from_table_id(u32 table_id)
Definition: ip6_fib.h:113
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
#define PREDICT_FALSE(x)
Definition: clib.h:97
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
unformat_function_t unformat_ip6_address
Definition: format.h:94
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1301
unformat_function_t unformat_eof
Definition: format.h:291
fib_node_index_t ip4_fib_table_lookup(const ip4_fib_t *fib, const ip4_address_t *addr, u32 len)
The IPv4 FIB.
Definition: ip4_fib.c:285
u16 curr_seq
Definition: ping.h:43
#define PING_DEFAULT_INTERVAL
Definition: ping.h:60
u16 n_vectors
Definition: node.h:344
static vlib_node_registration_t ip6_icmp_echo_reply_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_echo_reply_node)
Definition: ping.c:141
static ip4_fib_t * ip4_fib_get(u32 index)
Get the FIB at the given index.
Definition: ip4_fib.h:71
static vlib_node_registration_t ip4_icmp_echo_reply_node
(constructor) VLIB_REGISTER_NODE (ip4_icmp_echo_reply_node)
Definition: ping.c:199
ip6_main_t * ip6_main
Definition: ping.h:49
#define clib_memcpy(a, b, c)
Definition: string.h:69
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
static u32 ip4_fib_index_from_table_id(u32 table_id)
Definition: ip4_fib.h:101
uword cli_process_id
Definition: ping.h:44
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:382
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:1141
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:675
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vnet_buffer(b)
Definition: buffer.h:361
ip6_main_t ip6_main
Definition: ip6_forward.c:2828
ip_lookup_main_t lookup_main
Definition: ip6.h:135
void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
IPv4 main type.
Definition: ip4.h:95
static void print_ip4_icmp_reply(vlib_main_t *vm, u32 bi0)
Definition: ping.c:508
u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:95
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
void icmp6_register_type(vlib_main_t *vm, icmp6_type_t type, u32 node_index)
Definition: icmp6.c:803
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
ping_main_t ping_main
Definition: ping.h:57
static uword ip6_icmp_echo_reply_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ping.c:101
u16 icmp_id
Definition: ping.h:42
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1099
ping_run_t * ping_run_by_icmp_id
Definition: ping.h:54
fib_node_index_t ip6_fib_table_lookup(u32 fib_index, const ip6_address_t *addr, u32 len)
Definition: ip6_fib.c:246
#define PING_DEFAULT_DATA_LEN
Definition: ping.h:59
#define clib_error_return(e, args...)
Definition: error.h:111
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:453
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
static clib_error_t * ping_ip_address(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ping.c:658
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:238
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
Definition: defs.h:46