Line data Source code
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>
22 : #include <vnet/ip-neighbor/ip4_neighbor.h>
23 : #include <vnet/ip-neighbor/ip6_neighbor.h>
24 : #include <arping/arping.h>
25 :
26 : arping_main_t arping_main;
27 :
28 : #define foreach_arping_error _ (NONE, "no error")
29 :
30 : typedef enum
31 : {
32 : #define _(f, s) ARPING_ERROR_##f,
33 : foreach_arping_error
34 : #undef _
35 : ARPING_N_ERROR,
36 : } arping__error_t;
37 :
38 : static char *arping_error_strings[] = {
39 : #define _(n, s) s,
40 : foreach_arping_error
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,
51 : foreach_arping
52 : #undef _
53 : ARPING_N_NEXT,
54 : } arping_next_t;
55 :
56 : typedef struct arping_trace_t_
57 : {
58 : u32 sw_if_index;
59 : u16 arp_opcode;
60 : ethernet_arp_ip4_over_ethernet_address_t reply;
61 : } arping_trace_t;
62 :
63 : typedef enum
64 : {
65 : #define _(sym, str) ARPING6_NEXT_##sym,
66 : foreach_arping
67 : #undef _
68 : ARPING6_N_NEXT,
69 : } arping6_next_t;
70 :
71 : typedef CLIB_PACKED (struct {
72 : mac_address_t mac;
73 : ip6_address_t ip6;
74 : }) ethernet_arp_ip6_over_ethernet_address_t;
75 :
76 : typedef struct arping6_trace_t_
77 : {
78 : u32 sw_if_index;
79 : u8 type;
80 : ethernet_arp_ip6_over_ethernet_address_t reply;
81 : } arping6_trace_t;
82 :
83 : /* packet trace format function */
84 : static u8 *
85 0 : format_arping_trace (u8 *s, va_list *args)
86 : {
87 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
88 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
89 0 : arping_trace_t *t = va_arg (*args, arping_trace_t *);
90 :
91 0 : s = format (s, "sw-if-index: %u, opcode: %U, from %U (%U)", t->sw_if_index,
92 0 : format_ethernet_arp_opcode, t->arp_opcode, format_mac_address,
93 : &t->reply.mac, format_ip4_address, &t->reply.ip4);
94 :
95 0 : return s;
96 : }
97 :
98 : static u8 *
99 0 : format_arping6_trace (u8 *s, va_list *args)
100 : {
101 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
102 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
103 0 : arping6_trace_t *t = va_arg (*args, arping6_trace_t *);
104 :
105 0 : s = format (s, "sw-if-index: %u, type: %u, from %U (%U)", t->sw_if_index,
106 0 : t->type, format_mac_address, &t->reply.mac, format_ip6_address,
107 : &t->reply.ip6);
108 :
109 0 : return s;
110 : }
111 :
112 559 : VLIB_NODE_FN (arping_input_node)
113 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
114 : {
115 : u32 n_left_from, *from, *to_next, n_left_to_next;
116 : arping_next_t next_index;
117 0 : arping_main_t *am = &arping_main;
118 :
119 0 : next_index = node->cached_next_index;
120 0 : n_left_from = frame->n_vectors;
121 0 : from = vlib_frame_vector_args (frame);
122 :
123 0 : while (n_left_from > 0)
124 : {
125 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
126 :
127 0 : 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 0 : bi0 = to_next[0] = from[0];
136 0 : bi1 = to_next[1] = from[1];
137 :
138 0 : from += 2;
139 0 : n_left_from -= 2;
140 0 : to_next += 2;
141 0 : n_left_to_next -= 2;
142 :
143 0 : next0 = next1 = ARPING_NEXT_DROP;
144 :
145 0 : b0 = vlib_get_buffer (vm, bi0);
146 0 : b1 = vlib_get_buffer (vm, bi1);
147 :
148 0 : arp0 = vlib_buffer_get_current (b0);
149 0 : arp1 = vlib_buffer_get_current (b1);
150 :
151 0 : vnet_feature_next (&next0, b0);
152 0 : vnet_feature_next (&next1, b1);
153 :
154 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
155 0 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
156 :
157 0 : if (PREDICT_TRUE (arp0->opcode ==
158 : clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
159 : {
160 0 : aif0 = am->interfaces[sw_if_index0];
161 0 : if (PREDICT_TRUE (aif0->address.ip.ip4.as_u32 ==
162 : arp0->ip4_over_ethernet[0].ip4.as_u32))
163 : {
164 0 : aif0->recv.from4.ip4.as_u32 =
165 0 : arp0->ip4_over_ethernet[0].ip4.as_u32;
166 0 : clib_memcpy_fast (&aif0->recv.from4.mac,
167 0 : &arp0->ip4_over_ethernet[0].mac, 6);
168 0 : aif0->reply_count++;
169 : }
170 : }
171 0 : if (PREDICT_TRUE (arp1->opcode ==
172 : clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
173 : {
174 0 : aif1 = am->interfaces[sw_if_index1];
175 0 : if (PREDICT_TRUE (aif1->address.ip.ip4.as_u32 ==
176 : arp1->ip4_over_ethernet[0].ip4.as_u32))
177 : {
178 0 : aif1->recv.from4.ip4.as_u32 =
179 0 : arp1->ip4_over_ethernet[0].ip4.as_u32;
180 0 : clib_memcpy_fast (&aif1->recv.from4.mac,
181 0 : &arp1->ip4_over_ethernet[0].mac, 6);
182 0 : aif1->reply_count++;
183 : }
184 : }
185 :
186 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
187 : {
188 0 : arping_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
189 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
190 0 : t->arp_opcode = clib_host_to_net_u16 (arp0->opcode);
191 0 : t->reply.ip4.as_u32 = arp0->ip4_over_ethernet[0].ip4.as_u32;
192 0 : clib_memcpy_fast (&t->reply.mac, &arp0->ip4_over_ethernet[0].mac,
193 : 6);
194 : }
195 0 : if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
196 : {
197 0 : arping_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
198 0 : t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
199 0 : t->arp_opcode = clib_host_to_net_u16 (arp1->opcode);
200 0 : t->reply.ip4.as_u32 = arp1->ip4_over_ethernet[0].ip4.as_u32;
201 0 : clib_memcpy_fast (&t->reply.mac, &arp1->ip4_over_ethernet[0].mac,
202 : 6);
203 : }
204 :
205 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
206 : n_left_to_next, bi0, bi1, next0,
207 : next1);
208 : }
209 :
210 0 : 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 0 : bi0 = to_next[0] = from[0];
219 :
220 0 : from += 1;
221 0 : n_left_from -= 1;
222 0 : to_next += 1;
223 0 : n_left_to_next -= 1;
224 0 : next0 = ARPING_NEXT_DROP;
225 :
226 0 : b0 = vlib_get_buffer (vm, bi0);
227 0 : arp0 = vlib_buffer_get_current (b0);
228 :
229 0 : vnet_feature_next (&next0, b0);
230 :
231 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
232 :
233 0 : if (PREDICT_TRUE (arp0->opcode ==
234 : clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
235 : {
236 0 : aif0 = am->interfaces[sw_if_index0];
237 0 : if (PREDICT_TRUE (aif0->address.ip.ip4.as_u32 ==
238 : arp0->ip4_over_ethernet[0].ip4.as_u32))
239 : {
240 0 : aif0->recv.from4.ip4.as_u32 =
241 0 : arp0->ip4_over_ethernet[0].ip4.as_u32;
242 0 : clib_memcpy_fast (&aif0->recv.from4.mac,
243 0 : &arp0->ip4_over_ethernet[0].mac, 6);
244 0 : aif0->reply_count++;
245 : }
246 : }
247 :
248 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
249 : {
250 0 : arping_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
251 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
252 0 : t->arp_opcode = clib_host_to_net_u16 (arp0->opcode);
253 0 : t->reply.ip4.as_u32 = arp0->ip4_over_ethernet[0].ip4.as_u32;
254 0 : clib_memcpy_fast (&t->reply.mac, &arp0->ip4_over_ethernet[0].mac,
255 : 6);
256 : }
257 :
258 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
259 : n_left_to_next, bi0, next0);
260 : }
261 :
262 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
263 : }
264 :
265 0 : return frame->n_vectors;
266 : }
267 :
268 165800 : VLIB_REGISTER_NODE (arping_input_node) =
269 : {
270 : .name = "arping-input",.vector_size = sizeof (u32),.format_trace =
271 : format_arping_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
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 62183 : 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 :
284 559 : VLIB_NODE_FN (arping6_input_node)
285 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
286 : {
287 : u32 n_left_from, *from, *to_next, n_left_to_next;
288 : arping_next_t next_index;
289 0 : arping_main_t *am = &arping_main;
290 :
291 0 : next_index = node->cached_next_index;
292 0 : n_left_from = frame->n_vectors;
293 0 : from = vlib_frame_vector_args (frame);
294 :
295 0 : while (n_left_from > 0)
296 : {
297 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
298 :
299 0 : 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 0 : bi0 = to_next[0] = from[0];
313 0 : bi1 = to_next[1] = from[1];
314 :
315 0 : from += 2;
316 0 : n_left_from -= 2;
317 0 : to_next += 2;
318 0 : n_left_to_next -= 2;
319 :
320 0 : next0 = next1 = ARPING6_NEXT_DROP;
321 :
322 0 : b0 = vlib_get_buffer (vm, bi0);
323 0 : b1 = vlib_get_buffer (vm, bi1);
324 :
325 0 : ip60 = vlib_buffer_get_current (b0);
326 0 : ip61 = vlib_buffer_get_current (b1);
327 :
328 0 : vnet_feature_next (&next0, b0);
329 0 : vnet_feature_next (&next1, b1);
330 :
331 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
332 0 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
333 :
334 0 : sol_adv0 = ip6_next_header (ip60);
335 0 : lladdr0 =
336 : (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
337 : *) (sol_adv0 + 1);
338 :
339 0 : if (PREDICT_TRUE (sol_adv0->icmp.type ==
340 : ICMP6_neighbor_advertisement))
341 : {
342 0 : aif0 = am->interfaces[sw_if_index0];
343 0 : if (PREDICT_TRUE (clib_memcmp (&aif0->address.ip.ip6,
344 : &sol_adv0->target_address,
345 : sizeof (aif0->address.ip.ip6)) ==
346 : 0))
347 : {
348 0 : clib_memcpy_fast (&aif0->recv.from6.ip6,
349 0 : &sol_adv0->target_address,
350 : sizeof (aif0->recv.from6.ip6));
351 0 : clib_memcpy_fast (&aif0->recv.from6.mac,
352 0 : lladdr0->ethernet_address, 6);
353 0 : aif0->reply_count++;
354 : }
355 : }
356 :
357 0 : sol_adv1 = ip6_next_header (ip61);
358 0 : lladdr1 =
359 : (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
360 : *) (sol_adv1 + 1);
361 :
362 0 : if (PREDICT_TRUE (sol_adv1->icmp.type ==
363 : ICMP6_neighbor_advertisement))
364 : {
365 0 : aif1 = am->interfaces[sw_if_index1];
366 0 : if (PREDICT_TRUE (clib_memcmp (&aif1->address.ip.ip6,
367 : &sol_adv1->target_address,
368 : sizeof (aif1->address.ip.ip6)) ==
369 : 0))
370 : {
371 0 : clib_memcpy_fast (&aif1->recv.from6.ip6,
372 0 : &sol_adv1->target_address,
373 : sizeof (aif1->recv.from6.ip6));
374 0 : clib_memcpy_fast (&aif1->recv.from6.mac,
375 0 : lladdr1->ethernet_address, 6);
376 0 : aif1->reply_count++;
377 : }
378 : }
379 :
380 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
381 : {
382 0 : arping6_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
383 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
384 0 : t->type = sol_adv0->icmp.type;
385 0 : clib_memcpy_fast (&t->reply.ip6, &sol_adv0->target_address,
386 : sizeof (t->reply.ip6));
387 0 : clib_memcpy_fast (&t->reply.mac, lladdr0->ethernet_address, 6);
388 : }
389 0 : if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
390 : {
391 0 : arping6_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
392 0 : t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
393 0 : t->type = sol_adv1->icmp.type;
394 0 : clib_memcpy_fast (&t->reply.ip6, &sol_adv1->target_address,
395 : sizeof (t->reply.ip6));
396 0 : clib_memcpy_fast (&t->reply.mac, lladdr1->ethernet_address, 6);
397 : }
398 :
399 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
400 : n_left_to_next, bi0, bi1, next0,
401 : next1);
402 : }
403 :
404 0 : 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 0 : bi0 = to_next[0] = from[0];
416 :
417 0 : from += 1;
418 0 : n_left_from -= 1;
419 0 : to_next += 1;
420 0 : n_left_to_next -= 1;
421 0 : next0 = ARPING_NEXT_DROP;
422 :
423 0 : b0 = vlib_get_buffer (vm, bi0);
424 0 : ip60 = vlib_buffer_get_current (b0);
425 :
426 0 : vnet_feature_next (&next0, b0);
427 :
428 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
429 :
430 0 : sol_adv0 = ip6_next_header (ip60);
431 0 : lladdr0 =
432 : (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
433 : *) (sol_adv0 + 1);
434 0 : if (PREDICT_TRUE (sol_adv0->icmp.type ==
435 : ICMP6_neighbor_advertisement))
436 : {
437 0 : aif0 = am->interfaces[sw_if_index0];
438 0 : if (PREDICT_TRUE (clib_memcmp (&aif0->address.ip.ip6,
439 : &sol_adv0->target_address,
440 : sizeof (aif0->address.ip.ip6)) ==
441 : 0))
442 : {
443 0 : clib_memcpy_fast (&aif0->recv.from6.ip6,
444 0 : &sol_adv0->target_address,
445 : sizeof (aif0->recv.from6.ip6));
446 0 : clib_memcpy_fast (&aif0->recv.from6.mac,
447 0 : lladdr0->ethernet_address, 6);
448 0 : aif0->reply_count++;
449 : }
450 : }
451 :
452 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
453 : {
454 0 : arping6_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
455 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
456 0 : t->type = sol_adv0->icmp.type;
457 0 : clib_memcpy_fast (&t->reply.ip6, &sol_adv0->target_address,
458 : sizeof (t->reply.ip6));
459 0 : clib_memcpy_fast (&t->reply.mac, lladdr0->ethernet_address, 6);
460 : }
461 :
462 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
463 : n_left_to_next, bi0, next0);
464 : }
465 :
466 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
467 : }
468 :
469 0 : return frame->n_vectors;
470 : }
471 :
472 165800 : VLIB_REGISTER_NODE (arping6_input_node) =
473 : {
474 : .name = "arping6-input",.vector_size = sizeof (u32),.format_trace =
475 : format_arping6_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
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 62183 : 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 *
489 8 : arping_neighbor_advertisement (vlib_main_t *vm, arping_args_t *args)
490 : {
491 8 : vnet_main_t *vnm = vnet_get_main ();
492 8 : u32 send_count = 0;
493 :
494 32 : while (args->repeat > 0)
495 : {
496 24 : send_count++;
497 24 : if (args->address.version == AF_IP4)
498 : {
499 12 : if (args->silence == 0)
500 6 : vlib_cli_output (vm, "Sending %u GARP to %U", send_count,
501 : format_ip4_address, &args->address.ip.ip4);
502 12 : ip4_neighbor_advertise (vm, vnm, args->sw_if_index,
503 12 : vlib_get_thread_index (),
504 12 : &args->address.ip.ip4);
505 : }
506 : else
507 : {
508 12 : if (args->silence == 0)
509 6 : vlib_cli_output (vm, "Sending %u Neighbor Advertisement to %U",
510 : send_count, format_ip6_address,
511 : &args->address.ip.ip6);
512 12 : ip6_neighbor_advertise (vm, vnm, args->sw_if_index,
513 12 : vlib_get_thread_index (),
514 12 : &args->address.ip.ip6);
515 : }
516 24 : args->repeat--;
517 24 : if ((args->interval > 0.0) && (args->repeat > 0))
518 16 : vlib_process_suspend (vm, args->interval);
519 : }
520 :
521 8 : return 0;
522 : }
523 :
524 : static void
525 16 : arping_vnet_feature_enable_disable (vlib_main_t *vm, const char *arc_name,
526 : const char *node_name, u32 sw_if_index,
527 : int enable_disable, void *feature_config,
528 : u32 n_feature_config_bytes)
529 : {
530 16 : vlib_worker_thread_barrier_sync (vm);
531 16 : vnet_feature_enable_disable (arc_name, node_name, sw_if_index,
532 : enable_disable, feature_config,
533 : n_feature_config_bytes);
534 16 : vlib_worker_thread_barrier_release (vm);
535 16 : }
536 :
537 : static void
538 8 : arping_vec_validate (vlib_main_t *vm, u32 sw_if_index)
539 : {
540 8 : arping_main_t *am = &arping_main;
541 :
542 8 : if (sw_if_index >= vec_len (am->interfaces))
543 : {
544 1 : vlib_worker_thread_barrier_sync (vm);
545 1 : vec_validate (am->interfaces, sw_if_index);
546 1 : vlib_worker_thread_barrier_release (vm);
547 : }
548 8 : }
549 :
550 : static clib_error_t *
551 8 : arping_neighbor_probe_dst (vlib_main_t *vm, arping_args_t *args)
552 : {
553 8 : arping_main_t *am = &arping_main;
554 8 : u32 send_count = 0;
555 : clib_error_t *error;
556 : arping_intf_t aif;
557 :
558 : /* Disallow multiple sends on the same interface for now. Who needs it? */
559 8 : if ((vec_len (am->interfaces) > args->sw_if_index) &&
560 7 : (am->interfaces[args->sw_if_index] != 0))
561 : {
562 0 : error = clib_error_return (
563 : 0, "arping command is in progress for the same interface. "
564 : "Please try again later.");
565 0 : args->rv = VNET_API_ERROR_INVALID_VALUE;
566 0 : return error;
567 : }
568 :
569 8 : arping_vec_validate (vm, args->sw_if_index);
570 8 : clib_memset (&aif, 0, sizeof (aif));
571 8 : aif.interval = args->interval;
572 8 : aif.repeat = args->repeat;
573 8 : aif.reply_count = 0;
574 8 : am->interfaces[args->sw_if_index] = &aif;
575 :
576 8 : clib_memcpy (&aif.address, &args->address, sizeof (aif.address));
577 8 : if (args->address.version == AF_IP4)
578 4 : arping_vnet_feature_enable_disable (vm, "arp", "arping-input",
579 : args->sw_if_index, 1, 0, 0);
580 : else
581 4 : arping_vnet_feature_enable_disable (vm, "ip6-local", "arping6-input",
582 : args->sw_if_index, 1, 0, 0);
583 :
584 32 : while (args->repeat > 0)
585 : {
586 24 : send_count++;
587 24 : if (args->address.version == AF_IP4)
588 : {
589 12 : if (args->silence == 0)
590 6 : vlib_cli_output (vm, "Sending %u ARP Request to %U", send_count,
591 : format_ip4_address, &args->address.ip.ip4);
592 12 : ip4_neighbor_probe_dst (args->sw_if_index, vlib_get_thread_index (),
593 12 : &args->address.ip.ip4);
594 : }
595 : else
596 : {
597 12 : if (args->silence == 0)
598 6 : vlib_cli_output (vm, "Sending %u Neighbor Solicitation to %U",
599 : send_count, format_ip6_address,
600 : &args->address.ip.ip6);
601 12 : ip6_neighbor_probe_dst (args->sw_if_index, vlib_get_thread_index (),
602 12 : &args->address.ip.ip6);
603 : }
604 24 : args->repeat--;
605 24 : if ((args->interval > 0.0) && (args->repeat > 0))
606 16 : vlib_process_suspend (vm, args->interval);
607 : }
608 :
609 : /* wait for a second on the reply */
610 8 : u32 wait_count = 0;
611 88 : while ((aif.reply_count < send_count) && (wait_count < 10))
612 : {
613 80 : vlib_process_suspend (vm, 0.1);
614 80 : wait_count++;
615 : }
616 :
617 8 : if (args->address.version == AF_IP4)
618 : {
619 4 : clib_memcpy (&args->recv.from4, &aif.recv.from4,
620 : sizeof (args->recv.from4));
621 4 : arping_vnet_feature_enable_disable (vm, "arp", "arping-input",
622 : args->sw_if_index, 0, 0, 0);
623 : }
624 : else
625 : {
626 4 : clib_memcpy (&args->recv.from6, &aif.recv.from6,
627 : sizeof (args->recv.from6));
628 4 : arping_vnet_feature_enable_disable (vm, "ip6-local", "arping6-input",
629 : args->sw_if_index, 0, 0, 0);
630 : }
631 8 : args->reply_count = aif.reply_count;
632 :
633 8 : am->interfaces[args->sw_if_index] = 0;
634 :
635 8 : return 0;
636 : }
637 :
638 : void
639 16 : arping_run_command (vlib_main_t *vm, arping_args_t *args)
640 : {
641 16 : if (args->is_garp)
642 8 : args->error = arping_neighbor_advertisement (vm, args);
643 : else
644 8 : args->error = arping_neighbor_probe_dst (vm, args);
645 16 : }
646 :
647 : static clib_error_t *
648 8 : arping_ip_address (vlib_main_t *vm, unformat_input_t *input,
649 : vlib_cli_command_t *cmd)
650 : {
651 8 : clib_error_t *error = 0;
652 8 : vnet_main_t *vnm = vnet_get_main ();
653 8 : arping_args_t args = { 0 };
654 8 : f64 interval = ARPING_DEFAULT_INTERVAL;
655 :
656 8 : args.repeat = ARPING_DEFAULT_REPEAT;
657 8 : args.interval = ARPING_DEFAULT_INTERVAL;
658 8 : args.sw_if_index = ~0;
659 8 : args.silence = 0;
660 :
661 8 : if (unformat (input, "gratuitous"))
662 4 : args.is_garp = 1;
663 :
664 8 : if (unformat (input, "%U", unformat_ip4_address, &args.address.ip.ip4))
665 4 : args.address.version = AF_IP4;
666 4 : else if (unformat (input, "%U", unformat_ip6_address, &args.address.ip.ip6))
667 4 : args.address.version = AF_IP6;
668 : else
669 : {
670 0 : error = clib_error_return (
671 : 0,
672 : "expecting IP4/IP6 address `%U'. Usage: arping [gratuitous] <addr> "
673 : "<intf> [repeat <count>] [interval <secs>]",
674 : format_unformat_error, input);
675 0 : goto done;
676 : }
677 :
678 8 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm,
679 : &args.sw_if_index))
680 : {
681 0 : error = clib_error_return (0, "unknown interface `%U'",
682 : format_unformat_error, input);
683 0 : goto done;
684 : }
685 :
686 : /* parse the rest of the parameters in a cycle */
687 16 : while (!unformat_eof (input, NULL))
688 : {
689 8 : if (unformat (input, "interval"))
690 : {
691 4 : if (!unformat (input, "%f", &interval))
692 : {
693 0 : error = clib_error_return (
694 : 0, "expecting interval (floating point number) got `%U'",
695 : format_unformat_error, input);
696 0 : goto done;
697 : }
698 4 : args.interval = interval;
699 : }
700 4 : else if (unformat (input, "repeat"))
701 : {
702 4 : if (!unformat (input, "%u", &args.repeat))
703 : {
704 : error =
705 0 : clib_error_return (0, "expecting repeat count but got `%U'",
706 : format_unformat_error, input);
707 0 : goto done;
708 : }
709 : }
710 : else
711 : {
712 0 : error = clib_error_return (0, "unknown input `%U'",
713 : format_unformat_error, input);
714 0 : goto done;
715 : }
716 : }
717 :
718 8 : arping_run_command (vm, &args);
719 :
720 8 : if (args.reply_count)
721 : {
722 0 : if (args.address.version == AF_IP4)
723 0 : vlib_cli_output (vm, "Received %u ARP Replies from %U (%U)",
724 : args.reply_count, format_mac_address,
725 : &args.recv.from4.mac, format_ip4_address,
726 : &args.recv.from4.ip4);
727 : else
728 0 : vlib_cli_output (
729 : vm, "Received %u ICMP6 neighbor advertisements from %U (%U)",
730 : args.reply_count, format_mac_address, &args.recv.from6.mac,
731 : format_ip6_address, &args.recv.from6.ip6);
732 : }
733 8 : else if (args.is_garp == 0)
734 4 : vlib_cli_output (vm, "Received 0 Reply");
735 :
736 8 : error = args.error;
737 8 : done:
738 8 : return error;
739 : }
740 : // clang-format off
741 : /*?
742 : * This command sends an ARP REQUEST or gratuitous ARP to network hosts. The
743 : * address can be an IPv4 or IPv6 address.
744 : *
745 : * @cliexpar
746 : * @parblock
747 : * Example of how to send an IPv4 ARP REQUEST
748 : * @cliexstart{arping 100.1.1.10 VirtualEthernet0/0/0 repeat 3 interval 1}
749 : * Sending 1 ARP Request to 100.1.1.10
750 : * Sending 2 ARP Request to 100.1.1.10
751 : * Sending 3 ARP Request to 100.1.1.10
752 : * Received 3 ARP Replies from 52:53:00:00:04:01 (100.1.1.10)
753 : * @cliexend
754 : *
755 : * Example of how to send an IPv6 Neighbor Solicitation
756 : * @cliexstart{arping 2001:192::2 VirtualEthernet0/0/0 repeat 3 interval 1}
757 : * Sending 1 Neighbor Solicitation to 2001:192::2
758 : * Sending 2 Neighbor Solicitation to 2001:192::2
759 : * Sending 3 Neighbor Solicitation to 2001:192::2
760 : * Received 3 ICMP6 neighbor advertisements from 52:53:00:00:04:01 (2001:192::2)
761 : * @cliexend
762 : *
763 : * Example of how to send an IPv4 gratuitous ARP
764 : * @cliexstart{arping gratuitous 100.1.1.100 VirtualEthernet0/0/0 repeat 2}
765 : * Sending 1 GARP to 100.1.1.100
766 : * Sending 2 GARP to 100.1.1.100
767 : * @cliexend
768 : * @endparblock
769 : *
770 : ?*/
771 : // clang-format on
772 257767 : VLIB_CLI_COMMAND (arping_command, static) = {
773 : .path = "arping",
774 : .function = arping_ip_address,
775 : .short_help = "arping [gratuitous] {addr} {interface}"
776 : " [interval {sec}] [repeat {cnt}]",
777 : .is_mp_safe = 1,
778 : };
779 :
780 : static clib_error_t *
781 559 : arping_cli_init (vlib_main_t *vm)
782 : {
783 : /* initialize binary API */
784 559 : arping_plugin_api_hookup (vm);
785 :
786 559 : return 0;
787 : }
788 :
789 1119 : VLIB_INIT_FUNCTION (arping_cli_init);
790 :
791 : VLIB_PLUGIN_REGISTER () = {
792 : .version = VPP_BUILD_VER,
793 : .description = "Arping (arping)",
794 : };
795 :
796 : /*
797 : * fd.io coding-style-patch-verification: ON
798 : *
799 : * Local Variables:
800 : * eval: (c-set-style "gnu")
801 : * End:
802 : */
|