LCOV - code coverage report
Current view: top level - vnet/arp - arp.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 260 307 84.7 %
Date: 2023-07-05 22:20:52 Functions: 33 37 89.2 %

          Line data    Source code
       1             : /*
       2             :  * ethernet/arp.c: IP v4 ARP node
       3             :  *
       4             :  * Copyright (c) 2010 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vnet/arp/arp.h>
      19             : #include <vnet/arp/arp_packet.h>
      20             : 
      21             : #include <vnet/fib/ip4_fib.h>
      22             : #include <vnet/fib/fib_entry_src.h>
      23             : #include <vnet/adj/adj_nbr.h>
      24             : #include <vnet/adj/adj_mcast.h>
      25             : #include <vnet/pg/pg.h>
      26             : 
      27             : #include <vnet/ip-neighbor/ip_neighbor.h>
      28             : #include <vnet/ip-neighbor/ip4_neighbor.h>
      29             : #include <vnet/ip-neighbor/ip_neighbor_dp.h>
      30             : 
      31             : #include <vlibmemory/api.h>
      32             : 
      33             : /**
      34             :  * @file
      35             :  * @brief IPv4 ARP.
      36             :  *
      37             :  * This file contains code to manage the IPv4 ARP tables (IP Address
      38             :  * to MAC Address lookup).
      39             :  */
      40             : 
      41             : /**
      42             :  * @brief Per-interface ARP configuration and state
      43             :  */
      44             : typedef struct ethernet_arp_interface_t_
      45             : {
      46             :   /**
      47             :    * Is ARP enabled on this interface
      48             :    */
      49             :   u32 enabled;
      50             : } ethernet_arp_interface_t;
      51             : 
      52             : typedef struct
      53             : {
      54             :   /* Hash tables mapping name to opcode. */
      55             :   uword *opcode_by_name;
      56             : 
      57             :   /** Per interface state */
      58             :   ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
      59             : 
      60             :   /* ARP feature arc index */
      61             :   u8 feature_arc_index;
      62             : } ethernet_arp_main_t;
      63             : 
      64             : static ethernet_arp_main_t ethernet_arp_main;
      65             : 
      66             : static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 };
      67             : 
      68             : static uword
      69           0 : unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
      70             :                                               va_list * args)
      71             : {
      72           0 :   int *result = va_arg (*args, int *);
      73           0 :   ethernet_arp_main_t *am = &ethernet_arp_main;
      74             :   int x, i;
      75             : 
      76             :   /* Numeric opcode. */
      77           0 :   if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
      78             :     {
      79           0 :       if (x >= (1 << 16))
      80           0 :         return 0;
      81           0 :       *result = x;
      82           0 :       return 1;
      83             :     }
      84             : 
      85             :   /* Named type. */
      86           0 :   if (unformat_user (input, unformat_vlib_number_by_name,
      87             :                      am->opcode_by_name, &i))
      88             :     {
      89           0 :       *result = i;
      90           0 :       return 1;
      91             :     }
      92             : 
      93           0 :   return 0;
      94             : }
      95             : 
      96             : static uword
      97           0 : unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
      98             :                                              va_list * args)
      99             : {
     100           0 :   int *result = va_arg (*args, int *);
     101           0 :   if (!unformat_user
     102             :       (input, unformat_ethernet_arp_opcode_host_byte_order, result))
     103           0 :     return 0;
     104             : 
     105           0 :   *result = clib_host_to_net_u16 ((u16) * result);
     106           0 :   return 1;
     107             : }
     108             : 
     109             : typedef struct
     110             : {
     111             :   u8 packet_data[64];
     112             : } ethernet_arp_input_trace_t;
     113             : 
     114             : static u8 *
     115        4029 : format_ethernet_arp_input_trace (u8 * s, va_list * va)
     116             : {
     117        4029 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     118        4029 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     119        4029 :   ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
     120             : 
     121        4029 :   s = format (s, "%U",
     122             :               format_ethernet_arp_header,
     123        4029 :               t->packet_data, sizeof (t->packet_data));
     124             : 
     125        4029 :   return s;
     126             : }
     127             : 
     128             : static int
     129       12089 : arp_is_enabled (ethernet_arp_main_t * am, u32 sw_if_index)
     130             : {
     131       12089 :   if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
     132        8019 :     return 0;
     133             : 
     134        4070 :   return (am->ethernet_arp_by_sw_if_index[sw_if_index].enabled);
     135             : }
     136             : 
     137             : static void
     138        2463 : arp_enable (ethernet_arp_main_t * am, u32 sw_if_index)
     139             : {
     140        2463 :   if (arp_is_enabled (am, sw_if_index))
     141           0 :     return;
     142             : 
     143        2463 :   vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
     144             : 
     145        2463 :   am->ethernet_arp_by_sw_if_index[sw_if_index].enabled = 1;
     146             : 
     147        2463 :   vnet_feature_enable_disable ("arp", "arp-reply", sw_if_index, 1, NULL, 0);
     148        2463 :   vnet_feature_enable_disable ("arp", "arp-disabled", sw_if_index, 0, NULL,
     149             :                                0);
     150             : }
     151             : 
     152             : static void
     153        9626 : arp_disable (ethernet_arp_main_t * am, u32 sw_if_index)
     154             : {
     155        9626 :   if (!arp_is_enabled (am, sw_if_index))
     156        7418 :     return;
     157             : 
     158        2208 :   vnet_feature_enable_disable ("arp", "arp-disabled", sw_if_index, 1, NULL,
     159             :                                0);
     160        2208 :   vnet_feature_enable_disable ("arp", "arp-reply", sw_if_index, 0, NULL, 0);
     161             : 
     162        2208 :   am->ethernet_arp_by_sw_if_index[sw_if_index].enabled = 0;
     163             : }
     164             : 
     165             : static int
     166          22 : arp_unnumbered (vlib_buffer_t * p0,
     167             :                 u32 input_sw_if_index, u32 conn_sw_if_index)
     168             : {
     169          22 :   vnet_main_t *vnm = vnet_get_main ();
     170          22 :   vnet_interface_main_t *vim = &vnm->interface_main;
     171             :   vnet_sw_interface_t *si;
     172             : 
     173             :   /* verify that the input interface is unnumbered to the connected.
     174             :    * the connected interface is the interface on which the subnet is
     175             :    * configured */
     176          22 :   si = &vim->sw_interfaces[input_sw_if_index];
     177             : 
     178          22 :   if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
     179           5 :         (si->unnumbered_sw_if_index == conn_sw_if_index)))
     180             :     {
     181             :       /* the input interface is not unnumbered to the interface on which
     182             :        * the sub-net is configured that covers the ARP request.
     183             :        * So this is not the case for unnumbered.. */
     184          17 :       return 0;
     185             :     }
     186             : 
     187           5 :   return !0;
     188             : }
     189             : 
     190             : always_inline u32
     191        2010 : arp_learn (u32 sw_if_index,
     192             :            const ethernet_arp_ip4_over_ethernet_address_t * addr)
     193             : {
     194             :   /* *INDENT-OFF* */
     195        2010 :   ip_neighbor_learn_t l = {
     196             :     .ip = {
     197             :       .ip.ip4 = addr->ip4,
     198             :       .version = AF_IP4,
     199             :     },
     200             :     .mac = addr->mac,
     201             :     .sw_if_index = sw_if_index,
     202             :   };
     203             :   /* *INDENT-ON* */
     204             : 
     205        2010 :   ip_neighbor_learn_dp (&l);
     206             : 
     207        2010 :   return (ARP_ERROR_L3_SRC_ADDRESS_LEARNED);
     208             : }
     209             : 
     210             : typedef enum arp_input_next_t_
     211             : {
     212             :   ARP_INPUT_NEXT_DROP,
     213             :   ARP_INPUT_NEXT_DISABLED,
     214             :   ARP_INPUT_N_NEXT,
     215             : } arp_input_next_t;
     216             : 
     217             : static uword
     218        2120 : arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
     219             : {
     220             :   u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
     221        2120 :   ethernet_arp_main_t *am = &ethernet_arp_main;
     222             : 
     223        2120 :   from = vlib_frame_vector_args (frame);
     224        2120 :   n_left_from = frame->n_vectors;
     225        2120 :   next_index = node->cached_next_index;
     226             : 
     227        2120 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     228        2009 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     229             :                                    /* stride */ 1,
     230             :                                    sizeof (ethernet_arp_input_trace_t));
     231             : 
     232        4240 :   while (n_left_from > 0)
     233             :     {
     234        2120 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     235             : 
     236        4242 :       while (n_left_from > 0 && n_left_to_next > 0)
     237             :         {
     238             :           const ethernet_arp_header_t *arp0;
     239             :           arp_input_next_t next0;
     240             :           vlib_buffer_t *p0;
     241             :           u32 pi0, error0;
     242             : 
     243        2122 :           pi0 = to_next[0] = from[0];
     244        2122 :           from += 1;
     245        2122 :           to_next += 1;
     246        2122 :           n_left_from -= 1;
     247        2122 :           n_left_to_next -= 1;
     248             : 
     249        2122 :           p0 = vlib_get_buffer (vm, pi0);
     250        2122 :           arp0 = vlib_buffer_get_current (p0);
     251             : 
     252        2122 :           error0 = ARP_ERROR_REPLIES_SENT;
     253        2122 :           next0 = ARP_INPUT_NEXT_DROP;
     254             : 
     255        2122 :           error0 = (arp0->l2_type != clib_net_to_host_u16 (
     256             :                                        ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
     257        2122 :                             ARP_ERROR_L2_TYPE_NOT_ETHERNET :
     258             :                             error0);
     259        2122 :           error0 = (arp0->l3_type != clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
     260        2122 :                             ARP_ERROR_L3_TYPE_NOT_IP4 :
     261             :                             error0);
     262        4244 :           error0 = (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ?
     263        2122 :                             ARP_ERROR_L3_DST_ADDRESS_UNSET :
     264             :                             error0);
     265             : 
     266        2122 :           if (ARP_ERROR_REPLIES_SENT == error0)
     267             :             {
     268        2122 :               next0 = ARP_INPUT_NEXT_DISABLED;
     269        2122 :               vnet_feature_arc_start (am->feature_arc_index,
     270        2122 :                                       vnet_buffer (p0)->sw_if_index[VLIB_RX],
     271             :                                       &next0, p0);
     272             :             }
     273             :           else
     274           0 :             p0->error = node->errors[error0];
     275             : 
     276        2122 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     277             :                                            n_left_to_next, pi0, next0);
     278             :         }
     279             : 
     280        2120 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     281             :     }
     282             : 
     283        2120 :   return frame->n_vectors;
     284             : }
     285             : 
     286             : typedef enum arp_disabled_next_t_
     287             : {
     288             :   ARP_DISABLED_NEXT_DROP,
     289             :   ARP_DISABLED_N_NEXT,
     290             : } arp_disabled_next_t;
     291             : 
     292             : static uword
     293           5 : arp_disabled (vlib_main_t * vm,
     294             :               vlib_node_runtime_t * node, vlib_frame_t * frame)
     295             : {
     296             :   u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
     297             : 
     298           5 :   from = vlib_frame_vector_args (frame);
     299           5 :   n_left_from = frame->n_vectors;
     300           5 :   next_index = node->cached_next_index;
     301             : 
     302           5 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     303           5 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     304             :                                    /* stride */ 1,
     305             :                                    sizeof (ethernet_arp_input_trace_t));
     306             : 
     307          10 :   while (n_left_from > 0)
     308             :     {
     309           5 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     310             : 
     311          10 :       while (n_left_from > 0 && n_left_to_next > 0)
     312             :         {
     313           5 :           arp_disabled_next_t next0 = ARP_DISABLED_NEXT_DROP;
     314             :           vlib_buffer_t *p0;
     315             :           u32 pi0, error0;
     316             : 
     317           5 :           next0 = ARP_DISABLED_NEXT_DROP;
     318           5 :           error0 = ARP_ERROR_DISABLED;
     319             : 
     320           5 :           pi0 = to_next[0] = from[0];
     321           5 :           from += 1;
     322           5 :           to_next += 1;
     323           5 :           n_left_from -= 1;
     324           5 :           n_left_to_next -= 1;
     325             : 
     326           5 :           p0 = vlib_get_buffer (vm, pi0);
     327           5 :           p0->error = node->errors[error0];
     328             : 
     329           5 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     330             :                                            n_left_to_next, pi0, next0);
     331             :         }
     332             : 
     333           5 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     334             :     }
     335             : 
     336           5 :   return frame->n_vectors;
     337             : }
     338             : 
     339             : enum arp_dst_fib_type
     340             : {
     341             :   ARP_DST_FIB_NONE,
     342             :   ARP_DST_FIB_ADJ,
     343             :   ARP_DST_FIB_CONN
     344             : };
     345             : 
     346             : /*
     347             :  * we're looking for FIB sources that indicate the destination
     348             :  * is attached. There may be interposed DPO prior to the one
     349             :  * we are looking for
     350             :  */
     351             : static enum arp_dst_fib_type
     352        2052 : arp_dst_fib_check (const fib_node_index_t fei, fib_entry_flag_t * flags)
     353             : {
     354        2052 :   const fib_entry_t *entry = fib_entry_get (fei);
     355             :   const fib_entry_src_t *entry_src;
     356             :   fib_source_t src;
     357             :   /* *INDENT-OFF* */
     358        2066 :   FOR_EACH_SRC_ADDED(entry, entry_src, src,
     359             :   ({
     360             :     *flags = fib_entry_get_flags_for_source (fei, src);
     361             :     if (fib_entry_is_sourced (fei, FIB_SOURCE_ADJ))
     362             :         return ARP_DST_FIB_ADJ;
     363             :       else if (FIB_ENTRY_FLAG_CONNECTED & *flags)
     364             :         return ARP_DST_FIB_CONN;
     365             :   }))
     366             :   /* *INDENT-ON* */
     367             : 
     368          14 :   return ARP_DST_FIB_NONE;
     369             : }
     370             : 
     371             : static uword
     372        2106 : arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
     373             : {
     374        2106 :   vnet_main_t *vnm = vnet_get_main ();
     375             :   u32 n_left_from, next_index, *from, *to_next;
     376        2106 :   u32 n_replies_sent = 0;
     377             : 
     378        2106 :   from = vlib_frame_vector_args (frame);
     379        2106 :   n_left_from = frame->n_vectors;
     380        2106 :   next_index = node->cached_next_index;
     381             : 
     382        2106 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     383        1995 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     384             :                                    /* stride */ 1,
     385             :                                    sizeof (ethernet_arp_input_trace_t));
     386             : 
     387        4212 :   while (n_left_from > 0)
     388             :     {
     389             :       u32 n_left_to_next;
     390             : 
     391        2106 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     392             : 
     393        4214 :       while (n_left_from > 0 && n_left_to_next > 0)
     394             :         {
     395             :           vlib_buffer_t *p0;
     396             :           ethernet_arp_header_t *arp0;
     397             :           ethernet_header_t *eth_rx;
     398             :           const ip4_address_t *if_addr0;
     399             :           u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
     400             :           u8 dst_is_local0, is_vrrp_reply0;
     401             :           fib_node_index_t dst_fei, src_fei;
     402             :           const fib_prefix_t *pfx0;
     403             :           fib_entry_flag_t src_flags, dst_flags;
     404             : 
     405        2108 :           pi0 = from[0];
     406        2108 :           to_next[0] = pi0;
     407        2108 :           from += 1;
     408        2108 :           to_next += 1;
     409        2108 :           n_left_from -= 1;
     410        2108 :           n_left_to_next -= 1;
     411             : 
     412        2108 :           p0 = vlib_get_buffer (vm, pi0);
     413        2108 :           arp0 = vlib_buffer_get_current (p0);
     414             :           /* Fill in ethernet header. */
     415        2108 :           eth_rx = ethernet_buffer_get_header (p0);
     416             : 
     417        2108 :           next0 = ARP_REPLY_NEXT_DROP;
     418        2108 :           error0 = ARP_ERROR_REPLIES_SENT;
     419        2108 :           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
     420             : 
     421             :           /* Check that IP address is local and matches incoming interface. */
     422        2108 :           fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     423        2108 :           if (~0 == fib_index0)
     424             :             {
     425           0 :               error0 = ARP_ERROR_INTERFACE_NO_TABLE;
     426           0 :               goto drop;
     427             : 
     428             :             }
     429             : 
     430             :           {
     431             :             /*
     432             :              * we're looking for FIB entries that indicate the source
     433             :              * is attached. There may be more specific non-attached
     434             :              * routes that match the source, but these do not influence
     435             :              * whether we respond to an ARP request, i.e. they do not
     436             :              * influence whether we are the correct way for the sender
     437             :              * to reach us, they only affect how we reach the sender.
     438             :              */
     439             :             fib_entry_t *src_fib_entry;
     440             :             const fib_prefix_t *pfx;
     441             :             fib_entry_src_t *src;
     442             :             fib_source_t source;
     443             :             int attached;
     444             :             int mask;
     445             : 
     446        2108 :             mask = 32;
     447        2108 :             attached = 0;
     448             : 
     449             :             do
     450             :               {
     451        2109 :                 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
     452        2109 :                                                 &arp0->
     453             :                                                 ip4_over_ethernet[0].ip4,
     454             :                                                 mask);
     455        2109 :                 src_fib_entry = fib_entry_get (src_fei);
     456             : 
     457             :                 /*
     458             :                  * It's possible that the source that provides the
     459             :                  * flags we need, or the flags we must not have,
     460             :                  * is not the best source, so check then all.
     461             :                  */
     462             :                 /* *INDENT-OFF* */
     463        2114 :                 FOR_EACH_SRC_ADDED(src_fib_entry, src, source,
     464             :                 ({
     465             :                   src_flags = fib_entry_get_flags_for_source (src_fei, source);
     466             : 
     467             :                   /* Reject requests/replies with our local interface
     468             :                      address. */
     469             :                   if (FIB_ENTRY_FLAG_LOCAL & src_flags)
     470             :                     {
     471             :                       error0 = ARP_ERROR_L3_SRC_ADDRESS_IS_LOCAL;
     472             :                       /*
     473             :                        * When VPP has an interface whose address is also
     474             :                        * applied to a TAP interface on the host, then VPP's
     475             :                        * TAP interface will be unnumbered  to the 'real'
     476             :                        * interface and do proxy ARP from the host.
     477             :                        * The curious aspect of this setup is that ARP requests
     478             :                        * from the host will come from the VPP's own address.
     479             :                        * So don't drop immediately here, instead go see if this
     480             :                        * is a proxy ARP case.
     481             :                        */
     482             :                       goto next_feature;
     483             :                     }
     484             :                   /* A Source must also be local to subnet of matching
     485             :                    * interface address. */
     486             :                   if ((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
     487             :                       (FIB_ENTRY_FLAG_CONNECTED & src_flags))
     488             :                     {
     489             :                       attached = 1;
     490             :                       break;
     491             :                     }
     492             :                   /*
     493             :                    * else
     494             :                    *  The packet was sent from an address that is not
     495             :                    *  connected nor attached i.e. it is not from an
     496             :                    *  address that is covered by a link's sub-net,
     497             :                    *  nor is it a already learned host resp.
     498             :                    */
     499             :                 }));
     500             :                 /* *INDENT-ON* */
     501             : 
     502             :                 /*
     503             :                  * shorter mask lookup for the next iteration.
     504             :                  */
     505        2056 :                 pfx = fib_entry_get_prefix (src_fei);
     506        2056 :                 mask = pfx->fp_len - 1;
     507             : 
     508             :                 /*
     509             :                  * continue until we hit the default route or we find
     510             :                  * the attached we are looking for. The most likely
     511             :                  * outcome is we find the attached with the first source
     512             :                  * on the first lookup.
     513             :                  */
     514             :               }
     515           4 :             while (!attached &&
     516        2056 :                    !fib_entry_is_sourced (src_fei, FIB_SOURCE_DEFAULT_ROUTE));
     517             : 
     518        2055 :             if (!attached)
     519             :               {
     520             :                 /*
     521             :                  * the matching route is a not attached, i.e. it was
     522             :                  * added as a result of routing, rather than interface/ARP
     523             :                  * configuration. If the matching route is not a host route
     524             :                  * (i.e. a /32)
     525             :                  */
     526           3 :                 error0 = ARP_ERROR_L3_SRC_ADDRESS_NOT_LOCAL;
     527           3 :                 goto drop;
     528             :               }
     529             :           }
     530             : 
     531        2052 :           dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
     532        2052 :                                           &arp0->ip4_over_ethernet[1].ip4,
     533             :                                           32);
     534        2052 :           conn_sw_if_index0 = fib_entry_get_any_resolving_interface (dst_fei);
     535             : 
     536        2052 :           switch (arp_dst_fib_check (dst_fei, &dst_flags))
     537             :             {
     538           7 :             case ARP_DST_FIB_ADJ:
     539             :               /*
     540             :                * We matched an adj-fib on ths source subnet (a /32 previously
     541             :                * added as a result of ARP). If this request is a gratuitous
     542             :                * ARP, then learn from it.
     543             :                * The check for matching an adj-fib, is to prevent hosts
     544             :                * from spamming us with gratuitous ARPS that might otherwise
     545             :                * blow our ARP cache
     546             :                */
     547           7 :               if (conn_sw_if_index0 != sw_if_index0)
     548           4 :                 error0 = ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL;
     549           3 :               else if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
     550           3 :                        arp0->ip4_over_ethernet[1].ip4.as_u32)
     551             :                 {
     552           2 :                   vlib_increment_simple_counter (
     553             :                     &ip_neighbor_counters[AF_IP4]
     554             :                        .ipnc[VLIB_RX][IP_NEIGHBOR_CTR_GRAT],
     555             :                     vm->thread_index, sw_if_index0, 1);
     556             :                   error0 =
     557           2 :                     arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
     558             :                 }
     559           7 :               goto next_feature;
     560        2031 :             case ARP_DST_FIB_CONN:
     561             :               /* destination is connected, continue to process */
     562        2031 :               break;
     563          14 :             case ARP_DST_FIB_NONE:
     564             :               /* destination is not connected, stop here */
     565          14 :               error0 = ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL;
     566          14 :               goto next_feature;
     567             :             }
     568             : 
     569        2031 :           dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
     570        2031 :           pfx0 = fib_entry_get_prefix (dst_fei);
     571        2031 :           if_addr0 = &pfx0->fp_addr.ip4;
     572             : 
     573        2031 :           is_vrrp_reply0 =
     574        2031 :             ((arp0->opcode ==
     575        2031 :               clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
     576        2071 :              &&
     577          40 :              (!memcmp
     578          40 :               (arp0->ip4_over_ethernet[0].mac.bytes, vrrp_prefix,
     579             :                sizeof (vrrp_prefix))));
     580             : 
     581             :           /* Trash ARP packets whose ARP-level source addresses do not
     582             :              match their L2-frame-level source addresses, unless it's
     583             :              a reply from a VRRP virtual router */
     584        2031 :           if (!ethernet_mac_address_equal
     585        2031 :               (eth_rx->src_address,
     586        2037 :                arp0->ip4_over_ethernet[0].mac.bytes) && !is_vrrp_reply0)
     587             :             {
     588           1 :               error0 = ARP_ERROR_L2_ADDRESS_MISMATCH;
     589           1 :               goto drop;
     590             :             }
     591             : 
     592        4060 :           vlib_increment_simple_counter (
     593             :             &ip_neighbor_counters[AF_IP4]
     594        2030 :                .ipnc[VLIB_RX][arp0->opcode == clib_host_to_net_u16 (
     595             :                                                 ETHERNET_ARP_OPCODE_reply) ?
     596        2030 :                                       IP_NEIGHBOR_CTR_REPLY :
     597             :                                       IP_NEIGHBOR_CTR_REQUEST],
     598             :             vm->thread_index, sw_if_index0, 1);
     599             : 
     600             :           /* Learn or update sender's mapping only for replies to addresses
     601             :            * that are local to the subnet */
     602        2030 :           if (arp0->opcode ==
     603        2030 :               clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
     604             :             {
     605          40 :               if (dst_is_local0)
     606             :                 error0 =
     607          39 :                   arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
     608             :               else
     609             :                 /* a reply for a non-local destination could be a GARP.
     610             :                  * GARPs for hosts we know were handled above, so this one
     611             :                  * we drop */
     612           1 :                 error0 = ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL;
     613             : 
     614          40 :               goto next_feature;
     615             :             }
     616        1990 :           else if (arp0->opcode ==
     617        3980 :                    clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request) &&
     618             :                    (dst_is_local0 == 0))
     619             :             {
     620           4 :               goto next_feature;
     621             :             }
     622             : 
     623             :           /* Honor unnumbered interface, if any */
     624        3951 :           if (sw_if_index0 != conn_sw_if_index0 ||
     625        1965 :               sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
     626             :             {
     627             :               /*
     628             :                * The interface the ARP is sent to or was received on is not the
     629             :                * interface on which the covering prefix is configured.
     630             :                * Maybe this is a case for unnumbered.
     631             :                */
     632          22 :               if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
     633             :                 {
     634          17 :                   error0 = ARP_ERROR_UNNUMBERED_MISMATCH;
     635          17 :                   goto drop;
     636             :                 }
     637             :             }
     638        1969 :           if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
     639        1969 :               arp0->ip4_over_ethernet[1].ip4.as_u32)
     640             :             {
     641           0 :               error0 = ARP_ERROR_GRATUITOUS_ARP;
     642           0 :               goto drop;
     643             :             }
     644             : 
     645        1969 :           next0 = arp_mk_reply (vnm, p0, sw_if_index0,
     646             :                                 if_addr0, arp0, eth_rx);
     647             : 
     648             :           /* We are going to reply to this request, so, in the absence of
     649             :              errors, learn the sender */
     650        1969 :           if (!error0)
     651        1969 :             error0 = arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[1]);
     652             : 
     653        1969 :           vlib_increment_simple_counter (
     654             :             &ip_neighbor_counters[AF_IP4].ipnc[VLIB_TX][IP_NEIGHBOR_CTR_REPLY],
     655             :             vm->thread_index, sw_if_index0, 1);
     656        1969 :           n_replies_sent += 1;
     657        1969 :           goto enqueue;
     658             : 
     659         118 :         next_feature:
     660         118 :           vnet_feature_next (&next0, p0);
     661             : 
     662         139 :         drop:
     663         139 :           p0->error = node->errors[error0];
     664             : 
     665        2108 :         enqueue:
     666        2108 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     667             :                                            n_left_to_next, pi0, next0);
     668             :         }
     669             : 
     670        2106 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     671             :     }
     672             : 
     673        2106 :   vlib_error_count (vm, node->node_index, ARP_ERROR_REPLIES_SENT,
     674             :                     n_replies_sent);
     675             : 
     676        2106 :   return frame->n_vectors;
     677             : }
     678             : 
     679             : 
     680             : /* *INDENT-OFF* */
     681             : 
     682      178120 : VLIB_REGISTER_NODE (arp_input_node, static) =
     683             : {
     684             :   .function = arp_input,
     685             :   .name = "arp-input",
     686             :   .vector_size = sizeof (u32),
     687             :   .n_errors = ARP_N_ERROR,
     688             :   .error_counters = arp_error_counters,
     689             :   .n_next_nodes = ARP_INPUT_N_NEXT,
     690             :   .next_nodes = {
     691             :     [ARP_INPUT_NEXT_DROP] = "error-drop",
     692             :     [ARP_INPUT_NEXT_DISABLED] = "arp-disabled",
     693             :   },
     694             :   .format_buffer = format_ethernet_arp_header,
     695             :   .format_trace = format_ethernet_arp_input_trace,
     696             : };
     697             : 
     698      178120 : VLIB_REGISTER_NODE (arp_disabled_node, static) =
     699             : {
     700             :   .function = arp_disabled,
     701             :   .name = "arp-disabled",
     702             :   .vector_size = sizeof (u32),
     703             :   .n_errors = ARP_N_ERROR,
     704             :   .error_counters = arp_error_counters,
     705             :   .n_next_nodes = ARP_DISABLED_N_NEXT,
     706             :   .next_nodes = {
     707             :     [ARP_INPUT_NEXT_DROP] = "error-drop",
     708             :   },
     709             :   .format_buffer = format_ethernet_arp_header,
     710             :   .format_trace = format_ethernet_arp_input_trace,
     711             : };
     712             : 
     713      178120 : VLIB_REGISTER_NODE (arp_reply_node, static) =
     714             : {
     715             :   .function = arp_reply,
     716             :   .name = "arp-reply",
     717             :   .vector_size = sizeof (u32),
     718             :   .n_errors = ARP_N_ERROR,
     719             :   .error_counters = arp_error_counters,
     720             :   .n_next_nodes = ARP_REPLY_N_NEXT,
     721             :   .next_nodes = {
     722             :     [ARP_REPLY_NEXT_DROP] = "error-drop",
     723             :     [ARP_REPLY_NEXT_REPLY_TX] = "interface-output",
     724             :   },
     725             :   .format_buffer = format_ethernet_arp_header,
     726             :   .format_trace = format_ethernet_arp_input_trace,
     727             : };
     728             : 
     729             : /* Built-in ARP rx feature path definition */
     730        1119 : VNET_FEATURE_ARC_INIT (arp_feat, static) =
     731             : {
     732             :   .arc_name = "arp",
     733             :   .start_nodes = VNET_FEATURES ("arp-input"),
     734             :   .last_in_arc = "error-drop",
     735             :   .arc_index_ptr = &ethernet_arp_main.feature_arc_index,
     736             : };
     737             : 
     738       70583 : VNET_FEATURE_INIT (arp_reply_feat_node, static) =
     739             : {
     740             :   .arc_name = "arp",
     741             :   .node_name = "arp-reply",
     742             :   .runs_before = VNET_FEATURES ("arp-disabled"),
     743             : };
     744             : 
     745       70583 : VNET_FEATURE_INIT (arp_proxy_feat_node, static) =
     746             : {
     747             :   .arc_name = "arp",
     748             :   .node_name = "arp-proxy",
     749             :   .runs_after = VNET_FEATURES ("arp-reply"),
     750             :   .runs_before = VNET_FEATURES ("arp-disabled"),
     751             : };
     752             : 
     753       70583 : VNET_FEATURE_INIT (arp_disabled_feat_node, static) =
     754             : {
     755             :   .arc_name = "arp",
     756             :   .node_name = "arp-disabled",
     757             :   .runs_before = VNET_FEATURES ("error-drop"),
     758             : };
     759             : 
     760       70583 : VNET_FEATURE_INIT (arp_drop_feat_node, static) =
     761             : {
     762             :   .arc_name = "arp",
     763             :   .node_name = "error-drop",
     764             :   .runs_before = 0,     /* last feature */
     765             : };
     766             : 
     767             : /* *INDENT-ON* */
     768             : 
     769             : typedef struct
     770             : {
     771             :   pg_edit_t l2_type, l3_type;
     772             :   pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
     773             :   pg_edit_t opcode;
     774             :   struct
     775             :   {
     776             :     pg_edit_t mac;
     777             :     pg_edit_t ip4;
     778             :   } ip4_over_ethernet[2];
     779             : } pg_ethernet_arp_header_t;
     780             : 
     781             : static inline void
     782           0 : pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
     783             : {
     784             :   /* Initialize fields that are not bit fields in the IP header. */
     785             : #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
     786           0 :   _(l2_type);
     787           0 :   _(l3_type);
     788           0 :   _(n_l2_address_bytes);
     789           0 :   _(n_l3_address_bytes);
     790           0 :   _(opcode);
     791           0 :   _(ip4_over_ethernet[0].mac);
     792           0 :   _(ip4_over_ethernet[0].ip4);
     793           0 :   _(ip4_over_ethernet[1].mac);
     794           0 :   _(ip4_over_ethernet[1].ip4);
     795             : #undef _
     796           0 : }
     797             : 
     798             : uword
     799           0 : unformat_pg_arp_header (unformat_input_t * input, va_list * args)
     800             : {
     801           0 :   pg_stream_t *s = va_arg (*args, pg_stream_t *);
     802             :   pg_ethernet_arp_header_t *p;
     803             :   u32 group_index;
     804             : 
     805           0 :   p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
     806             :                             &group_index);
     807           0 :   pg_ethernet_arp_header_init (p);
     808             : 
     809             :   /* Defaults. */
     810           0 :   pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
     811           0 :   pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
     812           0 :   pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
     813           0 :   pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
     814             : 
     815           0 :   if (!unformat (input, "%U: %U/%U -> %U/%U",
     816             :                  unformat_pg_edit,
     817             :                  unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
     818             :                  unformat_pg_edit,
     819             :                  unformat_mac_address_t, &p->ip4_over_ethernet[0].mac,
     820             :                  unformat_pg_edit,
     821             :                  unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
     822             :                  unformat_pg_edit,
     823             :                  unformat_mac_address_t, &p->ip4_over_ethernet[1].mac,
     824             :                  unformat_pg_edit,
     825             :                  unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
     826             :     {
     827             :       /* Free up any edits we may have added. */
     828           0 :       pg_free_edit_group (s);
     829           0 :       return 0;
     830             :     }
     831           0 :   return 1;
     832             : }
     833             : 
     834             : /*
     835             :  * callback when an interface address is added or deleted
     836             :  */
     837             : static void
     838        4671 : arp_enable_disable_interface (ip4_main_t * im,
     839             :                               uword opaque, u32 sw_if_index, u32 is_enable)
     840             : {
     841        4671 :   ethernet_arp_main_t *am = &ethernet_arp_main;
     842             : 
     843        4671 :   if (is_enable)
     844        2463 :     arp_enable (am, sw_if_index);
     845             :   else
     846        2208 :     arp_disable (am, sw_if_index);
     847        4671 : }
     848             : 
     849             : /*
     850             :  * Remove any arp entries associated with the specified interface
     851             :  */
     852             : static clib_error_t *
     853       11597 : vnet_arp_add_del_sw_interface (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
     854             : {
     855       11597 :   ethernet_arp_main_t *am = &ethernet_arp_main;
     856       11597 :   if (is_add)
     857        7418 :     arp_disable (am, sw_if_index);
     858       11597 :   return (NULL);
     859             : }
     860             : 
     861        3363 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (vnet_arp_add_del_sw_interface);
     862             : 
     863             : const static ip_neighbor_vft_t arp_vft = {
     864             :   .inv_proxy4_add = arp_proxy_add,
     865             :   .inv_proxy4_del = arp_proxy_del,
     866             :   .inv_proxy4_enable = arp_proxy_enable,
     867             :   .inv_proxy4_disable = arp_proxy_disable,
     868             : };
     869             : 
     870             : static clib_error_t *
     871         559 : ethernet_arp_init (vlib_main_t * vm)
     872             : {
     873         559 :   ethernet_arp_main_t *am = &ethernet_arp_main;
     874         559 :   ip4_main_t *im = &ip4_main;
     875             :   pg_node_t *pn;
     876             : 
     877         559 :   ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
     878             : 
     879         559 :   pn = pg_get_node (arp_input_node.index);
     880         559 :   pn->unformat_edit = unformat_pg_arp_header;
     881             : 
     882         559 :   am->opcode_by_name = hash_create_string (0, sizeof (uword));
     883             : #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
     884       15093 :   foreach_ethernet_arp_opcode;
     885             : #undef _
     886             : 
     887             :   /* don't trace ARP error packets */
     888             :   {
     889             :     vlib_node_runtime_t *rt =
     890         559 :       vlib_node_get_runtime (vm, arp_input_node.index);
     891             : 
     892         559 :     vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_REPLIES_SENT],
     893             :                                          1);
     894         559 :     vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_DISABLED], 1);
     895         559 :     vnet_pcap_drop_trace_filter_add_del (
     896         559 :       rt->errors[ARP_ERROR_L2_TYPE_NOT_ETHERNET], 1);
     897         559 :     vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_L3_TYPE_NOT_IP4],
     898             :                                          1);
     899         559 :     vnet_pcap_drop_trace_filter_add_del (
     900         559 :       rt->errors[ARP_ERROR_L3_SRC_ADDRESS_NOT_LOCAL], 1);
     901         559 :     vnet_pcap_drop_trace_filter_add_del (
     902         559 :       rt->errors[ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL], 1);
     903         559 :     vnet_pcap_drop_trace_filter_add_del (
     904         559 :       rt->errors[ARP_ERROR_L3_DST_ADDRESS_UNSET], 1);
     905         559 :     vnet_pcap_drop_trace_filter_add_del (
     906         559 :       rt->errors[ARP_ERROR_L3_SRC_ADDRESS_IS_LOCAL], 1);
     907         559 :     vnet_pcap_drop_trace_filter_add_del (
     908         559 :       rt->errors[ARP_ERROR_L3_SRC_ADDRESS_LEARNED], 1);
     909         559 :     vnet_pcap_drop_trace_filter_add_del (
     910         559 :       rt->errors[ARP_ERROR_REPLIES_RECEIVED], 1);
     911         559 :     vnet_pcap_drop_trace_filter_add_del (
     912         559 :       rt->errors[ARP_ERROR_OPCODE_NOT_REQUEST], 1);
     913         559 :     vnet_pcap_drop_trace_filter_add_del (
     914         559 :       rt->errors[ARP_ERROR_PROXY_ARP_REPLIES_SENT], 1);
     915         559 :     vnet_pcap_drop_trace_filter_add_del (
     916         559 :       rt->errors[ARP_ERROR_L2_ADDRESS_MISMATCH], 1);
     917         559 :     vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_GRATUITOUS_ARP],
     918             :                                          1);
     919         559 :     vnet_pcap_drop_trace_filter_add_del (
     920         559 :       rt->errors[ARP_ERROR_INTERFACE_NO_TABLE], 1);
     921         559 :     vnet_pcap_drop_trace_filter_add_del (
     922         559 :       rt->errors[ARP_ERROR_INTERFACE_NOT_IP_ENABLED], 1);
     923         559 :     vnet_pcap_drop_trace_filter_add_del (
     924         559 :       rt->errors[ARP_ERROR_UNNUMBERED_MISMATCH], 1);
     925             :   }
     926             : 
     927             :   {
     928         559 :     ip4_enable_disable_interface_callback_t cb = {
     929             :       .function = arp_enable_disable_interface,
     930             :     };
     931         559 :     vec_add1 (im->enable_disable_interface_callbacks, cb);
     932             :   }
     933             : 
     934         559 :   ip_neighbor_register (AF_IP4, &arp_vft);
     935             : 
     936         559 :   return 0;
     937             : }
     938             : 
     939             : /* *INDENT-OFF* */
     940       94079 : VLIB_INIT_FUNCTION (ethernet_arp_init) =
     941             : {
     942             :   .runs_after = VLIB_INITS("ethernet_init",
     943             :                            "ip_neighbor_init"),
     944             : };
     945             : /* *INDENT-ON* */
     946             : 
     947             : /*
     948             :  * fd.io coding-style-patch-verification: ON
     949             :  *
     950             :  * Local Variables:
     951             :  * eval: (c-set-style "gnu")
     952             :  * End:
     953             :  */

Generated by: LCOV version 1.14