LCOV - code coverage report
Current view: top level - plugins/vrrp - vrrp_packet.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 327 357 91.6 %
Date: 2023-07-05 22:20:52 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /*
       2             :  * vrrp.c - vrrp plugin action functions
       3             :  *
       4             :  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
       5             :  *
       6             :  * SPDX-License-Identifier: Apache-2.0
       7             :  *
       8             :  */
       9             : 
      10             : #include <vnet/vnet.h>
      11             : #include <vnet/plugin/plugin.h>
      12             : #include <vnet/mfib/mfib_entry.h>
      13             : #include <vnet/mfib/mfib_table.h>
      14             : #include <vnet/adj/adj.h>
      15             : #include <vnet/adj/adj_mcast.h>
      16             : #include <vnet/fib/fib_table.h>
      17             : #include <vnet/fib/fib_sas.h>
      18             : #include <vnet/ip/igmp_packet.h>
      19             : #include <vnet/ip/ip6_link.h>
      20             : #include <vnet/ethernet/arp_packet.h>
      21             : 
      22             : #include <vrrp/vrrp.h>
      23             : #include <vrrp/vrrp_packet.h>
      24             : 
      25             : #include <vpp/app/version.h>
      26             : 
      27             : static const u8 vrrp4_dst_mac[6] = { 0x1, 0x0, 0x5e, 0x0, 0x0, 0x12 };
      28             : static const u8 vrrp6_dst_mac[6] = { 0x33, 0x33, 0x0, 0x0, 0x0, 0x12 };
      29             : static const u8 vrrp_src_mac_prefix[4] = { 0x0, 0x0, 0x5e, 0x0 };
      30             : 
      31             : static int
      32           4 : vrrp_adv_l2_build_multicast (vrrp_vr_t * vr, vlib_buffer_t * b)
      33             : {
      34           4 :   vnet_main_t *vnm = vnet_get_main ();
      35             :   vnet_link_t link_type;
      36             :   ethernet_header_t *eth;
      37           4 :   int n_bytes = 0;
      38             :   const void *dst_mac;
      39             :   u8 mac_byte_ipver;
      40             :   u8 *rewrite;
      41             : 
      42           4 :   eth = vlib_buffer_get_current (b);
      43             : 
      44           4 :   if (vrrp_vr_is_ipv6 (vr))
      45             :     {
      46           2 :       dst_mac = vrrp6_dst_mac;
      47           2 :       link_type = VNET_LINK_IP6;
      48           2 :       mac_byte_ipver = 0x2;
      49             :     }
      50             :   else
      51             :     {
      52           2 :       dst_mac = vrrp4_dst_mac;
      53           2 :       link_type = VNET_LINK_IP4;
      54           2 :       mac_byte_ipver = 0x1;
      55             :     }
      56             : 
      57           4 :   rewrite = ethernet_build_rewrite (vnm, vr->config.sw_if_index, link_type,
      58             :                                     dst_mac);
      59           4 :   clib_memcpy (eth, rewrite, vec_len (rewrite));
      60             : 
      61             :   /* change the source mac from the HW addr to the VRRP virtual MAC */
      62           4 :   clib_memcpy
      63             :     (eth->src_address, vrrp_src_mac_prefix, sizeof (vrrp_src_mac_prefix));
      64           4 :   eth->src_address[4] = mac_byte_ipver;
      65           4 :   eth->src_address[5] = vr->config.vr_id;
      66             : 
      67           4 :   n_bytes += vec_len (rewrite);
      68             : 
      69           4 :   vlib_buffer_chain_increase_length (b, b, n_bytes);
      70           4 :   vlib_buffer_advance (b, n_bytes);
      71             : 
      72           4 :   vec_free (rewrite);
      73             : 
      74           4 :   return n_bytes;
      75             : }
      76             : 
      77             : #define VRRP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 18 }
      78             : #define VRRP6_MCAST_ADDR_AS_U8 \
      79             : { 0xff, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12 }
      80             : 
      81             : static const ip46_address_t vrrp4_mcast_addr = {
      82             :   .ip4 = {.as_u8 = VRRP4_MCAST_ADDR_AS_U8,},
      83             : };
      84             : 
      85             : static const ip46_address_t vrrp6_mcast_addr = {
      86             :   .ip6 = {.as_u8 = VRRP6_MCAST_ADDR_AS_U8,},
      87             : };
      88             : 
      89             : /* size of static parts of header + (# addrs * addr length) */
      90             : always_inline u16
      91          12 : vrrp_adv_payload_len (vrrp_vr_t * vr)
      92             : {
      93          12 :   u16 addr_len = vrrp_vr_is_ipv6 (vr) ? 16 : 4;
      94             : 
      95          12 :   return sizeof (vrrp_header_t) + (vec_len (vr->config.vr_addrs) * addr_len);
      96             : }
      97             : 
      98             : static int
      99           4 : vrrp_adv_l3_build (vrrp_vr_t * vr, vlib_buffer_t * b,
     100             :                    const ip46_address_t * dst)
     101             : {
     102           4 :   if (!vrrp_vr_is_ipv6 (vr))    /* IPv4 */
     103             :     {
     104           2 :       ip4_header_t *ip4 = vlib_buffer_get_current (b);
     105             :       ip4_address_t *src4;
     106             : 
     107           2 :       clib_memset (ip4, 0, sizeof (*ip4));
     108           2 :       ip4->ip_version_and_header_length = 0x45;
     109           2 :       ip4->ttl = 255;
     110           2 :       ip4->protocol = IP_PROTOCOL_VRRP;
     111           2 :       clib_memcpy (&ip4->dst_address, &dst->ip4, sizeof (dst->ip4));
     112             : 
     113             :       /* RFC 5798 Section 5.1.1.1 - Source Address "is the primary IPv4
     114             :        * address of the interface the packet is being sent from". Assume
     115             :        * this is the first address on the interface.
     116             :        */
     117           2 :       src4 = ip_interface_get_first_ip (vr->config.sw_if_index, 1);
     118           2 :       if (!src4)
     119             :         {
     120           0 :           return -1;
     121             :         }
     122           2 :       ip4->src_address.as_u32 = src4->as_u32;
     123           2 :       ip4->length = clib_host_to_net_u16 (sizeof (*ip4) +
     124           2 :                                           vrrp_adv_payload_len (vr));
     125           2 :       ip4->checksum = ip4_header_checksum (ip4);
     126             : 
     127           2 :       vlib_buffer_chain_increase_length (b, b, sizeof (*ip4));
     128           2 :       vlib_buffer_advance (b, sizeof (*ip4));
     129             : 
     130           2 :       return sizeof (*ip4);
     131             :     }
     132             :   else
     133             :     {
     134           2 :       ip6_header_t *ip6 = vlib_buffer_get_current (b);
     135             : 
     136           2 :       clib_memset (ip6, 0, sizeof (*ip6));
     137           2 :       ip6->ip_version_traffic_class_and_flow_label = 0x00000060;
     138           2 :       ip6->hop_limit = 255;
     139           2 :       ip6->protocol = IP_PROTOCOL_VRRP;
     140           2 :       clib_memcpy (&ip6->dst_address, &dst->ip6, sizeof (dst->ip6));
     141           2 :       ip6_address_copy (&ip6->src_address,
     142             :                         ip6_get_link_local_address (vr->config.sw_if_index));
     143           2 :       ip6->payload_length = clib_host_to_net_u16 (vrrp_adv_payload_len (vr));
     144             : 
     145           2 :       vlib_buffer_chain_increase_length (b, b, sizeof (*ip6));
     146           2 :       vlib_buffer_advance (b, sizeof (*ip6));
     147             : 
     148           2 :       return sizeof (*ip6);
     149             :     }
     150             : }
     151             : 
     152             : 
     153             : u16
     154           4 : vrrp_adv_csum (void *l3_hdr, void *payload, u8 is_ipv6, u16 len)
     155             : {
     156           4 :   ip_csum_t csum = 0;
     157           4 :   u8 proto = IP_PROTOCOL_VRRP;
     158             :   int addr_len;
     159           4 :   int word_size = sizeof (uword);
     160             :   void *src_addr;
     161             :   int i;
     162             : 
     163           4 :   if (is_ipv6)
     164             :     {
     165           2 :       addr_len = 16;
     166           2 :       src_addr = &(((ip6_header_t *) l3_hdr)->src_address);
     167             :     }
     168             :   else
     169             :     {
     170           2 :       addr_len = 4;
     171           2 :       src_addr = &(((ip4_header_t *) l3_hdr)->src_address);
     172             :     }
     173             : 
     174          14 :   for (i = 0; i < (2 * addr_len); i += word_size)
     175             :     {
     176          10 :       if (word_size == sizeof (u64))
     177             :         csum =
     178          10 :           ip_csum_with_carry (csum, clib_mem_unaligned (src_addr + i, u64));
     179             :       else
     180             :         csum =
     181           0 :           ip_csum_with_carry (csum, clib_mem_unaligned (src_addr + i, u32));
     182             :     }
     183             : 
     184           4 :   csum = ip_csum_with_carry (csum,
     185           4 :                              clib_host_to_net_u32 (len + (proto << 16)));
     186             : 
     187             :   /* now do the payload */
     188           4 :   csum = ip_incremental_checksum (csum, payload, len);
     189             : 
     190           4 :   csum = ~ip_csum_fold (csum);
     191             : 
     192           4 :   return (u16) csum;
     193             : }
     194             : 
     195             : static int
     196           4 : vrrp_adv_payload_build (vrrp_vr_t * vr, vlib_buffer_t * b, int shutdown)
     197             : {
     198           4 :   vrrp_header_t *vrrp = vlib_buffer_get_current (b);
     199             :   void *l3_hdr;
     200             :   ip46_address_t *vr_addr;
     201             :   void *hdr_addr;
     202             :   u8 is_ipv6;
     203             :   u8 n_addrs;
     204             :   int len;
     205             : 
     206           4 :   n_addrs = vec_len (vr->config.vr_addrs);
     207           4 :   is_ipv6 = vrrp_vr_is_ipv6 (vr);
     208             : 
     209           4 :   if (is_ipv6)
     210             :     {
     211             :       ip6_header_t *ip6;
     212             : 
     213           2 :       len = sizeof (*vrrp) + n_addrs * sizeof (ip6_address_t);;
     214           2 :       l3_hdr = vlib_buffer_get_current (b) - sizeof (ip6_header_t);
     215           2 :       ip6 = l3_hdr;
     216           2 :       ip6->payload_length = clib_host_to_net_u16 (len);
     217             :     }
     218             :   else
     219             :     {
     220           2 :       len = sizeof (*vrrp) + n_addrs * sizeof (ip4_address_t);
     221           2 :       l3_hdr = vlib_buffer_get_current (b) - sizeof (ip4_header_t);
     222             :     }
     223             : 
     224           4 :   vrrp->vrrp_version_and_type = 0x31;
     225           4 :   vrrp->vr_id = vr->config.vr_id;
     226           4 :   vrrp->priority = (shutdown) ? 0 : vrrp_vr_priority (vr);
     227           4 :   vrrp->n_addrs = vec_len (vr->config.vr_addrs);
     228           4 :   vrrp->rsvd_and_max_adv_int = clib_host_to_net_u16 (vr->config.adv_interval);
     229           4 :   vrrp->checksum = 0;
     230             : 
     231           4 :   hdr_addr = (void *) (vrrp + 1);
     232             : 
     233           8 :   vec_foreach (vr_addr, vr->config.vr_addrs)
     234             :   {
     235           4 :     if (is_ipv6)
     236             :       {
     237           2 :         clib_memcpy (hdr_addr, &vr_addr->ip6, 16);
     238           2 :         hdr_addr += 16;
     239             :       }
     240             :     else
     241             :       {
     242           2 :         clib_memcpy (hdr_addr, &vr_addr->ip4, 4);
     243           2 :         hdr_addr += 4;
     244             :       }
     245             :   }
     246             : 
     247           4 :   vlib_buffer_chain_increase_length (b, b, vrrp_adv_payload_len (vr));
     248             : 
     249           4 :   vrrp->checksum =
     250           4 :     vrrp_adv_csum (l3_hdr, vrrp, is_ipv6, vrrp_adv_payload_len (vr));
     251             : 
     252           4 :   return len;
     253             : }
     254             : 
     255             : static_always_inline u32
     256           4 : vrrp_adv_next_node (vrrp_vr_t * vr)
     257             : {
     258           4 :   if (vrrp_vr_is_unicast (vr))
     259             :     {
     260           0 :       if (vrrp_vr_is_ipv6 (vr))
     261           0 :         return ip6_lookup_node.index;
     262             :       else
     263           0 :         return ip4_lookup_node.index;
     264             :     }
     265             :   else
     266             :     {
     267           4 :       vrrp_main_t *vmp = &vrrp_main;
     268             : 
     269           4 :       return vmp->intf_output_node_idx;
     270             :     }
     271             : }
     272             : 
     273             : static_always_inline const ip46_address_t *
     274           4 : vrrp_adv_mcast_addr (vrrp_vr_t * vr)
     275             : {
     276           4 :   if (vrrp_vr_is_ipv6 (vr))
     277           2 :     return &vrrp6_mcast_addr;
     278             : 
     279           2 :   return &vrrp4_mcast_addr;
     280             : }
     281             : 
     282             : int
     283           4 : vrrp_adv_send (vrrp_vr_t * vr, int shutdown)
     284             : {
     285           4 :   vlib_main_t *vm = vlib_get_main ();
     286             :   vlib_frame_t *to_frame;
     287           4 :   int i, n_buffers = 1;
     288           4 :   u32 node_index, *to_next, *bi = 0;
     289           4 :   u8 is_unicast = vrrp_vr_is_unicast (vr);
     290             : 
     291           4 :   node_index = vrrp_adv_next_node (vr);
     292             : 
     293           4 :   if (is_unicast)
     294           0 :     n_buffers = vec_len (vr->config.peer_addrs);
     295             : 
     296           4 :   if (n_buffers < 1)
     297             :     {
     298             :       /* A unicast VR will not start without peers added so this should
     299             :        * not happen. Just avoiding a crash if it happened somehow.
     300             :        */
     301           0 :       clib_warning ("Unicast VR configuration corrupted for %U",
     302             :                     format_vrrp_vr_key, vr);
     303           0 :       return -1;
     304             :     }
     305             : 
     306           4 :   vec_validate (bi, n_buffers - 1);
     307           4 :   if (vlib_buffer_alloc (vm, bi, n_buffers) != n_buffers)
     308             :     {
     309           0 :       clib_warning ("Buffer allocation failed for %U", format_vrrp_vr_key,
     310             :                     vr);
     311           0 :       vec_free (bi);
     312           0 :       return -1;
     313             :     }
     314             : 
     315           4 :   to_frame = vlib_get_frame_to_node (vm, node_index);
     316           4 :   to_next = vlib_frame_vector_args (to_frame);
     317             : 
     318           8 :   for (i = 0; i < n_buffers; i++)
     319             :     {
     320             :       vlib_buffer_t *b;
     321             :       u32 bi0;
     322           4 :       const ip46_address_t *dst = vrrp_adv_mcast_addr (vr);
     323             : 
     324           4 :       bi0 = vec_elt (bi, i);
     325           4 :       b = vlib_get_buffer (vm, bi0);
     326             : 
     327           4 :       b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     328           4 :       vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
     329           4 :       vnet_buffer (b)->sw_if_index[VLIB_TX] = vr->config.sw_if_index;
     330             : 
     331           4 :       if (is_unicast)
     332             :         {
     333           0 :           dst = vec_elt_at_index (vr->config.peer_addrs, i);
     334           0 :           vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
     335             :         }
     336             :       else
     337           4 :         vrrp_adv_l2_build_multicast (vr, b);
     338             : 
     339           4 :       if (-1 == vrrp_adv_l3_build (vr, b, dst))
     340             :         {
     341           0 :           vlib_frame_free (vm, to_frame);
     342           0 :           vlib_buffer_free (vm, bi, n_buffers);
     343           0 :           return -1;
     344             :         }
     345           4 :       vrrp_adv_payload_build (vr, b, shutdown);
     346             : 
     347           4 :       vlib_buffer_reset (b);
     348             : 
     349           4 :       to_next[i] = bi0;
     350             :     }
     351             : 
     352           4 :   to_frame->n_vectors = n_buffers;
     353             : 
     354           4 :   vlib_put_frame_to_node (vm, node_index, to_frame);
     355             : 
     356           4 :   vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_SENT, vr->stat_index);
     357           4 :   if (shutdown)
     358             :     {
     359           2 :       vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_SENT, vr->stat_index);
     360             :     }
     361             : 
     362           4 :   vec_free (bi);
     363             : 
     364           4 :   return 0;
     365             : }
     366             : 
     367             : static void
     368           1 : vrrp6_na_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b, ip6_address_t * addr6)
     369             : {
     370           1 :   vnet_main_t *vnm = vnet_get_main ();
     371           1 :   vlib_main_t *vm = vlib_get_main ();
     372             :   ethernet_header_t *eth;
     373             :   ip6_header_t *ip6;
     374             :   icmp6_neighbor_solicitation_or_advertisement_header_t *na;
     375             :   icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *ll_opt;
     376             :   int payload_length, bogus_length;
     377           1 :   int rewrite_bytes = 0;
     378             :   u8 *rewrite;
     379             :   u8 dst_mac[6];
     380             : 
     381             :   /* L2 headers */
     382           1 :   eth = vlib_buffer_get_current (b);
     383             : 
     384           1 :   ip6_multicast_ethernet_address (dst_mac, IP6_MULTICAST_GROUP_ID_all_hosts);
     385           1 :   rewrite =
     386           1 :     ethernet_build_rewrite (vnm, vr->config.sw_if_index, VNET_LINK_IP6,
     387             :                             dst_mac);
     388           1 :   rewrite_bytes += vec_len (rewrite);
     389           1 :   clib_memcpy (eth, rewrite, vec_len (rewrite));
     390           1 :   vec_free (rewrite);
     391             : 
     392           1 :   b->current_length += rewrite_bytes;
     393           1 :   vlib_buffer_advance (b, rewrite_bytes);
     394             : 
     395             :   /* IPv6 */
     396           1 :   ip6 = vlib_buffer_get_current (b);
     397             : 
     398           1 :   b->current_length += sizeof (*ip6);
     399           1 :   clib_memset (ip6, 0, sizeof (*ip6));
     400             : 
     401           1 :   ip6->ip_version_traffic_class_and_flow_label = 0x00000060;
     402           1 :   ip6->protocol = IP_PROTOCOL_ICMP6;
     403           1 :   ip6->hop_limit = 255;
     404           1 :   ip6_set_reserved_multicast_address (&ip6->dst_address,
     405             :                                       IP6_MULTICAST_SCOPE_link_local,
     406             :                                       IP6_MULTICAST_GROUP_ID_all_hosts);
     407           1 :   ip6_address_copy (&ip6->src_address,
     408             :                     ip6_get_link_local_address (vr->config.sw_if_index));
     409             : 
     410             : 
     411             :   /* ICMPv6 */
     412           1 :   na = (icmp6_neighbor_solicitation_or_advertisement_header_t *) (ip6 + 1);
     413           1 :   ll_opt =
     414             :     (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *) (na +
     415             :                                                                        1);
     416             : 
     417           1 :   payload_length = sizeof (*na) + sizeof (*ll_opt);
     418           1 :   b->current_length += payload_length;
     419           1 :   clib_memset (na, 0, payload_length);
     420             : 
     421           1 :   na->icmp.type = ICMP6_neighbor_advertisement;      /* icmp code, csum are 0 */
     422           1 :   na->target_address = *addr6;
     423           1 :   na->advertisement_flags = clib_host_to_net_u32
     424             :     (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
     425             :      | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER);
     426             : 
     427           1 :   ll_opt->header.type =
     428             :     ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
     429           1 :   ll_opt->header.n_data_u64s = 1;
     430           1 :   clib_memcpy (ll_opt->ethernet_address, vr->runtime.mac.bytes,
     431             :                sizeof (vr->runtime.mac));
     432             : 
     433           1 :   ip6->payload_length = clib_host_to_net_u16 (payload_length);
     434           1 :   na->icmp.checksum =
     435           1 :     ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus_length);
     436           1 : }
     437             : 
     438             : const mac_address_t broadcast_mac = {
     439             :   .bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,},
     440             : };
     441             : 
     442             : static void
     443           1 : vrrp4_garp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b, ip4_address_t * ip4)
     444             : {
     445           1 :   vnet_main_t *vnm = vnet_get_main ();
     446             :   ethernet_header_t *eth;
     447             :   ethernet_arp_header_t *arp;
     448             :   int rewrite_bytes;
     449             :   u8 *rewrite;
     450             : 
     451           1 :   eth = vlib_buffer_get_current (b);
     452             : 
     453           1 :   rewrite =
     454           1 :     ethernet_build_rewrite (vnm, vr->config.sw_if_index, VNET_LINK_ARP,
     455             :                             broadcast_mac.bytes);
     456           1 :   rewrite_bytes = vec_len (rewrite);
     457           1 :   clib_memcpy (eth, rewrite, rewrite_bytes);
     458           1 :   vec_free (rewrite);
     459             : 
     460           1 :   b->current_length += rewrite_bytes;
     461           1 :   vlib_buffer_advance (b, rewrite_bytes);
     462             : 
     463           1 :   arp = vlib_buffer_get_current (b);
     464           1 :   b->current_length += sizeof (*arp);
     465             : 
     466           1 :   clib_memset (arp, 0, sizeof (*arp));
     467             : 
     468           1 :   arp->l2_type = clib_host_to_net_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet);
     469           1 :   arp->l3_type = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
     470           1 :   arp->n_l2_address_bytes = 6;
     471           1 :   arp->n_l3_address_bytes = 4;
     472           1 :   arp->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
     473           1 :   arp->ip4_over_ethernet[0].mac = vr->runtime.mac;
     474           1 :   arp->ip4_over_ethernet[0].ip4 = *ip4;
     475           1 :   arp->ip4_over_ethernet[1].mac = broadcast_mac;
     476           1 :   arp->ip4_over_ethernet[1].ip4 = *ip4;
     477           1 : }
     478             : 
     479             : int
     480           2 : vrrp_garp_or_na_send (vrrp_vr_t * vr)
     481             : {
     482           2 :   vlib_main_t *vm = vlib_get_main ();
     483           2 :   vrrp_main_t *vmp = &vrrp_main;
     484             :   vlib_frame_t *to_frame;
     485           2 :   u32 *bi = 0;
     486             :   u32 n_buffers;
     487             :   u32 *to_next;
     488             :   int i;
     489             : 
     490           2 :   if (vec_len (vr->config.peer_addrs))
     491           0 :     return 0;                   /* unicast is used in routed environments - don't garp */
     492             : 
     493           2 :   n_buffers = vec_len (vr->config.vr_addrs);
     494           2 :   if (!n_buffers)
     495             :     {
     496           0 :       clib_warning ("Unable to send gratuitous ARP for VR %U - no addresses",
     497             :                     format_vrrp_vr_key, vr);
     498           0 :       return -1;
     499             :     }
     500             : 
     501             :   /* need to send a packet for each VR address */
     502           2 :   vec_validate (bi, n_buffers - 1);
     503             : 
     504           2 :   if (vlib_buffer_alloc (vm, bi, n_buffers) != n_buffers)
     505             :     {
     506           0 :       clib_warning ("Buffer allocation failed for %U", format_vrrp_vr_key,
     507             :                     vr);
     508           0 :       vec_free (bi);
     509           0 :       return -1;
     510             :     }
     511             : 
     512           2 :   to_frame = vlib_get_frame_to_node (vm, vmp->intf_output_node_idx);
     513           2 :   to_frame->n_vectors = 0;
     514           2 :   to_next = vlib_frame_vector_args (to_frame);
     515             : 
     516           4 :   for (i = 0; i < n_buffers; i++)
     517             :     {
     518             :       vlib_buffer_t *b;
     519             :       ip46_address_t *addr;
     520             : 
     521           2 :       addr = vec_elt_at_index (vr->config.vr_addrs, i);
     522           2 :       b = vlib_get_buffer (vm, bi[i]);
     523             : 
     524           2 :       b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     525           2 :       vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
     526           2 :       vnet_buffer (b)->sw_if_index[VLIB_TX] = vr->config.sw_if_index;
     527             : 
     528           2 :       if (vrrp_vr_is_ipv6 (vr))
     529           1 :         vrrp6_na_pkt_build (vr, b, &addr->ip6);
     530             :       else
     531           1 :         vrrp4_garp_pkt_build (vr, b, &addr->ip4);
     532             : 
     533           2 :       vlib_buffer_reset (b);
     534             : 
     535           2 :       to_next[i] = bi[i];
     536           2 :       to_frame->n_vectors++;
     537             :     }
     538             : 
     539           2 :   vlib_put_frame_to_node (vm, vmp->intf_output_node_idx, to_frame);
     540             : 
     541           2 :   return 0;
     542             : }
     543             : 
     544             : #define IGMP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 22 }
     545             : 
     546             : static const ip4_header_t igmp_ip4_mcast = {
     547             :   .ip_version_and_header_length = 0x46, /* there's options! */
     548             :   .ttl = 1,
     549             :   .protocol = IP_PROTOCOL_IGMP,
     550             :   .tos = 0xc0,
     551             :   .dst_address = {.as_u8 = IGMP4_MCAST_ADDR_AS_U8,},
     552             : };
     553             : 
     554             : static int
     555           1 : vrrp_igmp_pkt_build (vrrp_vr_t *vr, vlib_buffer_t *b)
     556             : {
     557             :   ip4_header_t *ip4;
     558             :   u8 *ip4_options;
     559             :   igmp_membership_report_v3_t *report;
     560             :   igmp_membership_group_v3_t *group;
     561             :   ip4_address_t *src4;
     562             : 
     563           1 :   ip4 = vlib_buffer_get_current (b);
     564           1 :   clib_memcpy (ip4, &igmp_ip4_mcast, sizeof (*ip4));
     565             : 
     566             :   /* Use the source address advertisements will use to join mcast group */
     567           1 :   src4 = ip_interface_get_first_ip (vr->config.sw_if_index, 1);
     568           1 :   if (!src4)
     569             :     {
     570           0 :       return -1;
     571             :     }
     572           1 :   ip4->src_address.as_u32 = src4->as_u32;
     573             : 
     574           1 :   vlib_buffer_chain_increase_length (b, b, sizeof (*ip4));
     575           1 :   vlib_buffer_advance (b, sizeof (*ip4));
     576             : 
     577           1 :   ip4_options = (u8 *) (ip4 + 1);
     578           1 :   ip4_options[0] = 0x94;        /* 10010100 == the router alert option */
     579           1 :   ip4_options[1] = 0x04;        /* length == 4 bytes */
     580           1 :   ip4_options[2] = 0x0;         /* value == Router shall examine packet */
     581           1 :   ip4_options[3] = 0x0;         /* reserved */
     582             : 
     583           1 :   vlib_buffer_chain_increase_length (b, b, 4);
     584           1 :   vlib_buffer_advance (b, 4);
     585             : 
     586           1 :   report = vlib_buffer_get_current (b);
     587             : 
     588           1 :   report->header.type = IGMP_TYPE_membership_report_v3;
     589           1 :   report->header.code = 0;
     590           1 :   report->header.checksum = 0;
     591           1 :   report->unused = 0;
     592           1 :   report->n_groups = clib_host_to_net_u16 (1);
     593             : 
     594           1 :   vlib_buffer_chain_increase_length (b, b, sizeof (*report));
     595           1 :   vlib_buffer_advance (b, sizeof (*report));
     596             : 
     597           1 :   group = vlib_buffer_get_current (b);
     598           1 :   group->type = IGMP_MEMBERSHIP_GROUP_change_to_exclude;
     599           1 :   group->n_aux_u32s = 0;
     600           1 :   group->n_src_addresses = 0;
     601           1 :   group->group_address.as_u32 = clib_host_to_net_u32 (0xe0000012);
     602             : 
     603           1 :   vlib_buffer_chain_increase_length (b, b, sizeof (*group));
     604           1 :   vlib_buffer_advance (b, sizeof (*group));
     605             : 
     606           1 :   ip4->length = clib_host_to_net_u16 (b->current_data);
     607           1 :   ip4->checksum = ip4_header_checksum (ip4);
     608             : 
     609           1 :   int payload_len = vlib_buffer_get_current (b) - ((void *) report);
     610           1 :   report->header.checksum =
     611           1 :     ~ip_csum_fold (ip_incremental_checksum (0, report, payload_len));
     612             : 
     613           1 :   vlib_buffer_reset (b);
     614           1 :   return 0;
     615             : }
     616             : 
     617             : /* multicast listener report packet format for ethernet. */
     618             : typedef CLIB_PACKED (struct
     619             :                      {
     620             :                      ip6_hop_by_hop_ext_t ext_hdr;
     621             :                      ip6_router_alert_option_t alert;
     622             :                      ip6_padN_option_t pad;
     623             :                      icmp46_header_t icmp;
     624             :                      u16 rsvd;
     625             :                      u16 num_addr_records;
     626             :                      icmp6_multicast_address_record_t records[0];
     627             :                      }) icmp6_multicast_listener_report_header_t;
     628             : 
     629             : static void
     630           1 : vrrp_icmp6_mlr_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b)
     631             : {
     632           1 :   vlib_main_t *vm = vlib_get_main ();
     633             :   ip6_header_t *ip6;
     634             :   icmp6_multicast_listener_report_header_t *rh;
     635             :   icmp6_multicast_address_record_t *rr;
     636             :   ip46_address_t *vr_addr;
     637             :   int bogus_length, n_addrs;
     638             :   u16 payload_length;
     639             : 
     640           1 :   n_addrs = vec_len (vr->config.vr_addrs) + 1;
     641           1 :   payload_length = sizeof (*rh) + (n_addrs * sizeof (*rr));
     642           1 :   b->current_length = sizeof (*ip6) + payload_length;
     643           1 :   b->error = ICMP6_ERROR_NONE;
     644             : 
     645           1 :   ip6 = vlib_buffer_get_current (b);
     646           1 :   rh = (icmp6_multicast_listener_report_header_t *) (ip6 + 1);
     647           1 :   rr = (icmp6_multicast_address_record_t *) (rh + 1);
     648             : 
     649             :   /* IP header */
     650           1 :   clib_memset (ip6, 0, b->current_length);
     651           1 :   ip6->ip_version_traffic_class_and_flow_label =
     652           1 :     clib_host_to_net_u32 (0x60000000);
     653           1 :   ip6->hop_limit = 1;
     654           1 :   ip6->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
     655           1 :   ip6_set_reserved_multicast_address (&ip6->dst_address,
     656             :                                       IP6_MULTICAST_SCOPE_link_local,
     657             :                                       IP6_MULTICAST_GROUP_ID_mldv2_routers);
     658           1 :   ip6_address_copy (&ip6->src_address,
     659             :                     ip6_get_link_local_address (vr->config.sw_if_index));
     660             : 
     661           1 :   clib_memset (rh, 0, sizeof (*rh));
     662             : 
     663             :   /* v6 hop by hop extension header */
     664           1 :   rh->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
     665           1 :   rh->ext_hdr.n_data_u64s = 0;
     666             : 
     667           1 :   rh->alert.type = IP6_MLDP_ALERT_TYPE;
     668           1 :   rh->alert.len = 2;
     669           1 :   rh->alert.value = 0;
     670             : 
     671           1 :   rh->pad.type = 1;
     672           1 :   rh->pad.len = 0;
     673             : 
     674             :   /* icmp6 header */
     675           1 :   rh->icmp.type = ICMP6_multicast_listener_report_v2;
     676           1 :   rh->icmp.checksum = 0;
     677             : 
     678           1 :   rh->rsvd = 0;
     679           1 :   rh->num_addr_records = clib_host_to_net_u16 (n_addrs);
     680             : 
     681             :   /* group addresses */
     682             : 
     683             :   /* All VRRP routers group */
     684           1 :   rr->type = 4;
     685           1 :   rr->aux_data_len_u32s = 0;
     686           1 :   rr->num_sources = 0;
     687           1 :   clib_memcpy
     688             :     (&rr->mcast_addr, &vrrp6_mcast_addr.ip6, sizeof (ip6_address_t));
     689             : 
     690             :   /* solicited node multicast addresses for VR addrs */
     691           2 :   vec_foreach (vr_addr, vr->config.vr_addrs)
     692             :   {
     693             :     u32 id;
     694             : 
     695           1 :     rr++;
     696           1 :     rr->type = 4;
     697           1 :     rr->aux_data_len_u32s = 0;
     698           1 :     rr->num_sources = 0;
     699             : 
     700           1 :     id = clib_net_to_host_u32 (vr_addr->ip6.as_u32[3]) & 0x00ffffff;
     701           1 :     ip6_set_solicited_node_multicast_address (&rr->mcast_addr, id);
     702             :   }
     703             : 
     704           1 :   ip6->payload_length = clib_host_to_net_u16 (payload_length);
     705           1 :   rh->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6,
     706             :                                                          &bogus_length);
     707           1 : }
     708             : 
     709             : int
     710           2 : vrrp_vr_multicast_group_join (vrrp_vr_t * vr)
     711             : {
     712           2 :   vlib_main_t *vm = vlib_get_main ();
     713             :   vlib_buffer_t *b;
     714             :   vlib_frame_t *f;
     715           2 :   vnet_main_t *vnm = vnet_get_main ();
     716             :   vrrp_intf_t *intf;
     717           2 :   u32 bi = 0, *to_next;
     718           2 :   int n_buffers = 1;
     719             :   u8 is_ipv6;
     720             :   u32 node_index;
     721             : 
     722           2 :   if (!vnet_sw_interface_is_up (vnm, vr->config.sw_if_index))
     723           0 :     return 0;
     724             : 
     725           2 :   is_ipv6 = vrrp_vr_is_ipv6 (vr);
     726             : 
     727           2 :   if (is_ipv6 && ip6_link_is_enabled (vr->config.sw_if_index) == 0)
     728           0 :     return 0;
     729             : 
     730           2 :   if (vlib_buffer_alloc (vm, &bi, n_buffers) != n_buffers)
     731             :     {
     732           0 :       clib_warning ("Buffer allocation failed for %U", format_vrrp_vr_key,
     733             :                     vr);
     734           0 :       return -1;
     735             :     }
     736             : 
     737           2 :   b = vlib_get_buffer (vm, bi);
     738             : 
     739           2 :   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     740             : 
     741           2 :   vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
     742           2 :   vnet_buffer (b)->sw_if_index[VLIB_TX] = vr->config.sw_if_index;
     743             : 
     744           2 :   intf = vrrp_intf_get (vr->config.sw_if_index);
     745           2 :   vnet_buffer (b)->ip.adj_index[VLIB_TX] = intf->mcast_adj_index[is_ipv6];
     746             : 
     747           2 :   if (is_ipv6)
     748             :     {
     749           1 :       vrrp_icmp6_mlr_pkt_build (vr, b);
     750           1 :       node_index = ip6_rewrite_mcast_node.index;
     751             :     }
     752             :   else
     753             :     {
     754           1 :       if (-1 == vrrp_igmp_pkt_build (vr, b))
     755             :         {
     756           0 :           clib_warning ("IGMP packet build failed for %U", format_vrrp_vr_key,
     757             :                         vr);
     758           0 :           vlib_buffer_free (vm, &bi, 1);
     759           0 :           return -1;
     760             :         }
     761           1 :       node_index = ip4_rewrite_mcast_node.index;
     762             :     }
     763             : 
     764           2 :   f = vlib_get_frame_to_node (vm, node_index);
     765           2 :   to_next = vlib_frame_vector_args (f);
     766           2 :   to_next[0] = bi;
     767           2 :   f->n_vectors = 1;
     768             : 
     769           2 :   vlib_put_frame_to_node (vm, node_index, f);
     770             : 
     771           2 :   return f->n_vectors;
     772             : }
     773             : 
     774             : 
     775             : /*
     776             :  * fd.io coding-style-patch-verification: ON
     777             :  *
     778             :  * Local Variables:
     779             :  * eval: (c-set-style "gnu")
     780             :  * End:
     781             :  */

Generated by: LCOV version 1.14