LCOV - code coverage report
Current view: top level - plugins/vrrp - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 121 396 30.6 %
Date: 2023-07-05 22:20:52 Functions: 52 83 62.7 %

          Line data    Source code
       1             : /*
       2             :  * node.c - vrrp packet handling node definitions
       3             :  *
       4             :  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
       5             :  *
       6             :  * SPDX-License-Identifier: Apache-2.0
       7             :  *
       8             :  */
       9             : #include <vlib/vlib.h>
      10             : #include <vlibmemory/api.h>
      11             : #include <vnet/vnet.h>
      12             : #include <vnet/ip/ip4_packet.h>
      13             : #include <vnet/ip/ip6_link.h>
      14             : #include <vnet/ethernet/arp_packet.h>
      15             : #include <vnet/fib/fib_sas.h>
      16             : #include <vppinfra/error.h>
      17             : #include <vrrp/vrrp.h>
      18             : #include <vrrp/vrrp_packet.h>
      19             : 
      20             : typedef struct
      21             : {
      22             :   u32 sw_if_index;
      23             :   u8 is_ipv6;
      24             :   vrrp_header_t vrrp;
      25             :   u8 addrs[256];                /* print up to 64 IPv4 or 16 IPv6 addresses */
      26             : } vrrp_trace_t;
      27             : 
      28             : /* packet trace format function */
      29             : static u8 *
      30           0 : format_vrrp_trace (u8 * s, va_list * args)
      31             : {
      32           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      33           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      34           0 :   vrrp_trace_t *t = va_arg (*args, vrrp_trace_t *);
      35             :   int i;
      36             : 
      37           0 :   s = format (s, "VRRP: sw_if_index %d IPv%d\n",
      38           0 :               t->sw_if_index, (t->is_ipv6) ? 6 : 4);
      39           0 :   s = format (s, "    %U\n", format_vrrp_packet_hdr, &t->vrrp);
      40           0 :   s = format (s, "    addresses: ");
      41             : 
      42           0 :   for (i = 0; i < t->vrrp.n_addrs; i++)
      43             :     {
      44           0 :       if (t->is_ipv6)
      45           0 :         s = format (s, "%U ", format_ip6_address,
      46           0 :                     (ip6_address_t *) (t->addrs + i * 16));
      47             :       else
      48           0 :         s = format (s, "%U ", format_ip4_address,
      49           0 :                     (ip4_address_t *) (t->addrs + i * 4));
      50             :     }
      51             : 
      52           0 :   return s;
      53             : }
      54             : 
      55             : extern vlib_node_registration_t vrrp4_input_node;
      56             : extern vlib_node_registration_t vrrp6_input_node;
      57             : extern vlib_node_registration_t vrrp4_arp_input_node;
      58             : extern vlib_node_registration_t vrrp6_nd_input_node;
      59             : 
      60             : #define foreach_vrrp_error                                        \
      61             : _(RECEIVED, "VRRP packets processed")                           \
      62             : _(BAD_TTL, "VRRP advertisement TTL is not 255")                         \
      63             : _(NOT_VERSION_3, "VRRP version is not 3")                       \
      64             : _(INCOMPLETE_PKT, "VRRP packet has wrong size")                         \
      65             : _(BAD_CHECKSUM, "VRRP checksum is invalid")                     \
      66             : _(UNKNOWN_VR, "VRRP message does not match known VRs")                  \
      67             : _(ADDR_MISMATCH, "VR addrs do not match configuration")
      68             : 
      69             : typedef enum
      70             : {
      71             : #define _(sym,str) VRRP_ERROR_##sym,
      72             :   foreach_vrrp_error
      73             : #undef _
      74             :     VRRP_N_ERROR,
      75             : } vrrp_error_t;
      76             : 
      77             : static char *vrrp_error_strings[] = {
      78             : #define _(sym,string) string,
      79             :   foreach_vrrp_error
      80             : #undef _
      81             : };
      82             : 
      83             : typedef enum
      84             : {
      85             :   VRRP_INPUT_NEXT_DROP,
      86             :   VRRP_INPUT_N_NEXT,
      87             : } vrrp_next_t;
      88             : 
      89             : /* Given a VR and a pointer to the VRRP header of an incoming packet,
      90             :  * compare the local src address to the peers. Return < 0 if the local
      91             :  * address < the peer address, 0 if they're equal, > 0 if
      92             :  * the local address > the peer address
      93             :  */
      94             : static int
      95           0 : vrrp_vr_addr_cmp (vrrp_vr_t *vr, ip46_address_t *peer_addr)
      96             : {
      97           0 :   vrrp_vr_config_t *vrc = &vr->config;
      98             :   void *peer_addr_bytes, *local_addr;
      99             :   ip46_address_t addr;
     100             :   int addr_size;
     101             : 
     102           0 :   clib_memset (&addr, 0, sizeof (addr));
     103             : 
     104           0 :   if (vrrp_vr_is_ipv6 (vr))
     105             :     {
     106           0 :       peer_addr_bytes = &peer_addr->ip6;
     107           0 :       local_addr = &addr.ip6;
     108           0 :       addr_size = 16;
     109           0 :       ip6_address_copy (local_addr,
     110             :                         ip6_get_link_local_address (vrc->sw_if_index));
     111             :     }
     112             :   else
     113             :     {
     114           0 :       peer_addr_bytes = &peer_addr->ip4;
     115           0 :       local_addr = &addr.ip4;
     116           0 :       addr_size = 4;
     117           0 :       fib_sas4_get (vrc->sw_if_index, NULL, local_addr);
     118             :     }
     119             : 
     120           0 :   return memcmp (local_addr, peer_addr_bytes, addr_size);
     121             : }
     122             : 
     123             : static void
     124           0 : vrrp_input_process_master (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
     125             : {
     126             :   /* received priority 0, another VR is shutting down. send an adv and
     127             :    * remain in the master state
     128             :    */
     129           0 :   if (args->priority == 0)
     130             :     {
     131           0 :       clib_warning ("Received shutdown message from a peer on VR %U",
     132             :                     format_vrrp_vr_key, vr);
     133           0 :       vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
     134           0 :       vrrp_adv_send (vr, 0);
     135           0 :       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
     136           0 :       return;
     137             :     }
     138             : 
     139             :   /* if either:
     140             :    * - received priority > adjusted priority, or
     141             :    * - received priority == adjusted priority and peer addr > local addr
     142             :    * allow the local VR to be preempted by the peer
     143             :    */
     144           0 :   if ((args->priority > vrrp_vr_priority (vr)) ||
     145           0 :       ((args->priority == vrrp_vr_priority (vr)) &&
     146           0 :        (vrrp_vr_addr_cmp (vr, &args->src_addr) < 0)))
     147             :     {
     148           0 :       vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, args);
     149             : 
     150           0 :       return;
     151             :     }
     152             : 
     153             :   /* if we made it this far, eiher received prority < adjusted priority or
     154             :    * received == adjusted and local addr > peer addr. Ignore.
     155             :    */
     156           0 :   return;
     157             : }
     158             : 
     159             : /* RFC 5798 section 6.4.2 */
     160             : static void
     161           0 : vrrp_input_process_backup (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
     162             : {
     163           0 :   vrrp_vr_config_t *vrc = &vr->config;
     164           0 :   vrrp_vr_runtime_t *vrt = &vr->runtime;
     165             : 
     166             :   /* master shutting down, ready for election */
     167           0 :   if (args->priority == 0)
     168             :     {
     169           0 :       clib_warning ("Master for VR %U is shutting down", format_vrrp_vr_key,
     170             :                     vr);
     171           0 :       vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
     172           0 :       vrt->master_down_int = vrt->skew;
     173           0 :       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
     174           0 :       return;
     175             :     }
     176             : 
     177             :   /* no preempt set or adv from a higher priority router, update timers */
     178           0 :   if (!(vrc->flags & VRRP_VR_PREEMPT) ||
     179           0 :       (args->priority >= vrrp_vr_priority (vr)))
     180             :     {
     181           0 :       vrt->master_adv_int = args->max_adv_int;
     182             : 
     183           0 :       vrrp_vr_skew_compute (vr);
     184           0 :       vrrp_vr_master_down_compute (vr);
     185           0 :       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
     186           0 :       return;
     187             :     }
     188             : 
     189             :   /* preempt set or our priority > received, continue to wait on master down */
     190           0 :   return;
     191             : }
     192             : 
     193             : always_inline void
     194           0 : vrrp_input_process (vrrp_input_process_args_t * args)
     195             : {
     196             :   vrrp_vr_t *vr;
     197             : 
     198           0 :   vr = vrrp_vr_lookup_index (args->vr_index);
     199             : 
     200           0 :   if (!vr)
     201             :     {
     202           0 :       clib_warning ("Error retrieving VR with index %u", args->vr_index);
     203           0 :       return;
     204             :     }
     205             : 
     206           0 :   vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_RCVD, vr->stat_index);
     207             : 
     208           0 :   switch (vr->runtime.state)
     209             :     {
     210           0 :     case VRRP_VR_STATE_INIT:
     211           0 :       return;
     212           0 :     case VRRP_VR_STATE_BACKUP:
     213             :       /* this is usually the only state an advertisement should be received */
     214           0 :       vrrp_input_process_backup (vr, args);
     215           0 :       break;
     216           0 :     case VRRP_VR_STATE_MASTER:
     217             :       /* might be getting preempted. or have a misbehaving peer */
     218           0 :       clib_warning ("Received advertisement for master VR %U",
     219             :                     format_vrrp_vr_key, vr);
     220           0 :       vrrp_input_process_master (vr, args);
     221           0 :       break;
     222           0 :     default:
     223           0 :       clib_warning ("Received advertisement for VR %U in unknown state %d",
     224             :                     format_vrrp_vr_key, vr, vr->runtime.state);
     225           0 :       break;
     226             :     }
     227             : 
     228           0 :   return;
     229             : }
     230             : 
     231             : typedef struct
     232             : {
     233             :   ip46_address_t ip;
     234             :   u32 vr_index;
     235             :   u8 vr_id;
     236             :   u8 is_ipv6;
     237             : } vrrp_arp_nd_trace_t;
     238             : 
     239             : 
     240             : static u8 *
     241           2 : format_vrrp_arp_nd_input_trace (u8 * s, va_list * va)
     242             : {
     243           2 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     244           2 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     245           2 :   vrrp_arp_nd_trace_t *t = va_arg (*va, vrrp_arp_nd_trace_t *);
     246             : 
     247           4 :   s = format (s, "address %U",
     248           2 :               (t->is_ipv6) ? format_ip6_address : format_ip4_address,
     249           2 :               (t->is_ipv6) ? (void *) &t->ip.ip6 : (void *) &t->ip.ip4);
     250             : 
     251           2 :   if (t->vr_index != ~0)
     252           2 :     s = format (s, ": vr_index %u vr_id %u", t->vr_index, t->vr_id);
     253             : 
     254           2 :   return s;
     255             : }
     256             : 
     257             : typedef enum
     258             : {
     259             :   VRRP_ARP_INPUT_NEXT_DROP,
     260             :   VRRP_ARP_INPUT_NEXT_REPLY_TX,
     261             :   VRRP_ARP_N_NEXT,
     262             : } vrrp_arp_next_t;
     263             : 
     264             : typedef enum
     265             : {
     266             :   VRRP_ND_INPUT_NEXT_DROP,
     267             :   VRRP_ND_INPUT_NEXT_REPLY_TX,
     268             :   VRRP_ND_N_NEXT,
     269             : } vrrp_nd_next_t;
     270             : 
     271             : static_always_inline void
     272           2 : vrrp_arp_nd_next (vlib_buffer_t * b, u32 * next_index, u32 * vr_index,
     273             :                   u8 is_ipv6)
     274             : {
     275           2 :   vnet_main_t *vnm = vnet_get_main ();
     276           2 :   vlib_main_t *vm = vlib_get_main ();
     277             :   ethernet_header_t *eth, *eth_new;
     278           2 :   void *lookup_addr = 0;
     279             :   vrrp_vr_t *vr;
     280             :   u32 sw_if_index;
     281             :   vnet_link_t link_type;
     282             :   u8 *rewrite, rewrite_len;
     283             :   int bogus_length;
     284             :   /* ND vars */
     285           2 :   ip6_header_t *ip6 = 0;
     286           2 :   icmp6_neighbor_solicitation_or_advertisement_header_t *sol_adv = 0;
     287           2 :   icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *lladdr = 0;
     288             :   /* ARP vars */
     289             :   ethernet_arp_header_t *arp;
     290             :   ip4_address_t ip4_addr;
     291             : 
     292           2 :   if (is_ipv6)
     293             :     {
     294           1 :       ip6 = vlib_buffer_get_current (b);
     295             : 
     296             :       /* we only care about about ICMP6 neighbor solicitiations */
     297           1 :       if (ip6->protocol != IP_PROTOCOL_ICMP6)
     298           0 :         return;
     299             : 
     300           1 :       sol_adv = ip6_next_header (ip6);
     301           1 :       lladdr = (void *) (sol_adv + 1);
     302             : 
     303             :       /* skip anything other than neighbor solicitations */
     304           1 :       if (sol_adv->icmp.type != ICMP6_neighbor_solicitation)
     305           0 :         return;
     306             : 
     307           1 :       lookup_addr = &sol_adv->target_address;
     308           1 :       link_type = VNET_LINK_IP6;
     309             :     }
     310             :   else
     311             :     {
     312           1 :       arp = vlib_buffer_get_current (b);
     313             : 
     314             :       /* skip non-request packets */
     315           1 :       if (arp->opcode != clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request))
     316           0 :         return;
     317             : 
     318           1 :       lookup_addr = &arp->ip4_over_ethernet[1].ip4;
     319           1 :       link_type = VNET_LINK_ARP;
     320             :     }
     321             : 
     322           2 :   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
     323             : 
     324             :   /* Don't bother with a hash lookup if no VRs configured on this interface */
     325           2 :   if (!vrrp_intf_num_vrs (sw_if_index, is_ipv6))
     326           0 :     return;
     327             : 
     328             :   /* skip requests that are not for VRRP addresses */
     329           2 :   *vr_index = vrrp_vr_lookup_address (sw_if_index, is_ipv6, lookup_addr);
     330           2 :   if (*vr_index == ~0)
     331           0 :     return;
     332             : 
     333           2 :   vr = vrrp_vr_lookup_index (*vr_index);
     334           2 :   if (!vr || vr->runtime.state != VRRP_VR_STATE_MASTER)
     335             :     {
     336             :       /* RFC 5798 - section 6.4.2 - Backup "MUST NOT respond" to ARP/ND.
     337             :        * So we must drop the request rather than allowing it to continue
     338             :        * on the feature arc.
     339             :        */
     340           0 :       *next_index = VRRP_ARP_INPUT_NEXT_DROP;
     341           0 :       return;
     342             :     }
     343             : 
     344             :   /* RFC 5798 section 6.4.3: Master "MUST respond" to ARP/ND. */
     345           2 :   eth = ethernet_buffer_get_header (b);
     346           4 :   rewrite = ethernet_build_rewrite (vnm, sw_if_index, link_type,
     347           2 :                                     eth->src_address);
     348           2 :   rewrite_len = vec_len (rewrite);
     349           2 :   if (rewrite_len == 0)
     350           0 :     return;
     351             : 
     352             :   /* send the reply out the incoming interface */
     353           2 :   *next_index = VRRP_ARP_INPUT_NEXT_REPLY_TX;
     354           2 :   vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
     355             : 
     356             :   /* the outbound ethernet & vlan headers may have a different length than
     357             :    * the received header, so get a pointer to the new start of the packet
     358             :    * and write the header there.
     359             :    */
     360           2 :   vlib_buffer_advance (b, -rewrite_len);
     361           2 :   eth_new = vlib_buffer_get_current (b);
     362           2 :   clib_memcpy_fast (eth_new, rewrite, rewrite_len);
     363           2 :   vec_free (rewrite);
     364             : 
     365           2 :   if (is_ipv6)
     366             :     {
     367           1 :       if (ip6_address_is_unspecified (&ip6->src_address))
     368           0 :         ip6_set_reserved_multicast_address (&ip6->dst_address,
     369             :                                             IP6_MULTICAST_SCOPE_link_local,
     370             :                                             IP6_MULTICAST_GROUP_ID_all_hosts);
     371             :       else
     372           1 :         ip6->dst_address = ip6->src_address;
     373             : 
     374           1 :       ip6->src_address = sol_adv->target_address;
     375           1 :       ip6->hop_limit = 255;
     376           1 :       sol_adv->icmp.type = ICMP6_neighbor_advertisement;
     377           1 :       sol_adv->icmp.checksum = 0;
     378           1 :       sol_adv->advertisement_flags =
     379           1 :         clib_host_to_net_u32 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER
     380             :                               | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
     381             :                               | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
     382             : 
     383           1 :       clib_memcpy (lladdr->ethernet_address, vr->runtime.mac.bytes,
     384             :                    sizeof (mac_address_t));
     385           1 :       lladdr->header.type =
     386             :         ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
     387             : 
     388           1 :       sol_adv->icmp.checksum =
     389           1 :         ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus_length);
     390             : 
     391             :     }
     392             :   else
     393             :     {
     394           1 :       ip4_addr = arp->ip4_over_ethernet[1].ip4;
     395             : 
     396           1 :       arp->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
     397           1 :       arp->ip4_over_ethernet[1] = arp->ip4_over_ethernet[0];
     398             : 
     399           1 :       arp->ip4_over_ethernet[0].mac = vr->runtime.mac;
     400           1 :       arp->ip4_over_ethernet[0].ip4 = ip4_addr;
     401             :     }
     402             : }
     403             : 
     404             : static_always_inline uword
     405           2 : vrrp_arp_nd_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
     406             :                           vlib_frame_t * frame, u8 is_ipv6)
     407             : {
     408             :   u32 n_left_from, *from, next_index, *to_next;
     409             : 
     410           2 :   from = vlib_frame_vector_args (frame);
     411           2 :   n_left_from = frame->n_vectors;
     412           2 :   next_index = node->cached_next_index;
     413             : 
     414           4 :   while (n_left_from > 0)
     415             :     {
     416             :       u32 n_left_to_next;
     417             : 
     418           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     419             : 
     420           4 :       while (n_left_from > 0 && n_left_to_next > 0)
     421             :         {
     422             : 
     423             :           vlib_buffer_t *b0;
     424             :           u32 bi0;
     425             :           u32 next0;
     426           2 :           u32 vr_index = ~0;
     427             : 
     428           2 :           bi0 = from[0];
     429           2 :           to_next[0] = bi0;
     430           2 :           from += 1;
     431           2 :           to_next += 1;
     432           2 :           n_left_from -= 1;
     433           2 :           n_left_to_next -= 1;
     434             : 
     435           2 :           b0 = vlib_get_buffer (vm, bi0);
     436             : 
     437           2 :           vnet_feature_next (&next0, b0);
     438           2 :           vrrp_arp_nd_next (b0, &next0, &vr_index, is_ipv6);
     439             : 
     440           2 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
     441             :             {
     442             :               vrrp_arp_nd_trace_t *t =
     443           2 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     444             :               vrrp_vr_t *vr;
     445             : 
     446           2 :               if (is_ipv6)
     447             :                 {
     448             :                   ip6_header_t *ip0;
     449             :                   icmp6_neighbor_solicitation_or_advertisement_header_t
     450             :                     * sol_adv0;
     451             : 
     452           1 :                   ip0 = vlib_buffer_get_current (b0);
     453           1 :                   sol_adv0 = ip6_next_header (ip0);
     454           1 :                   t->ip.ip6 = sol_adv0->target_address;
     455             :                 }
     456             :               else
     457             :                 {
     458             :                   ethernet_arp_header_t *arp0;
     459             : 
     460           1 :                   arp0 = vlib_buffer_get_current (b0);
     461           1 :                   t->ip.ip4 = arp0->ip4_over_ethernet[0].ip4;
     462             :                 }
     463             : 
     464           2 :               vr = vrrp_vr_lookup_index (vr_index);
     465           2 :               if (vr)
     466           2 :                 t->vr_id = vr->config.vr_id;
     467             : 
     468           2 :               t->vr_index = vr_index;
     469           2 :               t->is_ipv6 = is_ipv6;
     470             :             }
     471             : 
     472           2 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     473             :                                            n_left_to_next, bi0, next0);
     474             :         }
     475             : 
     476           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     477             :     }
     478             : 
     479           2 :   return frame->n_vectors;
     480             : }
     481             : 
     482        2237 : VLIB_NODE_FN (vrrp4_arp_input_node) (vlib_main_t * vm,
     483             :                                      vlib_node_runtime_t * node,
     484             :                                      vlib_frame_t * frame)
     485             : {
     486           1 :   return vrrp_arp_nd_input_inline (vm, node, frame, 0 /* is_ipv6 */ );
     487             : }
     488             : 
     489             : /* *INDENT-OFF* */
     490       12879 : VLIB_REGISTER_NODE (vrrp4_arp_input_node) =
     491             : {
     492             :   .name = "vrrp4-arp-input",
     493             :   .vector_size = sizeof (u32),
     494             :   .format_trace = format_vrrp_arp_nd_input_trace,
     495             :   .type = VLIB_NODE_TYPE_INTERNAL,
     496             : 
     497             :   .n_errors = ARRAY_LEN(vrrp_error_strings),
     498             :   .error_strings = vrrp_error_strings,
     499             : 
     500             :   .n_next_nodes = VRRP_ARP_N_NEXT,
     501             : 
     502             :   .next_nodes = {
     503             :         [VRRP_ARP_INPUT_NEXT_DROP] = "error-drop",
     504             :         [VRRP_ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
     505             :   },
     506             : };
     507             : 
     508        1679 : VNET_FEATURE_INIT (vrrp4_arp_feat_node, static) =
     509             : {
     510             :   .arc_name = "arp",
     511             :   .node_name = "vrrp4-arp-input",
     512             :   .runs_before = VNET_FEATURES ("arp-reply"),
     513             : };
     514             : 
     515        2237 : VLIB_NODE_FN (vrrp6_nd_input_node) (vlib_main_t * vm,
     516             :                                      vlib_node_runtime_t * node,
     517             :                                      vlib_frame_t * frame)
     518             : {
     519           1 :   return vrrp_arp_nd_input_inline (vm, node, frame, 1 /* is_ipv6 */);
     520             : }
     521             : 
     522             : /* *INDENT-OFF* */
     523       12879 : VLIB_REGISTER_NODE (vrrp6_nd_input_node) =
     524             : {
     525             :   .name = "vrrp6-nd-input",
     526             :   .vector_size = sizeof (u32),
     527             :   .format_trace = format_vrrp_arp_nd_input_trace,
     528             :   .type = VLIB_NODE_TYPE_INTERNAL,
     529             : 
     530             :   .n_errors = ARRAY_LEN(vrrp_error_strings),
     531             :   .error_strings = vrrp_error_strings,
     532             : 
     533             :   .n_next_nodes = VRRP_ND_N_NEXT,
     534             : 
     535             :   .next_nodes = {
     536             :         [VRRP_ND_INPUT_NEXT_DROP] = "error-drop",
     537             :         [VRRP_ND_INPUT_NEXT_REPLY_TX] = "interface-output",
     538             :   },
     539             : };
     540             : 
     541        1679 : VNET_FEATURE_INIT (vrrp6_nd_feat_node, static) =
     542             : {
     543             :   .arc_name = "ip6-local",
     544             :   .node_name = "vrrp6-nd-input",
     545             :   .runs_before = VNET_FEATURES ("ip6-local-end-of-arc"),
     546             : };
     547             : 
     548             : static_always_inline uword
     549           0 : vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
     550             :                     vlib_frame_t * frame, u8 is_ipv6)
     551             : {
     552             :   u32 n_left_from, *from;
     553           0 :   vrrp_main_t *vmp = &vrrp_main;
     554             : 
     555           0 :   from = vlib_frame_vector_args (frame);
     556           0 :   n_left_from = frame->n_vectors;
     557             : 
     558           0 :   while (n_left_from > 0)
     559             :     {
     560             :       u32 bi0;
     561             :       vlib_buffer_t *b0;
     562             :       u32 next0, error0;
     563             :       void *ip0;
     564             :       vrrp_header_t *vrrp0;
     565             :       vrrp_vr_t *vr0;
     566             :       vrrp_input_process_args_t args0;
     567             :       u8 *ttl0;
     568             :       u16 rx_csum0;
     569             :       u16 payload_len0;
     570             :       int addr_len;
     571             : 
     572           0 :       bi0 = from[0];
     573           0 :       b0 = vlib_get_buffer (vm, bi0);
     574             : 
     575           0 :       ip0 = vlib_buffer_get_current (b0);
     576             : 
     577           0 :       if (is_ipv6)
     578             :         {
     579           0 :           ip6_header_t *ip6 = ip0;
     580             : 
     581           0 :           vrrp0 = (vrrp_header_t *) (ip6 + 1);
     582           0 :           ttl0 = &ip6->hop_limit;
     583           0 :           addr_len = 16;
     584           0 :           payload_len0 = clib_net_to_host_u16 (ip6->payload_length);
     585           0 :           vlib_buffer_advance (b0, sizeof (*ip6));
     586           0 :           clib_memcpy_fast (&args0.src_addr.ip6, &ip6->src_address, addr_len);
     587             :         }
     588             :       else
     589             :         {
     590           0 :           ip4_header_t *ip4 = ip0;
     591             : 
     592           0 :           vrrp0 = (vrrp_header_t *) (ip4 + 1);
     593           0 :           ttl0 = &ip4->ttl;
     594           0 :           addr_len = 4;
     595           0 :           payload_len0 = clib_net_to_host_u16 (ip4->length) - sizeof(*ip4);
     596           0 :           vlib_buffer_advance (b0, sizeof (*ip4));
     597           0 :           clib_memcpy_fast (&args0.src_addr.ip4, &ip4->src_address, addr_len);
     598             :         }
     599             : 
     600           0 :       next0 = VRRP_INPUT_NEXT_DROP;
     601             : 
     602           0 :       error0 = VRRP_ERROR_RECEIVED;
     603             : 
     604             :       /* Validation from RFC 5798 sec 7.1 */
     605             : 
     606             :       /* checksum set to 0 for calculation, save original value */
     607           0 :       rx_csum0 = vrrp0->checksum;
     608           0 :       vrrp0->checksum = 0;
     609             : 
     610             :       /* Mandatory - TTL/hop limit must be 255 */
     611           0 :       if (*ttl0 != 255)
     612             :         {
     613           0 :           error0 = VRRP_ERROR_BAD_TTL;
     614           0 :           vrrp_incr_err_counter (VRRP_ERR_COUNTER_TTL);
     615           0 :           goto trace;
     616             :         }
     617             : 
     618             :       /* Mandatory - VRRP version must be 3 */
     619           0 :       if ((vrrp0->vrrp_version_and_type >> 4) != 3)
     620             :         {
     621           0 :           error0 = VRRP_ERROR_NOT_VERSION_3;
     622           0 :           vrrp_incr_err_counter (VRRP_ERR_COUNTER_VERSION);
     623           0 :           goto trace;
     624             :         }
     625             : 
     626             :       /* Mandatory - packet must be complete */
     627           0 :       if (b0->current_length < sizeof (*vrrp0) +
     628           0 :           ((u32) vrrp0->n_addrs) * addr_len)
     629             :         {
     630           0 :           error0 = VRRP_ERROR_INCOMPLETE_PKT;
     631           0 :           vrrp_incr_err_counter (VRRP_ERR_COUNTER_PKT_LEN);
     632           0 :           goto trace;
     633             :         }
     634             : 
     635             :       /* Mandatory - checksum must be correct */
     636           0 :       if (rx_csum0 != vrrp_adv_csum (ip0, vrrp0, is_ipv6, payload_len0))
     637             :         {
     638           0 :           error0 = VRRP_ERROR_BAD_CHECKSUM;
     639           0 :           vrrp_incr_err_counter (VRRP_ERR_COUNTER_CHKSUM);
     640           0 :           goto trace;
     641             :         }
     642             : 
     643             :       /* Mandatory - VR must be configured on the interface adv received on */
     644           0 :       if (!(vr0 =
     645           0 :               vrrp_vr_lookup (vnet_buffer(b0)->sw_if_index[VLIB_RX],
     646           0 :                               vrrp0->vr_id, is_ipv6)))
     647             :         {
     648           0 :           error0 = VRRP_ERROR_UNKNOWN_VR;
     649           0 :           vrrp_incr_err_counter (VRRP_ERR_COUNTER_VRID);
     650           0 :           goto trace;
     651             :         }
     652             : 
     653             :       /* Optional - count of addresses should match configuration */
     654             :       /* Could also check that addresses match, but likely to be O(n^2) */
     655           0 :       if (vrrp0->n_addrs != vec_len (vr0->config.vr_addrs))
     656             :         {
     657           0 :           error0 = VRRP_ERROR_ADDR_MISMATCH;
     658           0 :           vrrp_incr_err_counter (VRRP_ERR_COUNTER_ADDR_LIST);
     659           0 :           goto trace;
     660             :         }
     661             : 
     662             :       /* signal main thread to process contents of packet */
     663           0 :       args0.vr_index = vr0 - vmp->vrs;
     664           0 :       args0.priority = vrrp0->priority;
     665           0 :       args0.max_adv_int = vrrp_adv_int_from_packet (vrrp0);
     666             : 
     667           0 :       vl_api_rpc_call_main_thread (vrrp_input_process, (u8 *) &args0,
     668             :                                    sizeof (args0));
     669             : 
     670           0 :     trace:
     671           0 :       vrrp0->checksum = rx_csum0; /* restore csum for correct trace output */
     672           0 :       b0->error = node->errors[error0];
     673             : 
     674           0 :       if (b0->flags & VLIB_BUFFER_IS_TRACED)
     675             :         {
     676           0 :           vrrp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
     677           0 :           size_t addr_len = (is_ipv6 ? 16 : 4);
     678             : 
     679           0 :           t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
     680           0 :           t->is_ipv6 = is_ipv6;
     681           0 :           clib_memcpy_fast (&t->vrrp, vrrp0, sizeof (*vrrp0));
     682           0 :           clib_memcpy_fast (t->addrs, (void *) (vrrp0 + 1),
     683           0 :                             (size_t) vrrp0->n_addrs * addr_len);
     684             :         }
     685             : 
     686             :       /* always drop, never forward or reply here */
     687           0 :       vlib_set_next_frame_buffer (vm, node, next0, bi0);
     688             : 
     689           0 :       from += 1;
     690           0 :       n_left_from -= 1;
     691             :     }
     692             : 
     693           0 :   return frame->n_vectors;
     694             : }
     695             : 
     696        2236 : VLIB_NODE_FN (vrrp4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     697             :                                 vlib_frame_t * frame)
     698             : {
     699           0 :   return vrrp_input_inline (vm, node, frame, 0);
     700             : }
     701             : 
     702             : /* *INDENT-OFF* */
     703       12879 : VLIB_REGISTER_NODE (vrrp4_input_node) =
     704             : {
     705             :   .name = "vrrp4-input",
     706             :   .vector_size = sizeof (u32),
     707             :   .format_trace = format_vrrp_trace,
     708             :   .type = VLIB_NODE_TYPE_INTERNAL,
     709             : 
     710             :   .n_errors = ARRAY_LEN(vrrp_error_strings),
     711             :   .error_strings = vrrp_error_strings,
     712             : 
     713             :   .n_next_nodes = VRRP_INPUT_N_NEXT,
     714             : 
     715             :   .next_nodes = {
     716             :         [VRRP_INPUT_NEXT_DROP] = "error-drop",
     717             :   },
     718             : };
     719             : 
     720        2236 : VLIB_NODE_FN (vrrp6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     721             :                                 vlib_frame_t * frame)
     722             : {
     723           0 :   return vrrp_input_inline (vm, node, frame, 1);
     724             : }
     725             : 
     726       12879 : VLIB_REGISTER_NODE (vrrp6_input_node) =
     727             : {
     728             :   .name = "vrrp6-input",
     729             :   .vector_size = sizeof (u32),
     730             :   .format_trace = format_vrrp_trace,
     731             :   .type = VLIB_NODE_TYPE_INTERNAL,
     732             : 
     733             :   .n_errors = ARRAY_LEN(vrrp_error_strings),
     734             :   .error_strings = vrrp_error_strings,
     735             : 
     736             :   .n_next_nodes = VRRP_INPUT_N_NEXT,
     737             : 
     738             :   .next_nodes = {
     739             :         [VRRP_INPUT_NEXT_DROP] = "error-drop",
     740             :   },
     741             : };
     742             : 
     743             : typedef struct
     744             : {
     745             :   u32 sw_if_index;
     746             :   u8 is_ipv6;
     747             :   ip46_address_t src, dst;
     748             : } vrrp_accept_owner_trace_t;
     749             : 
     750             : /* packet trace format function */
     751             : static u8 *
     752           0 : format_vrrp_accept_owner_trace (u8 * s, va_list * args)
     753             : {
     754           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     755           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     756           0 :   vrrp_accept_owner_trace_t *t = va_arg (*args, vrrp_accept_owner_trace_t *);
     757           0 :   int ip_ver = 4, ip_type = IP46_TYPE_IP4;
     758             : 
     759           0 :   if (t->is_ipv6)
     760             :     {
     761           0 :       ip_ver = 6;
     762           0 :       ip_type = IP46_TYPE_IP6;
     763             :     }
     764             : 
     765           0 :   s = format (s, "IPv%d sw_if_index %d %U -> %U",
     766             :               ip_ver, t->sw_if_index,
     767             :               format_ip46_address, &t->src, ip_type,
     768             :               format_ip46_address, &t->dst, ip_type);
     769             : 
     770           0 :   return s;
     771             : }
     772             : 
     773             : #define foreach_vrrp_accept_owner_error                           \
     774             : _(RECEIVED, "VRRP owner accept packets received")               \
     775             : _(PROCESSED, "VRRP owner accept advertisements processed")
     776             : 
     777             : typedef enum
     778             : {
     779             : #define _(sym,str) VRRP_ACCEPT_OWNER_ERROR_##sym,
     780             :   foreach_vrrp_accept_owner_error
     781             : #undef _
     782             :     VRRP_ACCEPT_OWNER_N_ERROR,
     783             : } vrrp_accept_owner_error_t;
     784             : 
     785             : static char *vrrp_accept_owner_error_strings[] = {
     786             : #define _(sym,string) string,
     787             :   foreach_vrrp_accept_owner_error
     788             : #undef _
     789             : };
     790             : 
     791             : typedef enum
     792             : {
     793             :   VRRP_ACCEPT_OWNER_NEXT_PROCESS,
     794             :   VRRP_ACCEPT_OWNER_N_NEXT,
     795             : } vrrp_accept_owner_next_t;
     796             : 
     797             : static_always_inline void
     798           0 : vrrp_accept_owner_next_node (u32 sw_if_index, u8 vr_id, u8 is_ipv6,
     799             :                              u32 *next_index, u32 *error)
     800             : {
     801           0 :   vrrp_vr_t *vr = vrrp_vr_lookup (sw_if_index, vr_id, is_ipv6);
     802             : 
     803           0 :   if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER) &&
     804           0 :       (vr->config.flags & VRRP_VR_ACCEPT))
     805             :     {
     806           0 :       *next_index = VRRP_ACCEPT_OWNER_NEXT_PROCESS;
     807           0 :       *error = VRRP_ACCEPT_OWNER_ERROR_PROCESSED;
     808             :     }
     809           0 : }
     810             : 
     811             : static_always_inline uword
     812           0 : vrrp_accept_owner_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
     813             :                                 vlib_frame_t * frame, u8 is_ipv6)
     814             : {
     815             :   u32 n_left_from, *from, *to_next;
     816           0 :   u32 next_index = node->cached_next_index;
     817             : 
     818           0 :   from = vlib_frame_vector_args (frame);
     819           0 :   n_left_from = frame->n_vectors;
     820             : 
     821           0 :   while (n_left_from > 0)
     822             :     {
     823             :       u32 n_left_to_next;
     824             : 
     825           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     826             : 
     827           0 :       while (n_left_from >= 2 && n_left_to_next >= 2)
     828             :         {
     829             :           u32 bi0, bi1;
     830             :           vlib_buffer_t *b0, *b1;
     831             :           u32 next0, next1;
     832             :           u32 error0, error1;
     833             :           vrrp_header_t *vrrp0, *vrrp1;
     834             :           ip4_header_t *ip40, *ip41;
     835             :           ip6_header_t *ip60, *ip61;
     836             :           u32 sw_if_index0, sw_if_index1;
     837             : 
     838           0 :           bi0 = from[0];
     839           0 :           bi1 = from[1];
     840             : 
     841           0 :           to_next[0] = bi0;
     842           0 :           to_next[1] = bi1;
     843             : 
     844           0 :           b0 = vlib_get_buffer (vm, bi0);
     845           0 :           b1 = vlib_get_buffer (vm, bi1);
     846             : 
     847             :           /* most packets will follow feature arc */
     848           0 :           vnet_feature_next (&next0, b0);
     849           0 :           vnet_feature_next (&next1, b1);
     850             : 
     851           0 :           error0 = error1 = VRRP_ACCEPT_OWNER_ERROR_RECEIVED;
     852             : 
     853           0 :           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
     854           0 :           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
     855             : 
     856             :           /* find VRRP advertisements which should be sent to VRRP node */
     857           0 :           if (is_ipv6)
     858             :             {
     859           0 :               ip60 = vlib_buffer_get_current (b0);
     860           0 :               ip61 = vlib_buffer_get_current (b1);
     861             : 
     862           0 :               if (PREDICT_FALSE (ip60->protocol == IP_PROTOCOL_VRRP))
     863             :                 {
     864           0 :                   vrrp0 = (vrrp_header_t *) (ip60 + 1);
     865           0 :                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
     866             :                                                is_ipv6, &next0, &error0);
     867             :                 }
     868           0 :               if (PREDICT_FALSE (ip61->protocol == IP_PROTOCOL_VRRP))
     869             :                 {
     870           0 :                   vrrp1 = (vrrp_header_t *) (ip61 + 1);
     871           0 :                   vrrp_accept_owner_next_node (sw_if_index1, vrrp1->vr_id,
     872             :                                                is_ipv6, &next1, &error1);
     873             :                 }
     874             :             }
     875             :           else
     876             :             {
     877           0 :               ip40 = vlib_buffer_get_current (b0);
     878           0 :               ip41 = vlib_buffer_get_current (b1);
     879             : 
     880           0 :               if (PREDICT_FALSE (ip40->protocol == IP_PROTOCOL_VRRP))
     881             :                 {
     882           0 :                   vrrp0 = (vrrp_header_t *) (ip40 + 1);
     883           0 :                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
     884             :                                                is_ipv6, &next0, &error0);
     885             :                 }
     886           0 :               if (PREDICT_FALSE (ip41->protocol == IP_PROTOCOL_VRRP))
     887             :                 {
     888           0 :                   vrrp1 = (vrrp_header_t *) (ip41 + 1);
     889           0 :                   vrrp_accept_owner_next_node (sw_if_index1, vrrp1->vr_id,
     890             :                                                is_ipv6, &next1, &error1);
     891             :                 }
     892             :             }
     893             : 
     894           0 :           b0->error = node->errors[error0];
     895           0 :           b1->error = node->errors[error1];
     896             : 
     897           0 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
     898             :             {
     899             :               vrrp_accept_owner_trace_t *t =
     900           0 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     901             : 
     902           0 :               t->sw_if_index = sw_if_index0;
     903           0 :               t->is_ipv6 = is_ipv6;
     904           0 :               if (is_ipv6)
     905             :                 {
     906           0 :                   ip6_address_copy (&t->src.ip6, &ip60->src_address);
     907           0 :                   ip6_address_copy (&t->dst.ip6, &ip60->dst_address);
     908             :                 }
     909             :               else
     910             :                 {
     911           0 :                   t->src.ip4.as_u32 = ip40->src_address.as_u32;
     912           0 :                   t->dst.ip4.as_u32 = ip40->dst_address.as_u32;
     913             :                 }
     914             :             }
     915             : 
     916           0 :           if (b1->flags & VLIB_BUFFER_IS_TRACED)
     917             :             {
     918             :               vrrp_accept_owner_trace_t *t =
     919           0 :                 vlib_add_trace (vm, node, b1, sizeof (*t));
     920             : 
     921           0 :               t->sw_if_index = sw_if_index1;
     922           0 :               t->is_ipv6 = is_ipv6;
     923           0 :               if (is_ipv6)
     924             :                 {
     925           0 :                   ip6_address_copy (&t->src.ip6, &ip61->src_address);
     926           0 :                   ip6_address_copy (&t->dst.ip6, &ip61->dst_address);
     927             :                 }
     928             :               else
     929             :                 {
     930           0 :                   t->src.ip4.as_u32 = ip41->src_address.as_u32;
     931           0 :                   t->dst.ip4.as_u32 = ip41->dst_address.as_u32;
     932             :                 }
     933             :             }
     934             : 
     935           0 :           from += 2;
     936           0 :           n_left_from -= 2;
     937           0 :           to_next += 2;
     938           0 :           n_left_to_next -= 2;
     939             : 
     940           0 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     941             :                                            to_next, n_left_to_next,
     942             :                                            bi0, bi1, next0, next1);
     943             :         }
     944             : 
     945           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     946             :         {
     947             :           u32 bi0;
     948             :           vlib_buffer_t *b0;
     949             :           u32 next0;
     950             :           u32 error0;
     951             :           vrrp_header_t *vrrp0;
     952             :           ip4_header_t *ip4;
     953             :           ip6_header_t *ip6;
     954             :           u32 sw_if_index0;
     955             : 
     956           0 :           bi0 = from[0];
     957           0 :           to_next[0] = bi0;
     958             : 
     959           0 :           b0 = vlib_get_buffer (vm, bi0);
     960             : 
     961             :           /* most packets will follow feature arc */
     962           0 :           vnet_feature_next (&next0, b0);
     963             : 
     964           0 :           error0 = VRRP_ACCEPT_OWNER_ERROR_RECEIVED;
     965             : 
     966           0 :           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
     967             : 
     968             :           /* find VRRP advertisements which should be sent to VRRP node */
     969           0 :           if (is_ipv6)
     970             :             {
     971           0 :               ip6 = vlib_buffer_get_current (b0);
     972             : 
     973           0 :               if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_VRRP))
     974             :                 {
     975           0 :                   vrrp0 = (vrrp_header_t *) (ip6 + 1);
     976           0 :                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
     977             :                                                is_ipv6, &next0, &error0);
     978             :                 }
     979             :             }
     980             :           else
     981             :             {
     982           0 :               ip4 = vlib_buffer_get_current (b0);
     983             : 
     984           0 :               if (PREDICT_FALSE (ip4->protocol == IP_PROTOCOL_VRRP))
     985             :                 {
     986           0 :                   vrrp0 = (vrrp_header_t *) (ip4 + 1);
     987           0 :                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
     988             :                                                is_ipv6, &next0, &error0);
     989             :                 }
     990             :             }
     991             : 
     992           0 :           b0->error = node->errors[error0];
     993             : 
     994           0 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
     995             :             {
     996             :               vrrp_accept_owner_trace_t *t =
     997           0 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     998             : 
     999           0 :               t->sw_if_index = sw_if_index0;
    1000           0 :               t->is_ipv6 = is_ipv6;
    1001           0 :               if (is_ipv6)
    1002             :                 {
    1003           0 :                   ip6_address_copy (&t->src.ip6, &ip6->src_address);
    1004           0 :                   ip6_address_copy (&t->dst.ip6, &ip6->dst_address);
    1005             :                 }
    1006             :               else
    1007             :                 {
    1008           0 :                   t->src.ip4.as_u32 = ip4->src_address.as_u32;
    1009           0 :                   t->dst.ip4.as_u32 = ip4->dst_address.as_u32;
    1010             :                 }
    1011             :             }
    1012             : 
    1013           0 :           from += 1;
    1014           0 :           n_left_from -= 1;
    1015           0 :           to_next += 1;
    1016           0 :           n_left_to_next -= 1;
    1017             : 
    1018           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
    1019             :                                            to_next, n_left_to_next,
    1020             :                                            bi0, next0);
    1021             :         }
    1022             : 
    1023           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1024             :     }
    1025             : 
    1026           0 :   return frame->n_vectors;
    1027             : }
    1028             : 
    1029        2236 : VLIB_NODE_FN (vrrp4_accept_owner_input_node) (vlib_main_t * vm,
    1030             :                                               vlib_node_runtime_t * node,
    1031             :                                               vlib_frame_t * frame)
    1032             : {
    1033           0 :   return vrrp_accept_owner_input_inline (vm, node, frame, 0);
    1034             : }
    1035             : 
    1036       12879 : VLIB_REGISTER_NODE (vrrp4_accept_owner_input_node) =
    1037             : {
    1038             :   .name = "vrrp4-accept-owner-input",
    1039             :   .vector_size = sizeof (u32),
    1040             :   .format_trace = format_vrrp_accept_owner_trace,
    1041             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1042             : 
    1043             :   .n_errors = ARRAY_LEN(vrrp_accept_owner_error_strings),
    1044             :   .error_strings = vrrp_accept_owner_error_strings,
    1045             : 
    1046             :   .n_next_nodes = VRRP_ACCEPT_OWNER_N_NEXT,
    1047             : 
    1048             :   .next_nodes = {
    1049             :         [VRRP_ACCEPT_OWNER_NEXT_PROCESS] = "vrrp4-input",
    1050             :   },
    1051             : };
    1052             : 
    1053        1679 : VNET_FEATURE_INIT (vrrp4_accept_owner_mc, static) =
    1054             : {
    1055             :   .arc_name = "ip4-multicast",
    1056             :   .node_name = "vrrp4-accept-owner-input",
    1057             :   .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
    1058             : };
    1059             : 
    1060        2236 : VLIB_NODE_FN (vrrp6_accept_owner_input_node) (vlib_main_t * vm,
    1061             :                                            vlib_node_runtime_t * node,
    1062             :                                            vlib_frame_t * frame)
    1063             : {
    1064           0 :   return vrrp_accept_owner_input_inline (vm, node, frame, 1);
    1065             : }
    1066             : 
    1067       12879 : VLIB_REGISTER_NODE (vrrp6_accept_owner_input_node) =
    1068             : {
    1069             :   .name = "vrrp6-accept-owner-input",
    1070             :   .vector_size = sizeof (u32),
    1071             :   .format_trace = format_vrrp_accept_owner_trace,
    1072             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1073             : 
    1074             :   .n_errors = ARRAY_LEN(vrrp_accept_owner_error_strings),
    1075             :   .error_strings = vrrp_accept_owner_error_strings,
    1076             : 
    1077             :   .n_next_nodes = VRRP_ACCEPT_OWNER_N_NEXT,
    1078             : 
    1079             :   .next_nodes = {
    1080             :         [VRRP_ACCEPT_OWNER_NEXT_PROCESS] = "vrrp6-input",
    1081             :   },
    1082             : };
    1083             : 
    1084        1679 : VNET_FEATURE_INIT (vrrp6_accept_owner_mc, static) =
    1085             : {
    1086             :   .arc_name = "ip6-multicast",
    1087             :   .node_name = "vrrp6-accept-owner-input",
    1088             :   .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
    1089             : };
    1090             : 
    1091             : static clib_error_t *
    1092         559 : vrrp_input_init (vlib_main_t *vm)
    1093             : {
    1094             :   clib_error_t *error;
    1095             : 
    1096         559 :   if ((error = vlib_call_init_function (vm, vrrp_init)))
    1097           0 :     return error;
    1098             : 
    1099         559 :   ip4_register_protocol (IP_PROTOCOL_VRRP, vrrp4_input_node.index);
    1100         559 :   ip6_register_protocol (IP_PROTOCOL_VRRP, vrrp6_input_node.index);
    1101             : 
    1102         559 :   return 0;
    1103             : }
    1104             : 
    1105        1119 : VLIB_INIT_FUNCTION (vrrp_input_init);
    1106             : 
    1107             : /* *INDENT-ON* */
    1108             : 
    1109             : /*
    1110             :  * fd.io coding-style-patch-verification: ON
    1111             :  *
    1112             :  * Local Variables:
    1113             :  * eval: (c-set-style "gnu")
    1114             :  * End:
    1115             :  */

Generated by: LCOV version 1.14