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