LCOV - code coverage report
Current view: top level - plugins/arping - arping.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 118 312 37.8 %
Date: 2023-10-26 01:39:38 Functions: 21 25 84.0 %

          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         575 : 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      171116 : 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       67995 : 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         575 : 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      171116 : 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       67995 : 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      269737 : 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         575 : arping_cli_init (vlib_main_t *vm)
     782             : {
     783             :   /* initialize binary API */
     784         575 :   arping_plugin_api_hookup (vm);
     785             : 
     786         575 :   return 0;
     787             : }
     788             : 
     789        1151 : 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             :  */

Generated by: LCOV version 1.14