blob: b470ddeba081726e80f80a5603ffc9b5d813095d [file] [log] [blame]
Matthew Smith39e94282020-02-11 11:25:32 -06001/*
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>
Neale Rannse2fe0972020-11-26 08:37:27 +000017#include <vnet/fib/fib_sas.h>
Matthew Smith39e94282020-02-11 11:25:32 -060018#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
27static const u8 vrrp4_dst_mac[6] = { 0x1, 0x0, 0x5e, 0x0, 0x0, 0x12 };
28static const u8 vrrp6_dst_mac[6] = { 0x33, 0x33, 0x0, 0x0, 0x0, 0x12 };
29static const u8 vrrp_src_mac_prefix[4] = { 0x0, 0x0, 0x5e, 0x0 };
30
31static int
32vrrp_adv_l2_build_multicast (vrrp_vr_t * vr, vlib_buffer_t * b)
33{
34 vnet_main_t *vnm = vnet_get_main ();
35 vnet_link_t link_type;
36 ethernet_header_t *eth;
37 int n_bytes = 0;
38 const void *dst_mac;
39 u8 mac_byte_ipver;
40 u8 *rewrite;
41
42 eth = vlib_buffer_get_current (b);
43
44 if (vrrp_vr_is_ipv6 (vr))
45 {
46 dst_mac = vrrp6_dst_mac;
47 link_type = VNET_LINK_IP6;
48 mac_byte_ipver = 0x2;
49 }
50 else
51 {
52 dst_mac = vrrp4_dst_mac;
53 link_type = VNET_LINK_IP4;
54 mac_byte_ipver = 0x1;
55 }
56
57 rewrite = ethernet_build_rewrite (vnm, vr->config.sw_if_index, link_type,
58 dst_mac);
59 clib_memcpy (eth, rewrite, vec_len (rewrite));
60
61 /* change the source mac from the HW addr to the VRRP virtual MAC */
62 clib_memcpy
63 (eth->src_address, vrrp_src_mac_prefix, sizeof (vrrp_src_mac_prefix));
64 eth->src_address[4] = mac_byte_ipver;
65 eth->src_address[5] = vr->config.vr_id;
66
67 n_bytes += vec_len (rewrite);
68
69 vlib_buffer_chain_increase_length (b, b, n_bytes);
70 vlib_buffer_advance (b, n_bytes);
71
72 vec_free (rewrite);
73
74 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
81static const ip46_address_t vrrp4_mcast_addr = {
82 .ip4 = {.as_u8 = VRRP4_MCAST_ADDR_AS_U8,},
83};
84
85static 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) */
90always_inline u16
91vrrp_adv_payload_len (vrrp_vr_t * vr)
92{
93 u16 addr_len = vrrp_vr_is_ipv6 (vr) ? 16 : 4;
94
95 return sizeof (vrrp_header_t) + (vec_len (vr->config.vr_addrs) * addr_len);
96}
97
98static int
99vrrp_adv_l3_build (vrrp_vr_t * vr, vlib_buffer_t * b,
100 const ip46_address_t * dst)
101{
102 if (!vrrp_vr_is_ipv6 (vr)) /* IPv4 */
103 {
104 ip4_header_t *ip4 = vlib_buffer_get_current (b);
105
106 clib_memset (ip4, 0, sizeof (*ip4));
107 ip4->ip_version_and_header_length = 0x45;
108 ip4->ttl = 255;
109 ip4->protocol = IP_PROTOCOL_VRRP;
110 clib_memcpy (&ip4->dst_address, &dst->ip4, sizeof (dst->ip4));
Neale Rannse2fe0972020-11-26 08:37:27 +0000111 fib_sas4_get (vr->config.sw_if_index, NULL, &ip4->src_address);
Matthew Smith39e94282020-02-11 11:25:32 -0600112 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
142u16
143vrrp_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
184static int
185vrrp_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
244static_always_inline u32
245vrrp_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
262static_always_inline const ip46_address_t *
263vrrp_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
271int
272vrrp_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
Matthew Smith26954942020-02-20 08:58:15 -0600285 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
Matthew Smith39e94282020-02-11 11:25:32 -0600295 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
Matthew Smith39e94282020-02-11 11:25:32 -0600316 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
317 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
318 vnet_buffer (b)->sw_if_index[VLIB_TX] = vr->config.sw_if_index;
319
320 if (is_unicast)
321 {
322 dst = vec_elt_at_index (vr->config.peer_addrs, i);
323 vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
324 }
325 else
326 vrrp_adv_l2_build_multicast (vr, b);
327
328 vrrp_adv_l3_build (vr, b, dst);
329 vrrp_adv_payload_build (vr, b, shutdown);
330
331 vlib_buffer_reset (b);
332
333 to_next[i] = bi0;
334 }
335
336 to_frame->n_vectors = n_buffers;
337
338 vlib_put_frame_to_node (vm, node_index, to_frame);
339
340 vec_free (bi);
341
342 return 0;
343}
344
345static void
346vrrp6_na_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b, ip6_address_t * addr6)
347{
348 vnet_main_t *vnm = vnet_get_main ();
349 vlib_main_t *vm = vlib_get_main ();
350 ethernet_header_t *eth;
351 ip6_header_t *ip6;
352 icmp6_neighbor_solicitation_or_advertisement_header_t *na;
353 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *ll_opt;
354 int payload_length, bogus_length;
355 int rewrite_bytes = 0;
356 u8 *rewrite;
357 u8 dst_mac[6];
358
359 /* L2 headers */
360 eth = vlib_buffer_get_current (b);
361
362 ip6_multicast_ethernet_address (dst_mac, IP6_MULTICAST_GROUP_ID_all_hosts);
363 rewrite =
364 ethernet_build_rewrite (vnm, vr->config.sw_if_index, VNET_LINK_IP6,
365 dst_mac);
366 rewrite_bytes += vec_len (rewrite);
367 clib_memcpy (eth, rewrite, vec_len (rewrite));
368 vec_free (rewrite);
369
370 b->current_length += rewrite_bytes;
371 vlib_buffer_advance (b, rewrite_bytes);
372
373 /* IPv6 */
374 ip6 = vlib_buffer_get_current (b);
375
376 b->current_length += sizeof (*ip6);
377 clib_memset (ip6, 0, sizeof (*ip6));
378
379 ip6->ip_version_traffic_class_and_flow_label = 0x00000060;
380 ip6->protocol = IP_PROTOCOL_ICMP6;
381 ip6->hop_limit = 255;
382 ip6_set_reserved_multicast_address (&ip6->dst_address,
383 IP6_MULTICAST_SCOPE_link_local,
384 IP6_MULTICAST_GROUP_ID_all_hosts);
385 ip6_address_copy (&ip6->src_address,
386 ip6_get_link_local_address (vr->config.sw_if_index));
387
388
389 /* ICMPv6 */
390 na = (icmp6_neighbor_solicitation_or_advertisement_header_t *) (ip6 + 1);
391 ll_opt =
392 (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *) (na +
393 1);
394
395 payload_length = sizeof (*na) + sizeof (*ll_opt);
396 b->current_length += payload_length;
397 clib_memset (na, 0, payload_length);
398
399 na->icmp.type = ICMP6_neighbor_advertisement; /* icmp code, csum are 0 */
400 na->target_address = *addr6;
401 na->advertisement_flags = clib_host_to_net_u32
402 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
403 | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER);
404
405 ll_opt->header.type =
406 ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
407 ll_opt->header.n_data_u64s = 1;
408 clib_memcpy (ll_opt->ethernet_address, vr->runtime.mac.bytes,
409 sizeof (vr->runtime.mac));
410
411 ip6->payload_length = clib_host_to_net_u16 (payload_length);
412 na->icmp.checksum =
413 ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus_length);
414}
415
416const mac_address_t broadcast_mac = {
417 .bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,},
418};
419
420static void
421vrrp4_garp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b, ip4_address_t * ip4)
422{
423 vnet_main_t *vnm = vnet_get_main ();
424 ethernet_header_t *eth;
425 ethernet_arp_header_t *arp;
426 int rewrite_bytes;
427 u8 *rewrite;
428
429 eth = vlib_buffer_get_current (b);
430
431 rewrite =
432 ethernet_build_rewrite (vnm, vr->config.sw_if_index, VNET_LINK_ARP,
433 broadcast_mac.bytes);
434 rewrite_bytes = vec_len (rewrite);
435 clib_memcpy (eth, rewrite, rewrite_bytes);
436 vec_free (rewrite);
437
438 b->current_length += rewrite_bytes;
439 vlib_buffer_advance (b, rewrite_bytes);
440
441 arp = vlib_buffer_get_current (b);
442 b->current_length += sizeof (*arp);
443
444 clib_memset (arp, 0, sizeof (*arp));
445
446 arp->l2_type = clib_host_to_net_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet);
447 arp->l3_type = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
448 arp->n_l2_address_bytes = 6;
449 arp->n_l3_address_bytes = 4;
450 arp->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
451 arp->ip4_over_ethernet[0].mac = vr->runtime.mac;
452 arp->ip4_over_ethernet[0].ip4 = *ip4;
453 arp->ip4_over_ethernet[1].mac = broadcast_mac;
454 arp->ip4_over_ethernet[1].ip4 = *ip4;
455}
456
457int
458vrrp_garp_or_na_send (vrrp_vr_t * vr)
459{
460 vlib_main_t *vm = vlib_get_main ();
461 vrrp_main_t *vmp = &vrrp_main;
462 vlib_frame_t *to_frame;
463 u32 *bi = 0;
464 u32 n_buffers;
465 u32 *to_next;
466 int i;
467
468 if (vec_len (vr->config.peer_addrs))
469 return 0; /* unicast is used in routed environments - don't garp */
470
471 n_buffers = vec_len (vr->config.vr_addrs);
472 if (!n_buffers)
473 {
474 clib_warning ("Unable to send gratuitous ARP for VR %U - no addresses",
475 format_vrrp_vr_key, vr);
476 return -1;
477 }
478
479 /* need to send a packet for each VR address */
480 vec_validate (bi, n_buffers - 1);
481
482 if (vlib_buffer_alloc (vm, bi, n_buffers) != n_buffers)
483 {
484 clib_warning ("Buffer allocation failed for %U", format_vrrp_vr_key,
485 vr);
486 vec_free (bi);
487 return -1;
488 }
489
490 to_frame = vlib_get_frame_to_node (vm, vmp->intf_output_node_idx);
491 to_frame->n_vectors = 0;
492 to_next = vlib_frame_vector_args (to_frame);
493
494 for (i = 0; i < n_buffers; i++)
495 {
496 vlib_buffer_t *b;
497 ip46_address_t *addr;
498
499 addr = vec_elt_at_index (vr->config.vr_addrs, i);
500 b = vlib_get_buffer (vm, bi[i]);
501
Matthew Smith39e94282020-02-11 11:25:32 -0600502 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
503 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
504 vnet_buffer (b)->sw_if_index[VLIB_TX] = vr->config.sw_if_index;
505
506 if (vrrp_vr_is_ipv6 (vr))
507 vrrp6_na_pkt_build (vr, b, &addr->ip6);
508 else
509 vrrp4_garp_pkt_build (vr, b, &addr->ip4);
510
511 vlib_buffer_reset (b);
512
513 to_next[i] = bi[i];
514 to_frame->n_vectors++;
515 }
516
517 vlib_put_frame_to_node (vm, vmp->intf_output_node_idx, to_frame);
518
519 return 0;
520}
521
522#define IGMP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 22 }
523
524static const ip4_header_t igmp_ip4_mcast = {
525 .ip_version_and_header_length = 0x46, /* there's options! */
526 .ttl = 1,
527 .protocol = IP_PROTOCOL_IGMP,
528 .tos = 0xc0,
529 .dst_address = {.as_u8 = IGMP4_MCAST_ADDR_AS_U8,},
530};
531
532static void
533vrrp_igmp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b)
534{
535 ip4_header_t *ip4;
536 u8 *ip4_options;
537 igmp_membership_report_v3_t *report;
538 igmp_membership_group_v3_t *group;
539
540 ip4 = vlib_buffer_get_current (b);
541 clib_memcpy (ip4, &igmp_ip4_mcast, sizeof (*ip4));
Neale Rannse2fe0972020-11-26 08:37:27 +0000542 fib_sas4_get (vr->config.sw_if_index, NULL, &ip4->src_address);
Matthew Smith39e94282020-02-11 11:25:32 -0600543
544 vlib_buffer_chain_increase_length (b, b, sizeof (*ip4));
545 vlib_buffer_advance (b, sizeof (*ip4));
546
547 ip4_options = (u8 *) (ip4 + 1);
548 ip4_options[0] = 0x94; /* 10010100 == the router alert option */
549 ip4_options[1] = 0x04; /* length == 4 bytes */
550 ip4_options[2] = 0x0; /* value == Router shall examine packet */
551 ip4_options[3] = 0x0; /* reserved */
552
553 vlib_buffer_chain_increase_length (b, b, 4);
554 vlib_buffer_advance (b, 4);
555
556 report = vlib_buffer_get_current (b);
557
558 report->header.type = IGMP_TYPE_membership_report_v3;
559 report->header.code = 0;
560 report->header.checksum = 0;
561 report->unused = 0;
562 report->n_groups = clib_host_to_net_u16 (1);
563
564 vlib_buffer_chain_increase_length (b, b, sizeof (*report));
565 vlib_buffer_advance (b, sizeof (*report));
566
567 group = vlib_buffer_get_current (b);
568 group->type = IGMP_MEMBERSHIP_GROUP_change_to_exclude;
569 group->n_aux_u32s = 0;
570 group->n_src_addresses = 0;
571 group->group_address.as_u32 = clib_host_to_net_u32 (0xe0000012);
572
573 vlib_buffer_chain_increase_length (b, b, sizeof (*group));
574 vlib_buffer_advance (b, sizeof (*group));
575
576 ip4->length = clib_host_to_net_u16 (b->current_data);
577 ip4->checksum = ip4_header_checksum (ip4);
578
579 int payload_len = vlib_buffer_get_current (b) - ((void *) report);
580 report->header.checksum =
581 ~ip_csum_fold (ip_incremental_checksum (0, report, payload_len));
582
583 vlib_buffer_reset (b);
584}
585
586/* multicast listener report packet format for ethernet. */
587typedef CLIB_PACKED (struct
588 {
589 ip6_hop_by_hop_ext_t ext_hdr;
590 ip6_router_alert_option_t alert;
591 ip6_padN_option_t pad;
592 icmp46_header_t icmp;
593 u16 rsvd;
594 u16 num_addr_records;
595 icmp6_multicast_address_record_t records[0];
596 }) icmp6_multicast_listener_report_header_t;
597
598static void
599vrrp_icmp6_mlr_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b)
600{
601 vlib_main_t *vm = vlib_get_main ();
602 ip6_header_t *ip6;
603 icmp6_multicast_listener_report_header_t *rh;
604 icmp6_multicast_address_record_t *rr;
605 ip46_address_t *vr_addr;
606 int bogus_length, n_addrs;
607 u16 payload_length;
608
609 n_addrs = vec_len (vr->config.vr_addrs) + 1;
610 payload_length = sizeof (*rh) + (n_addrs * sizeof (*rr));
611 b->current_length = sizeof (*ip6) + payload_length;
612 b->error = ICMP6_ERROR_NONE;
613
614 ip6 = vlib_buffer_get_current (b);
615 rh = (icmp6_multicast_listener_report_header_t *) (ip6 + 1);
616 rr = (icmp6_multicast_address_record_t *) (rh + 1);
617
618 /* IP header */
619 clib_memset (ip6, 0, b->current_length);
620 ip6->ip_version_traffic_class_and_flow_label =
621 clib_host_to_net_u32 (0x60000000);
622 ip6->hop_limit = 1;
623 ip6->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
624 ip6_set_reserved_multicast_address (&ip6->dst_address,
625 IP6_MULTICAST_SCOPE_link_local,
626 IP6_MULTICAST_GROUP_ID_mldv2_routers);
627 ip6_address_copy (&ip6->src_address,
628 ip6_get_link_local_address (vr->config.sw_if_index));
629
630 clib_memset (rh, 0, sizeof (*rh));
631
632 /* v6 hop by hop extension header */
633 rh->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
634 rh->ext_hdr.n_data_u64s = 0;
635
636 rh->alert.type = IP6_MLDP_ALERT_TYPE;
637 rh->alert.len = 2;
638 rh->alert.value = 0;
639
640 rh->pad.type = 1;
641 rh->pad.len = 0;
642
643 /* icmp6 header */
644 rh->icmp.type = ICMP6_multicast_listener_report_v2;
645 rh->icmp.checksum = 0;
646
647 rh->rsvd = 0;
648 rh->num_addr_records = clib_host_to_net_u16 (n_addrs);
649
650 /* group addresses */
651
652 /* All VRRP routers group */
653 rr->type = 4;
654 rr->aux_data_len_u32s = 0;
655 rr->num_sources = 0;
656 clib_memcpy
657 (&rr->mcast_addr, &vrrp6_mcast_addr.ip6, sizeof (ip6_address_t));
658
659 /* solicited node multicast addresses for VR addrs */
660 vec_foreach (vr_addr, vr->config.vr_addrs)
661 {
662 u32 id;
663
664 rr++;
665 rr->type = 4;
666 rr->aux_data_len_u32s = 0;
667 rr->num_sources = 0;
668
669 id = clib_net_to_host_u32 (vr_addr->ip6.as_u32[3]) & 0x00ffffff;
670 ip6_set_solicited_node_multicast_address (&rr->mcast_addr, id);
671 }
672
673 ip6->payload_length = clib_host_to_net_u16 (payload_length);
674 rh->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6,
675 &bogus_length);
676}
677
678int
679vrrp_vr_multicast_group_join (vrrp_vr_t * vr)
680{
681 vlib_main_t *vm = vlib_get_main ();
682 vlib_buffer_t *b;
683 vlib_frame_t *f;
684 vnet_main_t *vnm = vnet_get_main ();
685 vrrp_intf_t *intf;
686 u32 bi = 0, *to_next;
687 int n_buffers = 1;
688 u8 is_ipv6;
689 u32 node_index;
690
691 if (!vnet_sw_interface_is_up (vnm, vr->config.sw_if_index))
692 return 0;
693
Jon Loeligerdabdc192021-06-25 11:24:57 -0400694 is_ipv6 = vrrp_vr_is_ipv6 (vr);
695
696 if (is_ipv6 && ip6_link_is_enabled (vr->config.sw_if_index) == 0)
697 return 0;
698
Matthew Smith39e94282020-02-11 11:25:32 -0600699 if (vlib_buffer_alloc (vm, &bi, n_buffers) != n_buffers)
700 {
701 clib_warning ("Buffer allocation failed for %U", format_vrrp_vr_key,
702 vr);
703 return -1;
704 }
705
Matthew Smith39e94282020-02-11 11:25:32 -0600706 b = vlib_get_buffer (vm, bi);
707
Matthew Smith39e94282020-02-11 11:25:32 -0600708 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
709
710 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
711 vnet_buffer (b)->sw_if_index[VLIB_TX] = vr->config.sw_if_index;
712
713 intf = vrrp_intf_get (vr->config.sw_if_index);
714 vnet_buffer (b)->ip.adj_index[VLIB_TX] = intf->mcast_adj_index[is_ipv6];
715
716 if (is_ipv6)
717 {
718 vrrp_icmp6_mlr_pkt_build (vr, b);
719 node_index = ip6_rewrite_mcast_node.index;
720 }
721 else
722 {
723 vrrp_igmp_pkt_build (vr, b);
724 node_index = ip4_rewrite_mcast_node.index;
725 }
726
727 f = vlib_get_frame_to_node (vm, node_index);
728 to_next = vlib_frame_vector_args (f);
729 to_next[0] = bi;
730 f->n_vectors = 1;
731
732 vlib_put_frame_to_node (vm, node_index, f);
733
734 return f->n_vectors;
735}
736
737
738/*
739 * fd.io coding-style-patch-verification: ON
740 *
741 * Local Variables:
742 * eval: (c-set-style "gnu")
743 * End:
744 */