FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
arping.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 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 <stddef.h>
17 
18 #include <vlib/vlib.h>
19 #include <vlib/unix/unix.h>
20 #include <vnet/plugin/plugin.h>
21 #include <vpp/app/version.h>
24 #include <arping/arping.h>
25 
27 
28 #define foreach_arping_error _ (NONE, "no error")
29 
30 typedef enum
31 {
32 #define _(f, s) ARPING_ERROR_##f,
34 #undef _
37 
38 static char *arping_error_strings[] = {
39 #define _(n, s) s,
41 #undef _
42 };
43 
44 #define foreach_arping \
45  _ (DROP, "error-drop") \
46  _ (IO, "interface-output")
47 
48 typedef enum
49 {
50 #define _(sym, str) ARPING_NEXT_##sym,
52 #undef _
55 
56 typedef struct arping_trace_t_
57 {
60  ethernet_arp_ip4_over_ethernet_address_t reply;
62 
63 typedef enum
64 {
65 #define _(sym, str) ARPING6_NEXT_##sym,
67 #undef _
70 
71 typedef CLIB_PACKED (struct {
73  ip6_address_t ip6;
74 }) ethernet_arp_ip6_over_ethernet_address_t;
75 
76 typedef struct arping6_trace_t_
77 {
79  u8 type;
80  ethernet_arp_ip6_over_ethernet_address_t reply;
82 
83 /* packet trace format function */
84 static u8 *
85 format_arping_trace (u8 *s, va_list *args)
86 {
87  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
88  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
89  arping_trace_t *t = va_arg (*args, arping_trace_t *);
90 
91  s = format (s, "sw-if-index: %u, opcode: %U, from %U (%U)", t->sw_if_index,
93  &t->reply.mac, format_ip4_address, &t->reply.ip4);
94 
95  return s;
96 }
97 
98 static u8 *
99 format_arping6_trace (u8 *s, va_list *args)
100 {
101  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
102  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
103  arping6_trace_t *t = va_arg (*args, arping6_trace_t *);
104 
105  s = format (s, "sw-if-index: %u, type: %u, from %U (%U)", t->sw_if_index,
106  t->type, format_mac_address, &t->reply.mac, format_ip6_address,
107  &t->reply.ip6);
108 
109  return s;
110 }
111 
114 {
115  u32 n_left_from, *from, *to_next, n_left_to_next;
118 
119  next_index = node->cached_next_index;
120  n_left_from = frame->n_vectors;
122 
123  while (n_left_from > 0)
124  {
125  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
126 
127  while (n_left_from >= 2 && n_left_to_next >= 2)
128  {
129  u32 next0, next1, bi0, bi1;
130  vlib_buffer_t *b0, *b1;
131  ethernet_arp_header_t *arp0, *arp1;
132  u32 sw_if_index0, sw_if_index1;
133  arping_intf_t *aif0, *aif1;
134 
135  bi0 = to_next[0] = from[0];
136  bi1 = to_next[1] = from[1];
137 
138  from += 2;
139  n_left_from -= 2;
140  to_next += 2;
141  n_left_to_next -= 2;
142 
143  next0 = next1 = ARPING_NEXT_DROP;
144 
145  b0 = vlib_get_buffer (vm, bi0);
146  b1 = vlib_get_buffer (vm, bi1);
147 
148  arp0 = vlib_buffer_get_current (b0);
149  arp1 = vlib_buffer_get_current (b1);
150 
151  vnet_feature_next (&next0, b0);
152  vnet_feature_next (&next1, b1);
153 
154  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
155  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
156 
157  if (PREDICT_TRUE (arp0->opcode ==
158  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
159  {
160  aif0 = am->interfaces[sw_if_index0];
161  if (PREDICT_TRUE (aif0->address.ip.ip4.as_u32 ==
162  arp0->ip4_over_ethernet[0].ip4.as_u32))
163  {
164  aif0->recv.from4.ip4.as_u32 =
165  arp0->ip4_over_ethernet[0].ip4.as_u32;
166  clib_memcpy_fast (&aif0->recv.from4.mac,
167  &arp0->ip4_over_ethernet[0].mac, 6);
168  aif0->reply_count++;
169  }
170  }
171  if (PREDICT_TRUE (arp1->opcode ==
172  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
173  {
174  aif1 = am->interfaces[sw_if_index1];
175  if (PREDICT_TRUE (aif1->address.ip.ip4.as_u32 ==
176  arp1->ip4_over_ethernet[0].ip4.as_u32))
177  {
178  aif1->recv.from4.ip4.as_u32 =
179  arp1->ip4_over_ethernet[0].ip4.as_u32;
180  clib_memcpy_fast (&aif1->recv.from4.mac,
181  &arp1->ip4_over_ethernet[0].mac, 6);
182  aif1->reply_count++;
183  }
184  }
185 
186  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
187  {
188  arping_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
189  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
190  t->arp_opcode = clib_host_to_net_u16 (arp0->opcode);
191  t->reply.ip4.as_u32 = arp0->ip4_over_ethernet[0].ip4.as_u32;
192  clib_memcpy_fast (&t->reply.mac, &arp0->ip4_over_ethernet[0].mac,
193  6);
194  }
195  if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
196  {
197  arping_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
198  t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
199  t->arp_opcode = clib_host_to_net_u16 (arp1->opcode);
200  t->reply.ip4.as_u32 = arp1->ip4_over_ethernet[0].ip4.as_u32;
201  clib_memcpy_fast (&t->reply.mac, &arp1->ip4_over_ethernet[0].mac,
202  6);
203  }
204 
206  n_left_to_next, bi0, bi1, next0,
207  next1);
208  }
209 
210  while (n_left_from > 0 && n_left_to_next > 0)
211  {
212  u32 next0, bi0;
213  vlib_buffer_t *b0;
214  ethernet_arp_header_t *arp0;
215  arping_intf_t *aif0;
216  u32 sw_if_index0;
217 
218  bi0 = to_next[0] = from[0];
219 
220  from += 1;
221  n_left_from -= 1;
222  to_next += 1;
223  n_left_to_next -= 1;
224  next0 = ARPING_NEXT_DROP;
225 
226  b0 = vlib_get_buffer (vm, bi0);
227  arp0 = vlib_buffer_get_current (b0);
228 
229  vnet_feature_next (&next0, b0);
230 
231  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
232 
233  if (PREDICT_TRUE (arp0->opcode ==
234  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
235  {
236  aif0 = am->interfaces[sw_if_index0];
237  if (PREDICT_TRUE (aif0->address.ip.ip4.as_u32 ==
238  arp0->ip4_over_ethernet[0].ip4.as_u32))
239  {
240  aif0->recv.from4.ip4.as_u32 =
241  arp0->ip4_over_ethernet[0].ip4.as_u32;
242  clib_memcpy_fast (&aif0->recv.from4.mac,
243  &arp0->ip4_over_ethernet[0].mac, 6);
244  aif0->reply_count++;
245  }
246  }
247 
248  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
249  {
250  arping_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
251  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
252  t->arp_opcode = clib_host_to_net_u16 (arp0->opcode);
253  t->reply.ip4.as_u32 = arp0->ip4_over_ethernet[0].ip4.as_u32;
254  clib_memcpy_fast (&t->reply.mac, &arp0->ip4_over_ethernet[0].mac,
255  6);
256  }
257 
259  n_left_to_next, bi0, next0);
260  }
261 
262  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
263  }
264 
265  return frame->n_vectors;
266 }
267 
269 {
270  .name = "arping-input",.vector_size = sizeof (u32),.format_trace =
272  ARPING_N_ERROR,.error_strings = arping_error_strings,.n_next_nodes =
273  ARPING_N_NEXT,.next_nodes =
274  {
275  [ARPING_NEXT_DROP] = "error-drop",[ARPING_NEXT_IO] = "interface-output",}
276 ,};
277 
278 VNET_FEATURE_INIT (arping_feat_node, static) = {
279  .arc_name = "arp",
280  .node_name = "arping-input",
281  .runs_before = VNET_FEATURES ("arp-reply"),
282 };
283 
286 {
287  u32 n_left_from, *from, *to_next, n_left_to_next;
290 
291  next_index = node->cached_next_index;
292  n_left_from = frame->n_vectors;
294 
295  while (n_left_from > 0)
296  {
297  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
298 
299  while (n_left_from >= 2 && n_left_to_next >= 2)
300  {
301  u32 next0, next1, bi0, bi1;
302  vlib_buffer_t *b0, *b1;
303  ip6_header_t *ip60, *ip61;
304  u32 sw_if_index0, sw_if_index1;
305  arping_intf_t *aif0, *aif1;
306  icmp6_neighbor_solicitation_or_advertisement_header_t *sol_adv0,
307  *sol_adv1;
308  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
309  *lladdr0,
310  *lladdr1;
311 
312  bi0 = to_next[0] = from[0];
313  bi1 = to_next[1] = from[1];
314 
315  from += 2;
316  n_left_from -= 2;
317  to_next += 2;
318  n_left_to_next -= 2;
319 
320  next0 = next1 = ARPING6_NEXT_DROP;
321 
322  b0 = vlib_get_buffer (vm, bi0);
323  b1 = vlib_get_buffer (vm, bi1);
324 
325  ip60 = vlib_buffer_get_current (b0);
326  ip61 = vlib_buffer_get_current (b1);
327 
328  vnet_feature_next (&next0, b0);
329  vnet_feature_next (&next1, b1);
330 
331  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
332  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
333 
334  sol_adv0 = ip6_next_header (ip60);
335  lladdr0 =
336  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
337  *) (sol_adv0 + 1);
338 
339  if (PREDICT_TRUE (sol_adv0->icmp.type ==
340  ICMP6_neighbor_advertisement))
341  {
342  aif0 = am->interfaces[sw_if_index0];
343  if (PREDICT_TRUE (clib_memcmp (&aif0->address.ip.ip6,
344  &sol_adv0->target_address,
345  sizeof (aif0->address.ip.ip6)) ==
346  0))
347  {
348  clib_memcpy_fast (&aif0->recv.from6.ip6,
349  &sol_adv0->target_address,
350  sizeof (aif0->recv.from6.ip6));
351  clib_memcpy_fast (&aif0->recv.from6.mac,
352  lladdr0->ethernet_address, 6);
353  aif0->reply_count++;
354  }
355  }
356 
357  sol_adv1 = ip6_next_header (ip61);
358  lladdr1 =
359  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
360  *) (sol_adv1 + 1);
361 
362  if (PREDICT_TRUE (sol_adv1->icmp.type ==
363  ICMP6_neighbor_advertisement))
364  {
365  aif1 = am->interfaces[sw_if_index1];
366  if (PREDICT_TRUE (clib_memcmp (&aif1->address.ip.ip6,
367  &sol_adv1->target_address,
368  sizeof (aif1->address.ip.ip6)) ==
369  0))
370  {
371  clib_memcpy_fast (&aif1->recv.from6.ip6,
372  &sol_adv1->target_address,
373  sizeof (aif1->recv.from6.ip6));
374  clib_memcpy_fast (&aif1->recv.from6.mac,
375  lladdr1->ethernet_address, 6);
376  aif1->reply_count++;
377  }
378  }
379 
380  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
381  {
382  arping6_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
383  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
384  t->type = sol_adv0->icmp.type;
385  clib_memcpy_fast (&t->reply.ip6, &sol_adv0->target_address,
386  sizeof (t->reply.ip6));
387  clib_memcpy_fast (&t->reply.mac, lladdr0->ethernet_address, 6);
388  }
389  if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
390  {
391  arping6_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
392  t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
393  t->type = sol_adv1->icmp.type;
394  clib_memcpy_fast (&t->reply.ip6, &sol_adv1->target_address,
395  sizeof (t->reply.ip6));
396  clib_memcpy_fast (&t->reply.mac, lladdr1->ethernet_address, 6);
397  }
398 
400  n_left_to_next, bi0, bi1, next0,
401  next1);
402  }
403 
404  while (n_left_from > 0 && n_left_to_next > 0)
405  {
406  u32 next0, bi0;
407  vlib_buffer_t *b0;
408  arping_intf_t *aif0;
409  u32 sw_if_index0;
410  ip6_header_t *ip60;
411  icmp6_neighbor_solicitation_or_advertisement_header_t *sol_adv0;
412  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
413  *lladdr0;
414 
415  bi0 = to_next[0] = from[0];
416 
417  from += 1;
418  n_left_from -= 1;
419  to_next += 1;
420  n_left_to_next -= 1;
421  next0 = ARPING_NEXT_DROP;
422 
423  b0 = vlib_get_buffer (vm, bi0);
424  ip60 = vlib_buffer_get_current (b0);
425 
426  vnet_feature_next (&next0, b0);
427 
428  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
429 
430  sol_adv0 = ip6_next_header (ip60);
431  lladdr0 =
432  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
433  *) (sol_adv0 + 1);
434  if (PREDICT_TRUE (sol_adv0->icmp.type ==
435  ICMP6_neighbor_advertisement))
436  {
437  aif0 = am->interfaces[sw_if_index0];
438  if (PREDICT_TRUE (clib_memcmp (&aif0->address.ip.ip6,
439  &sol_adv0->target_address,
440  sizeof (aif0->address.ip.ip6)) ==
441  0))
442  {
443  clib_memcpy_fast (&aif0->recv.from6.ip6,
444  &sol_adv0->target_address,
445  sizeof (aif0->recv.from6.ip6));
446  clib_memcpy_fast (&aif0->recv.from6.mac,
447  lladdr0->ethernet_address, 6);
448  aif0->reply_count++;
449  }
450  }
451 
452  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
453  {
454  arping6_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
455  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
456  t->type = sol_adv0->icmp.type;
457  clib_memcpy_fast (&t->reply.ip6, &sol_adv0->target_address,
458  sizeof (t->reply.ip6));
459  clib_memcpy_fast (&t->reply.mac, lladdr0->ethernet_address, 6);
460  }
461 
463  n_left_to_next, bi0, next0);
464  }
465 
466  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
467  }
468 
469  return frame->n_vectors;
470 }
471 
473 {
474  .name = "arping6-input",.vector_size = sizeof (u32),.format_trace =
476  ARPING_N_ERROR,.error_strings = arping_error_strings,.n_next_nodes =
477  ARPING_N_NEXT,.next_nodes =
478  {
479  [ARPING6_NEXT_DROP] = "error-drop",[ARPING6_NEXT_IO] = "interface-output",}
480 ,};
481 
482 VNET_FEATURE_INIT (arping6_feat_node, static) = {
483  .arc_name = "ip6-local",
484  .node_name = "arping6-input",
485  .runs_before = VNET_FEATURES ("ip6-local-end-of-arc"),
486 };
487 
488 static clib_error_t *
490 {
491  vnet_main_t *vnm = vnet_get_main ();
492  u32 send_count = 0;
493 
494  while (args->repeat > 0)
495  {
496  send_count++;
497  if (args->address.version == AF_IP4)
498  {
499  if (args->silence == 0)
500  vlib_cli_output (vm, "Sending %u GARP to %U", send_count,
501  format_ip4_address, &args->address.ip.ip4);
503  &args->address.ip.ip4);
504  }
505  else
506  {
507  if (args->silence == 0)
508  vlib_cli_output (vm, "Sending %u Neighbor Advertisement to %U",
509  send_count, format_ip6_address,
510  &args->address.ip.ip6);
512  &args->address.ip.ip6);
513  }
514  args->repeat--;
515  if ((args->interval > 0.0) && (args->repeat > 0))
517  }
518 
519  return 0;
520 }
521 
522 static void
524  const char *node_name, u32 sw_if_index,
525  int enable_disable, void *feature_config,
526  u32 n_feature_config_bytes)
527 {
529  vnet_feature_enable_disable (arc_name, node_name, sw_if_index,
530  enable_disable, feature_config,
531  n_feature_config_bytes);
533 }
534 
535 static void
537 {
539 
540  if (sw_if_index >= vec_len (am->interfaces))
541  {
545  }
546 }
547 
548 static clib_error_t *
550 {
552  u32 send_count = 0;
554  arping_intf_t aif;
555 
556  /* Disallow multiple sends on the same interface for now. Who needs it? */
557  if (am->interfaces && (am->interfaces[args->sw_if_index] != 0))
558  {
560  0, "arping command is in progress for the same interface. "
561  "Please try again later.");
562  args->rv = VNET_API_ERROR_INVALID_VALUE;
563  return error;
564  }
565 
567  clib_memset (&aif, 0, sizeof (aif));
568  aif.interval = args->interval;
569  aif.repeat = args->repeat;
570  aif.reply_count = 0;
571  am->interfaces[args->sw_if_index] = &aif;
572 
573  clib_memcpy (&aif.address, &args->address, sizeof (aif.address));
574  if (args->address.version == AF_IP4)
575  arping_vnet_feature_enable_disable (vm, "arp", "arping-input",
576  args->sw_if_index, 1, 0, 0);
577  else
578  arping_vnet_feature_enable_disable (vm, "ip6-local", "arping6-input",
579  args->sw_if_index, 1, 0, 0);
580 
581  while (args->repeat > 0)
582  {
583  send_count++;
584  if (args->address.version == AF_IP4)
585  {
586  if (args->silence == 0)
587  vlib_cli_output (vm, "Sending %u ARP Request to %U", send_count,
588  format_ip4_address, &args->address.ip.ip4);
589  ip4_neighbor_probe_dst (args->sw_if_index, &args->address.ip.ip4);
590  }
591  else
592  {
593  if (args->silence == 0)
594  vlib_cli_output (vm, "Sending %u Neighbor Solicitation to %U",
595  send_count, format_ip6_address,
596  &args->address.ip.ip6);
597  ip6_neighbor_probe_dst (args->sw_if_index, &args->address.ip.ip6);
598  }
599  args->repeat--;
600  if ((args->interval > 0.0) && (args->repeat > 0))
602  }
603 
604  /* wait for a second on the reply */
605  u32 wait_count = 0;
606  while ((aif.reply_count < send_count) && (wait_count < 10))
607  {
608  vlib_process_suspend (vm, 0.1);
609  wait_count++;
610  }
611 
612  if (args->address.version == AF_IP4)
613  {
614  clib_memcpy (&args->recv.from4, &aif.recv.from4,
615  sizeof (args->recv.from4));
616  arping_vnet_feature_enable_disable (vm, "arp", "arping-input",
617  args->sw_if_index, 0, 0, 0);
618  }
619  else
620  {
621  clib_memcpy (&args->recv.from6, &aif.recv.from6,
622  sizeof (args->recv.from6));
623  arping_vnet_feature_enable_disable (vm, "ip6-local", "arping6-input",
624  args->sw_if_index, 0, 0, 0);
625  }
626  args->reply_count = aif.reply_count;
627 
628  am->interfaces[args->sw_if_index] = 0;
629 
630  return 0;
631 }
632 
633 void
635 {
636  if (args->is_garp)
637  args->error = arping_neighbor_advertisement (vm, args);
638  else
639  args->error = arping_neighbor_probe_dst (vm, args);
640 }
641 
642 static clib_error_t *
644  vlib_cli_command_t *cmd)
645 {
646  clib_error_t *error = 0;
647  vnet_main_t *vnm = vnet_get_main ();
648  arping_args_t args = { 0 };
650 
653  args.sw_if_index = ~0;
654  args.silence = 0;
655 
656  if (unformat (input, "gratuitous"))
657  args.is_garp = 1;
658 
659  if (unformat (input, "%U", unformat_ip4_address, &args.address.ip.ip4))
660  args.address.version = AF_IP4;
661  else if (unformat (input, "%U", unformat_ip6_address, &args.address.ip.ip6))
662  args.address.version = AF_IP6;
663  else
664  {
666  0,
667  "expecting IP4/IP6 address `%U'. Usage: arping [gratuitous] <addr> "
668  "<intf> [repeat <count>] [interval <secs>]",
669  format_unformat_error, input);
670  goto done;
671  }
672 
673  if (!unformat_user (input, unformat_vnet_sw_interface, vnm,
674  &args.sw_if_index))
675  {
676  error = clib_error_return (0, "unknown interface `%U'",
677  format_unformat_error, input);
678  goto done;
679  }
680 
681  /* parse the rest of the parameters in a cycle */
682  while (!unformat_eof (input, NULL))
683  {
684  if (unformat (input, "interval"))
685  {
686  if (!unformat (input, "%f", &interval))
687  {
689  0, "expecting interval (floating point number) got `%U'",
690  format_unformat_error, input);
691  goto done;
692  }
693  args.interval = interval;
694  }
695  else if (unformat (input, "repeat"))
696  {
697  if (!unformat (input, "%u", &args.repeat))
698  {
699  error =
700  clib_error_return (0, "expecting repeat count but got `%U'",
701  format_unformat_error, input);
702  goto done;
703  }
704  }
705  else
706  {
707  error = clib_error_return (0, "unknown input `%U'",
708  format_unformat_error, input);
709  goto done;
710  }
711  }
712 
713  arping_run_command (vm, &args);
714 
715  if (args.reply_count)
716  {
717  if (args.address.version == AF_IP4)
718  vlib_cli_output (vm, "Received %u ARP Replies from %U (%U)",
720  &args.recv.from4.mac, format_ip4_address,
721  &args.recv.from4.ip4);
722  else
724  vm, "Received %u ICMP6 neighbor advertisements from %U (%U)",
725  args.reply_count, format_mac_address, &args.recv.from6.mac,
726  format_ip6_address, &args.recv.from6.ip6);
727  }
728  else if (args.is_garp == 0)
729  vlib_cli_output (vm, "Received 0 Reply");
730 
731  error = args.error;
732 done:
733  return error;
734 }
735 // clang-format off
736 /*?
737  * This command sends an ARP REQUEST or gratuitous ARP to network hosts. The
738  * address can be an IPv4 or IPv6 address.
739  *
740  * @cliexpar
741  * @parblock
742  * Example of how to send an IPv4 ARP REQUEST
743  * @cliexstart{arping 100.1.1.10 VirtualEthernet0/0/0 repeat 3 interval 1}
744  * Sending 1 ARP Request to 100.1.1.10
745  * Sending 2 ARP Request to 100.1.1.10
746  * Sending 3 ARP Request to 100.1.1.10
747  * Received 3 ARP Replies from 52:53:00:00:04:01 (100.1.1.10)
748  * @cliexend
749  *
750  * Example of how to send an IPv6 Neighbor Solicitation
751  * @cliexstart{arping 2001:192::2 VirtualEthernet0/0/0 repeat 3 interval 1}
752  * Sending 1 Neighbor Solicitation to 2001:192::2
753  * Sending 2 Neighbor Solicitation to 2001:192::2
754  * Sending 3 Neighbor Solicitation to 2001:192::2
755  * Received 3 ICMP6 neighbor advertisements from 52:53:00:00:04:01 (2001:192::2)
756  * @cliexend
757  *
758  * Example of how to send an IPv4 gratuitous ARP
759  * @cliexstart{arping gratuitous 100.1.1.100 VirtualEthernet0/0/0 repeat 2}
760  * Sending 1 GARP to 100.1.1.100
761  * Sending 2 GARP to 100.1.1.100
762  * @cliexend
763  * @endparblock
764  *
765 ?*/
766 // clang-format on
768  .path = "arping",
769  .function = arping_ip_address,
770  .short_help = "arping [gratuitous] {addr} {interface}"
771  " [interval {sec}] [repeat {cnt}]",
772  .is_mp_safe = 1,
773 };
774 
775 static clib_error_t *
777 {
778  /* initialize binary API */
780 
781  return 0;
782 }
783 
785 
787  .version = VPP_BUILD_VER,
788  .description = "Arping (arping)",
789 };
790 
791 /*
792  * fd.io coding-style-patch-verification: ON
793  *
794  * Local Variables:
795  * eval: (c-set-style "gnu")
796  * End:
797  */
ARPING6_N_NEXT
@ ARPING6_N_NEXT
Definition: arping.c:68
vlib.h
arping_args_t::address
ip_address_t address
Definition: arping.h:55
vlib_worker_thread_barrier_release
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1375
ethernet_arp_header_t::opcode
u16 opcode
Definition: arp_packet.h:139
mac
vl_api_mac_address_t mac
Definition: l2.api:559
unformat_user
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
node
vlib_main_t vlib_node_runtime_t * node
Definition: arping.c:113
arping_args_t::rv
i32 rv
Definition: arping.h:63
arping6_next_t
arping6_next_t
Definition: arping.c:63
ip4_neighbor.h
format_ip4_address
format_function_t format_ip4_address
Definition: format.h:73
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
arping_intf_t
Definition: arping.h:35
vlib_get_buffer
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
arping_next_t
arping_next_t
Definition: arping.c:48
clib_memcmp
#define clib_memcmp(s1, s2, m1)
Definition: string.h:734
next_index
arping_next_t next_index
Definition: arping.c:116
arping_trace_t_::reply
ethernet_arp_ip4_over_ethernet_address_t reply
Definition: arping.c:60
arping_neighbor_probe_dst
static clib_error_t * arping_neighbor_probe_dst(vlib_main_t *vm, arping_args_t *args)
Definition: arping.c:549
ARPING_N_NEXT
@ ARPING_N_NEXT
Definition: arping.c:53
VLIB_NODE_TYPE_INTERNAL
@ VLIB_NODE_TYPE_INTERNAL
Definition: node.h:72
arping_intf_t::reply_count
u32 reply_count
Definition: arping.h:43
arping6_trace_t
arping6_trace_t
Definition: arping.c:81
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
vlib_cli_command_t::path
char * path
Definition: cli.h:96
ethernet_arp_header_t::ip4_over_ethernet
ethernet_arp_ip4_over_ethernet_address_t ip4_over_ethernet[2]
Definition: arp_packet.h:142
arping_args_t::repeat
u32 repeat
Definition: arping.h:57
CLIB_PACKED
typedef CLIB_PACKED(struct { mac_address_t mac;ip6_address_t ip6;})
Definition: arping.c:71
u16
unsigned short u16
Definition: types.h:57
arping_neighbor_advertisement
static clib_error_t * arping_neighbor_advertisement(vlib_main_t *vm, arping_args_t *args)
Definition: arping.c:489
arping_run_command
void arping_run_command(vlib_main_t *vm, arping_args_t *args)
Definition: arping.c:634
AF_IP4
@ AF_IP4
Definition: ip_types.h:23
VLIB_RX
@ VLIB_RX
Definition: defs.h:46
unformat_input_t
struct _unformat_input_t unformat_input_t
arping_args_t::silence
u8 silence
Definition: arping.h:60
ip6_next_header
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:407
vlib_frame_t
Definition: node.h:372
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
arping_command
static vlib_cli_command_t arping_command
(constructor) VLIB_CLI_COMMAND (arping_command)
Definition: arping.c:767
error
Definition: cJSON.c:88
arping_main_t
Definition: arping.h:46
format_mac_address
u8 * format_mac_address(u8 *s, va_list *args)
Definition: format.c:58
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
frame
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: arping.c:114
arping_input_node
vlib_node_registration_t arping_input_node
(constructor) VLIB_REGISTER_NODE (arping_input_node)
Definition: arping.c:268
arping_trace_t_::sw_if_index
u32 sw_if_index
Definition: arping.c:58
unformat_eof
unformat_function_t unformat_eof
Definition: format.h:285
ethernet_arp_header_t
Definition: arp_packet.h:133
arping_trace_t
struct arping_trace_t_ arping_trace_t
arping__error_t
arping__error_t
Definition: arping.c:30
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
ip6_neighbor.h
arping_vnet_feature_enable_disable
static void arping_vnet_feature_enable_disable(vlib_main_t *vm, const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: arping.c:523
VLIB_NODE_FN
#define VLIB_NODE_FN(node)
Definition: node.h:202
arping_intf_t::recv
arping46_reply_t recv
Definition: arping.h:42
ip_address::version
ip_address_family_t version
Definition: ip_types.h:82
CLIB_UNUSED
#define CLIB_UNUSED(x)
Definition: clib.h:90
vnet_buffer
#define vnet_buffer(b)
Definition: buffer.h:441
vnet_get_main
vnet_main_t * vnet_get_main(void)
Definition: pnat_test_stubs.h:56
arping_intf_t::address
ip_address_t address
Definition: arping.h:40
vlib_worker_thread_barrier_sync
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:173
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
ip6_neighbor_advertise
void ip6_neighbor_advertise(vlib_main_t *vm, vnet_main_t *vnm, u32 sw_if_index, const ip6_address_t *addr)
Definition: ip6_neighbor.c:43
vnet_feature_next
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
vlib_frame_vector_args
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
arping_cli_init
static clib_error_t * arping_cli_init(vlib_main_t *vm)
Definition: arping.c:776
foreach_arping_error
#define foreach_arping_error
Definition: arping.c:28
vm
vlib_main_t * vm
Definition: arping.c:113
VLIB_PLUGIN_REGISTER
VLIB_PLUGIN_REGISTER()
arping_args_t
Definition: arping.h:53
arping_main
arping_main_t arping_main
Definition: arping.c:26
arping_args_t::reply_count
u32 reply_count
Definition: arping.h:64
arping_main_t::interfaces
arping_intf_t ** interfaces
Definition: arping.h:49
ARPING_DEFAULT_INTERVAL
#define ARPING_DEFAULT_INTERVAL
Definition: arping.h:21
ip4_neighbor_probe_dst
void ip4_neighbor_probe_dst(u32 sw_if_index, const ip4_address_t *dst)
Definition: ip4_neighbor.c:57
f64
double f64
Definition: types.h:142
arping_vec_validate
static void arping_vec_validate(vlib_main_t *vm, u32 sw_if_index)
Definition: arping.c:536
format_unformat_error
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
format_arping6_trace
static u8 * format_arping6_trace(u8 *s, va_list *args)
Definition: arping.c:99
ARPING_N_ERROR
@ ARPING_N_ERROR
Definition: arping.c:35
ip4_neighbor_advertise
void ip4_neighbor_advertise(vlib_main_t *vm, vnet_main_t *vnm, u32 sw_if_index, const ip4_address_t *addr)
Definition: ip4_neighbor.c:71
interval
u16 interval
Definition: vrrp.api:34
vlib_node_registration_t
struct _vlib_node_registration vlib_node_registration_t
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
arping6_input_node
vlib_node_registration_t arping6_input_node
(constructor) VLIB_REGISTER_NODE (arping6_input_node)
Definition: arping.c:472
arping_ip_address
static clib_error_t * arping_ip_address(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: arping.c:643
plugin.h
from
from
Definition: arping.c:121
vnet_main_t
Definition: vnet.h:76
arping_args_t::interval
f64 interval
Definition: arping.h:58
vlib_validate_buffer_enqueue_x1
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
arping_plugin_api_hookup
clib_error_t * arping_plugin_api_hookup(vlib_main_t *vm)
Definition: arping_api.c:67
unformat_vnet_sw_interface
unformat_function_t unformat_vnet_sw_interface
Definition: interface_funcs.h:462
arping_intf_t::interval
f64 interval
Definition: arping.h:38
format
description fragment has unexpected format
Definition: map.api:433
vlib_put_next_frame
vlib_put_next_frame(vm, node, next_index, 0)
vlib_process_suspend
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:486
arping_args_t::sw_if_index
u32 sw_if_index
Definition: arping.h:56
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
ip6_neighbor_probe_dst
void ip6_neighbor_probe_dst(u32 sw_if_index, const ip6_address_t *dst)
Definition: ip6_neighbor.c:33
ip6
vl_api_ip6_address_t ip6
Definition: one.api:424
n_left_from
n_left_from
Definition: arping.c:120
arping.h
ARPING_DEFAULT_REPEAT
#define ARPING_DEFAULT_REPEAT
Definition: arping.h:22
AF_IP6
@ AF_IP6
Definition: ip_types.h:24
ip6_header_t
Definition: ip6_packet.h:294
vnet_feature_enable_disable
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: pnat_test_stubs.h:50
mac_address_t_
Definition: mac_address.h:21
arping_args_t::is_garp
u8 is_garp
Definition: arping.h:59
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
vlib_node_t
Definition: node.h:247
vlib_add_trace
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
VNET_FEATURES
#define VNET_FEATURES(...)
Definition: feature.h:470
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
unix.h
vlib_buffer_get_current
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
foreach_arping
#define foreach_arping
Definition: arping.c:44
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
format_ip6_address
format_function_t format_ip6_address
Definition: format.h:91
arping_args_t::recv
arping46_reply_t recv
Definition: arping.h:65
arping_intf_t::repeat
u32 repeat
Definition: arping.h:39
arping_args_t::error
clib_error_t * error
Definition: arping.h:66
format_ethernet_arp_opcode
u8 * format_ethernet_arp_opcode(u8 *s, va_list *va)
Definition: arp_packet.c:23
ip_address::ip
ip46_address_t ip
Definition: ip_types.h:81
unformat_ip6_address
unformat_function_t unformat_ip6_address
Definition: format.h:89
unformat_ip4_address
unformat_function_t unformat_ip4_address
Definition: format.h:68
format_arping_trace
static u8 * format_arping_trace(u8 *s, va_list *args)
Definition: arping.c:85
vlib_validate_buffer_enqueue_x2
#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
arping_trace_t_::arp_opcode
u16 arp_opcode
Definition: arping.c:59
VNET_FEATURE_INIT
VNET_FEATURE_INIT(arping_feat_node, static)
vlib_node_runtime_t
Definition: node.h:454
arping_error_strings
static char * arping_error_strings[]
Definition: arping.c:38
vlib_cli_command_t
Definition: cli.h:92
PREDICT_TRUE
#define PREDICT_TRUE(x)
Definition: clib.h:125
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
vlib_get_next_frame
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:395
arping_trace_t_
Definition: arping.c:56
am
arping_main_t * am
Definition: arping.c:117
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_buffer_t::flags
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,...
Definition: buffer.h:133
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
VLIB_REGISTER_NODE
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169