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 : */
|