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/ip/igmp_packet.h>
18 : #include <vnet/ip/ip6_link.h>
19 :
20 : #include <vrrp/vrrp.h>
21 : #include <vrrp/vrrp_packet.h>
22 :
23 : #include <vpp/app/version.h>
24 :
25 : vrrp_main_t vrrp_main;
26 :
27 : static const mac_address_t ipv4_vmac = {
28 : .bytes = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00}
29 : };
30 :
31 : static const mac_address_t ipv6_vmac = {
32 : .bytes = {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00}
33 : };
34 :
35 : vlib_simple_counter_main_t vrrp_errs[] = {
36 : /* Total number of VRRP packets received with invalid checksum */
37 : {
38 : .name = "CHKSUM_ERRS",
39 : .stat_segment_name = "/net/vrrp/chksum-errs",
40 : },
41 : /* Total number of VRRP packets received with unknown or unsupported version
42 : */
43 : {
44 : .name = "VERSION_ERRS",
45 : .stat_segment_name = "/net/vrrp/version-errs",
46 : },
47 : /* Total number of VRRP packets received with invalid VRID */
48 : {
49 : .name = "VRID_ERRS",
50 : .stat_segment_name = "/net/vrrp/vrid-errs",
51 : },
52 : /* Total number of VRRP packets received with TTL/Hop limit != 255 */
53 : {
54 : .name = "TTL_ERRS",
55 : .stat_segment_name = "/net/vrrp/ttl-errs",
56 : },
57 : /* Number of packets received with an address list not matching the locally
58 : configured one */
59 : {
60 : .name = "ADDR_LIST_ERRS",
61 : .stat_segment_name = "/net/vrrp/addr-list-errs",
62 : },
63 : /* Number of packets received with a length less than the VRRP header */
64 : {
65 : .name = "PACKET_LEN_ERRS",
66 : .stat_segment_name = "/net/vrrp/packet-len-errs",
67 : },
68 : };
69 :
70 : void
71 0 : vrrp_incr_err_counter (vrrp_err_counter_t err_type)
72 : {
73 0 : if (err_type >= VRRP_ERR_COUNTER_MAX)
74 : {
75 0 : clib_warning ("Attempt to increse error counter of unknown type %u",
76 : err_type);
77 0 : return;
78 : }
79 0 : vlib_increment_simple_counter (&vrrp_errs[err_type],
80 0 : vlib_get_main ()->thread_index, 0, 1);
81 : }
82 :
83 : // per-VRRP statistics
84 :
85 : /* Number of times a VRRP instance has transitioned to master */
86 : vlib_simple_counter_main_t vrrp_stats[] = {
87 : {
88 : .name = "MASTER_TRANS",
89 : .stat_segment_name = "/net/vrrp/master-trans",
90 : },
91 : /* Number of VRRP advertisements sent by a VRRP instance */
92 : {
93 : .name = "ADV_SENT",
94 : .stat_segment_name = "/net/vrrp/adv-sent",
95 : },
96 : /* Number of VRRP advertisements received by a VRRP instance */
97 : {
98 : .name = "ADV_RCVD",
99 : .stat_segment_name = "/net/vrrp/adv-rcvd",
100 : },
101 : /* Number of VRRP priority-0 packets sent by a VRRP instance */
102 : {
103 : .name = "PRIO0_SENT",
104 : .stat_segment_name = "/net/vrrp/prio0-sent",
105 : },
106 : /* Number of VRRP priority-0 packets received by a VRRP instance */
107 : {
108 : .name = "PRIO0_RCVD",
109 : .stat_segment_name = "/net/vrrp/prio0-rcvd",
110 : },
111 : };
112 :
113 : void
114 8 : vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index)
115 : {
116 8 : if (stat_type >= VRRP_STAT_COUNTER_MAX)
117 : {
118 0 : clib_warning ("Attempt to increse stat counter of unknown type %u",
119 : stat_type);
120 0 : return;
121 : }
122 8 : vlib_increment_simple_counter (
123 8 : &vrrp_stats[stat_type], vlib_get_main ()->thread_index, stat_index, 1);
124 : }
125 :
126 : typedef struct
127 : {
128 : vrrp_vr_key_t key;
129 : u32 count;
130 : } vrrp_hwif_vr_count_t;
131 :
132 : typedef enum
133 : {
134 : VRRP_IF_UPDATE_IP,
135 : VRRP_IF_UPDATE_HW_LINK,
136 : VRRP_IF_UPDATE_SW_ADMIN,
137 : } vrrp_intf_update_type_t;
138 :
139 : typedef struct
140 : {
141 : vrrp_intf_update_type_t type;
142 : u32 sw_if_index;
143 : u32 hw_if_index;
144 : int intf_up;
145 : } vrrp_intf_update_t;
146 :
147 : static int vrrp_intf_is_up (u32 sw_if_index, u8 is_ipv6,
148 : vrrp_intf_update_t * pending);
149 :
150 : static walk_rc_t
151 4 : vrrp_hwif_master_count_walk (vnet_main_t * vnm, u32 sw_if_index, void *arg)
152 : {
153 4 : vrrp_hwif_vr_count_t *vr_count = arg;
154 : vrrp_vr_t *vr;
155 :
156 4 : vr = vrrp_vr_lookup (sw_if_index, vr_count->key.vr_id,
157 4 : vr_count->key.is_ipv6);
158 :
159 4 : if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER))
160 2 : vr_count->count++;
161 :
162 4 : return WALK_CONTINUE;
163 : }
164 :
165 : /*
166 : * Get a count of VRs in master state on a given hardware interface with
167 : * the provided VR ID and AF.
168 : */
169 : static u32
170 4 : vrrp_vr_hwif_master_vrs_by_vrid (u32 hw_if_index, u8 vr_id, u8 is_ipv6)
171 : {
172 4 : vnet_main_t *vnm = vnet_get_main ();
173 : vrrp_hwif_vr_count_t vr_count;
174 :
175 4 : clib_memset (&vr_count, 0, sizeof (vr_count));
176 :
177 4 : vr_count.key.vr_id = vr_id;
178 4 : vr_count.key.is_ipv6 = is_ipv6;
179 :
180 4 : vnet_hw_interface_walk_sw (vnm, hw_if_index,
181 : vrrp_hwif_master_count_walk, &vr_count);
182 :
183 4 : return vr_count.count;
184 : }
185 :
186 : /*
187 : * Add or delete the VR virtual MAC address on the hardware interface
188 : * when a VR enters or leaves the master state.
189 : *
190 : * Multiple subinterfaces may host the same VR ID. We should only add or
191 : * delete the virtual MAC if this is the first VR being enabled on the
192 : * hardware interface or the last one being disabled, respectively.
193 : */
194 : void
195 4 : vrrp_vr_transition_vmac (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
196 : {
197 4 : vnet_main_t *vnm = vnet_get_main ();
198 4 : clib_error_t *error = 0;
199 : vnet_hw_interface_t *hw;
200 4 : u8 enable = (new_state == VRRP_VR_STATE_MASTER);
201 : u32 n_master_vrs;
202 :
203 4 : hw = vnet_get_sup_hw_interface (vnm, vr->config.sw_if_index);
204 : n_master_vrs =
205 4 : vrrp_vr_hwif_master_vrs_by_vrid (hw->hw_if_index, vr->config.vr_id,
206 4 : vrrp_vr_is_ipv6 (vr));
207 :
208 : /* enable only if current master vrs is 0, disable only if 0 or 1 */
209 4 : if ((enable && !n_master_vrs) || (!enable && (n_master_vrs < 2)))
210 : {
211 4 : clib_warning ("%s virtual MAC address %U on hardware interface %u",
212 : (enable) ? "Adding" : "Deleting",
213 : format_ethernet_address, vr->runtime.mac.bytes,
214 : hw->hw_if_index);
215 :
216 4 : error = vnet_hw_interface_add_del_mac_address
217 4 : (vnm, hw->hw_if_index, vr->runtime.mac.bytes, enable);
218 : }
219 :
220 4 : if (error)
221 0 : clib_error_report (error);
222 4 : }
223 :
224 : /*
225 : * Manage VR interface data on transition to/from master:
226 : * - enable or disable ARP/ND input feature if appropriate
227 : * - update count of VRs in master state
228 : */
229 : static void
230 4 : vrrp_vr_transition_intf (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
231 : {
232 : vrrp_intf_t *intf;
233 4 : const char *arc_name = 0, *node_name = 0;
234 4 : const char *mc_arc_name = 0, *mc_node_name = 0;
235 4 : u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
236 : u32 *vr_index;
237 4 : int n_master_accept = 0;
238 4 : int n_started = 0;
239 :
240 4 : if (is_ipv6)
241 : {
242 2 : arc_name = "ip6-local";
243 2 : node_name = "vrrp6-nd-input";
244 2 : mc_arc_name = "ip6-multicast";
245 2 : mc_node_name = "vrrp6-accept-owner-input";
246 : }
247 : else
248 : {
249 2 : arc_name = "arp";
250 2 : node_name = "vrrp4-arp-input";
251 2 : mc_arc_name = "ip4-multicast";
252 2 : mc_node_name = "vrrp4-accept-owner-input";
253 : }
254 :
255 4 : intf = vrrp_intf_get (vr->config.sw_if_index);
256 :
257 : /* Check other VRs on this intf to see if features need to be toggled */
258 8 : vec_foreach (vr_index, intf->vr_indices[is_ipv6])
259 : {
260 4 : vrrp_vr_t *intf_vr = vrrp_vr_lookup_index (*vr_index);
261 :
262 4 : if (intf_vr == vr)
263 4 : continue;
264 :
265 0 : if (intf_vr->runtime.state == VRRP_VR_STATE_INIT)
266 0 : continue;
267 :
268 0 : n_started++;
269 :
270 0 : if ((intf_vr->runtime.state == VRRP_VR_STATE_MASTER) &&
271 0 : vrrp_vr_accept_mode_enabled (intf_vr))
272 0 : n_master_accept++;
273 : }
274 :
275 : /* If entering/leaving init state, start/stop ARP or ND feature if no other
276 : * VRs are active on the interface.
277 : */
278 4 : if (((vr->runtime.state == VRRP_VR_STATE_INIT) ||
279 4 : (new_state == VRRP_VR_STATE_INIT)) && (n_started == 0))
280 4 : vnet_feature_enable_disable (arc_name, node_name,
281 : vr->config.sw_if_index,
282 : (new_state != VRRP_VR_STATE_INIT), NULL, 0);
283 :
284 : /* Special housekeeping when entering/leaving master mode */
285 4 : if ((vr->runtime.state == VRRP_VR_STATE_MASTER) ||
286 : (new_state == VRRP_VR_STATE_MASTER))
287 : {
288 : /* Maintain count of master state VRs on interface */
289 4 : if (new_state == VRRP_VR_STATE_MASTER)
290 2 : intf->n_master_vrs[is_ipv6]++;
291 2 : else if (intf->n_master_vrs[is_ipv6] > 0)
292 2 : intf->n_master_vrs[is_ipv6]--;
293 :
294 : /* If accept mode is enabled and no other master on intf has accept
295 : * mode enabled, enable/disable feature node to avoid spurious drops by
296 : * spoofing check.
297 : */
298 4 : if (vrrp_vr_accept_mode_enabled (vr) && !n_master_accept)
299 0 : vnet_feature_enable_disable (mc_arc_name, mc_node_name,
300 : vr->config.sw_if_index,
301 : (new_state == VRRP_VR_STATE_MASTER),
302 : NULL, 0);
303 : }
304 4 : }
305 :
306 : /* If accept mode enabled, add/remove VR addresses from interface */
307 : static void
308 4 : vrrp_vr_transition_addrs (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
309 : {
310 4 : vlib_main_t *vm = vlib_get_main ();
311 : u8 is_del;
312 : ip46_address_t *vr_addr;
313 :
314 4 : if (!vrrp_vr_accept_mode_enabled (vr))
315 4 : return;
316 :
317 : /* owner always has VR addresses configured, should never remove them */
318 0 : if (vrrp_vr_is_owner (vr))
319 0 : return;
320 :
321 : /* only need to do something if entering or leaving master state */
322 0 : if ((vr->runtime.state != VRRP_VR_STATE_MASTER) &&
323 : (new_state != VRRP_VR_STATE_MASTER))
324 0 : return;
325 :
326 0 : is_del = (new_state != VRRP_VR_STATE_MASTER);
327 :
328 0 : clib_warning ("%s VR addresses on sw_if_index %u",
329 : (is_del) ? "Deleting" : "Adding", vr->config.sw_if_index);
330 :
331 0 : vec_foreach (vr_addr, vr->config.vr_addrs)
332 : {
333 0 : ip_interface_address_t *ia = NULL;
334 :
335 : /* We need to know the address length to use, find it from another
336 : * address on the interface. Or use a default (/24, /64).
337 : */
338 0 : if (!vrrp_vr_is_ipv6 (vr))
339 : {
340 0 : ip4_main_t *im = &ip4_main;
341 : ip4_address_t *intf4;
342 :
343 : intf4 =
344 0 : ip4_interface_address_matching_destination
345 0 : (im, &vr_addr->ip4, vr->config.sw_if_index, &ia);
346 :
347 0 : ip4_add_del_interface_address (vm, vr->config.sw_if_index,
348 : &vr_addr->ip4,
349 0 : (intf4 ? ia->address_length : 24),
350 : is_del);
351 : }
352 : else
353 : {
354 0 : ip6_main_t *im = &ip6_main;
355 : ip6_address_t *intf6;
356 :
357 : intf6 =
358 0 : ip6_interface_address_matching_destination
359 0 : (im, &vr_addr->ip6, vr->config.sw_if_index, &ia);
360 :
361 0 : ip6_add_del_interface_address (vm, vr->config.sw_if_index,
362 : &vr_addr->ip6,
363 0 : (intf6 ? ia->address_length : 64),
364 : is_del);
365 : }
366 : }
367 : }
368 :
369 : void
370 4 : vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data)
371 : {
372 :
373 4 : clib_warning ("VR %U transitioning to %U", format_vrrp_vr_key, vr,
374 : format_vrrp_vr_state, new_state);
375 :
376 : /* Don't do anything if transitioning to the state VR is already in.
377 : * This should never happen, just covering our bases.
378 : */
379 4 : if (new_state == vr->runtime.state)
380 0 : return;
381 :
382 4 : if (new_state == VRRP_VR_STATE_MASTER)
383 : {
384 2 : vrrp_incr_stat_counter (VRRP_STAT_COUNTER_MASTER_TRANS, vr->stat_index);
385 : /* RFC 5798 sec 6.4.1 (105) - startup event for VR with priority 255
386 : * sec 6.4.2 (365) - master down timer fires on backup VR
387 : */
388 :
389 2 : vrrp_vr_multicast_group_join (vr);
390 2 : vrrp_adv_send (vr, 0);
391 2 : vrrp_garp_or_na_send (vr);
392 :
393 2 : vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
394 : }
395 2 : else if (new_state == VRRP_VR_STATE_BACKUP)
396 : {
397 : /* RFC 5798 sec 6.4.1 (150) - startup event for VR with priority < 255
398 : * sec 6.4.3 (735) - master preempted by higher priority VR
399 : */
400 :
401 0 : vrrp_vr_multicast_group_join (vr);
402 :
403 0 : if (vr->runtime.state == VRRP_VR_STATE_MASTER)
404 : {
405 0 : vrrp_input_process_args_t *args = data;
406 :
407 0 : if (args)
408 0 : vr->runtime.master_adv_int = args->max_adv_int;
409 : }
410 : else /* INIT, INTF_DOWN */
411 0 : vr->runtime.master_adv_int = vr->config.adv_interval;
412 :
413 0 : vrrp_vr_skew_compute (vr);
414 0 : vrrp_vr_master_down_compute (vr);
415 0 : vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
416 :
417 : }
418 2 : else if (new_state == VRRP_VR_STATE_INIT)
419 : {
420 : /* RFC 5798 sec 6.4.2 (345) - shutdown event for backup VR
421 : * sec 6.4.3 (655) - shutdown event for master VR
422 : */
423 :
424 2 : vrrp_vr_timer_cancel (vr);
425 2 : if (vr->runtime.state == VRRP_VR_STATE_MASTER)
426 2 : vrrp_adv_send (vr, 1);
427 : }
428 0 : else if (new_state == VRRP_VR_STATE_INTF_DOWN)
429 : /* State is not specified by RFC. This is to avoid attempting to
430 : * send packets on an interface that's down and to avoid having a
431 : * VR believe it is already the master when an interface is brought up
432 : */
433 0 : vrrp_vr_timer_cancel (vr);
434 :
435 : /* add/delete virtual IP addrs if accept_mode is true */
436 4 : vrrp_vr_transition_addrs (vr, new_state);
437 :
438 : /* enable/disable input features if necessary */
439 4 : vrrp_vr_transition_intf (vr, new_state);
440 :
441 : /* add/delete virtual MAC address on NIC if necessary */
442 4 : vrrp_vr_transition_vmac (vr, new_state);
443 :
444 4 : vrrp_vr_event (vr, new_state);
445 :
446 4 : vr->runtime.state = new_state;
447 : }
448 :
449 : #define VRRP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 18 }
450 : #define VRRP6_MCAST_ADDR_AS_U8 \
451 : { 0xff, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12 }
452 :
453 : static const mfib_prefix_t all_vrrp4_routers = {
454 : .fp_proto = FIB_PROTOCOL_IP4,
455 : .fp_len = 32,
456 : .fp_grp_addr = {
457 : .ip4 = {
458 : .as_u8 = VRRP4_MCAST_ADDR_AS_U8,
459 : },
460 : },
461 : };
462 :
463 : static const mfib_prefix_t all_vrrp6_routers = {
464 : .fp_proto = FIB_PROTOCOL_IP6,
465 : .fp_len = 128,
466 : .fp_grp_addr = {
467 : .ip6 = {
468 : .as_u8 = VRRP6_MCAST_ADDR_AS_U8,
469 : },
470 : },
471 : };
472 :
473 : static int
474 4 : vrrp_intf_enable_disable_mcast (u8 enable, u32 sw_if_index, u8 is_ipv6)
475 : {
476 4 : vrrp_main_t *vrm = &vrrp_main;
477 : vrrp_intf_t *intf;
478 : u32 fib_index, i;
479 4 : u32 n_vrs_in_fib = 0;
480 : const mfib_prefix_t *vrrp_prefix;
481 : fib_protocol_t proto;
482 : vnet_link_t link_type;
483 4 : fib_route_path_t for_us = {
484 : .frp_sw_if_index = 0xffffffff,
485 : .frp_weight = 1,
486 : .frp_flags = FIB_ROUTE_PATH_LOCAL,
487 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
488 : };
489 4 : fib_route_path_t via_itf = {
490 : .frp_sw_if_index = sw_if_index,
491 : .frp_weight = 1,
492 : .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
493 : };
494 :
495 4 : intf = vrrp_intf_get (sw_if_index);
496 :
497 4 : if (is_ipv6)
498 : {
499 2 : proto = FIB_PROTOCOL_IP6;
500 2 : link_type = VNET_LINK_IP6;
501 2 : vrrp_prefix = &all_vrrp6_routers;
502 : }
503 : else
504 : {
505 2 : proto = FIB_PROTOCOL_IP4;
506 2 : link_type = VNET_LINK_IP4;
507 2 : vrrp_prefix = &all_vrrp4_routers;
508 : }
509 :
510 4 : for_us.frp_proto = fib_proto_to_dpo (proto);
511 4 : via_itf.frp_proto = fib_proto_to_dpo (proto);
512 4 : fib_index = mfib_table_get_index_for_sw_if_index (proto, sw_if_index);
513 :
514 16 : vec_foreach_index (i, vrm->vrrp_intfs)
515 : {
516 12 : if (mfib_table_get_index_for_sw_if_index (proto, i) != fib_index)
517 0 : continue;
518 :
519 12 : n_vrs_in_fib += vrrp_intf_num_vrs (i, is_ipv6);
520 : }
521 :
522 4 : if (enable)
523 : {
524 : /* ensure that the local mcast route exists */
525 2 : mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
526 : MFIB_ENTRY_FLAG_NONE, &for_us);
527 :
528 2 : mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
529 : MFIB_ENTRY_FLAG_NONE, &via_itf);
530 2 : intf->mcast_adj_index[! !is_ipv6] =
531 2 : adj_mcast_add_or_lock (proto, link_type, sw_if_index);
532 : }
533 : else
534 : {
535 : /* Remove mcast local routes if this is the last VR being deleted */
536 2 : if (n_vrs_in_fib == 0)
537 2 : mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
538 : &for_us);
539 :
540 2 : mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
541 : &via_itf);
542 : }
543 :
544 4 : return 0;
545 : }
546 :
547 : static int
548 4 : vrrp_intf_vr_add_del (u8 is_add, u32 sw_if_index, u32 vr_index, u8 is_ipv6)
549 : {
550 : vrrp_intf_t *vr_intf;
551 :
552 4 : vr_intf = vrrp_intf_get (sw_if_index);
553 4 : if (!vr_intf)
554 0 : return -1;
555 :
556 4 : if (is_add)
557 : {
558 2 : if (!vec_len (vr_intf->vr_indices[is_ipv6]))
559 2 : vrrp_intf_enable_disable_mcast (1, sw_if_index, is_ipv6);
560 :
561 2 : vec_add1 (vr_intf->vr_indices[is_ipv6], vr_index);
562 : }
563 : else
564 : {
565 2 : u32 per_intf_index =
566 2 : vec_search (vr_intf->vr_indices[is_ipv6], vr_index);
567 :
568 2 : if (per_intf_index != ~0)
569 2 : vec_del1 (vr_intf->vr_indices[is_ipv6], per_intf_index);
570 :
571 : /* no more VRs on this interface, disable multicast */
572 2 : if (!vec_len (vr_intf->vr_indices[is_ipv6]))
573 2 : vrrp_intf_enable_disable_mcast (0, sw_if_index, is_ipv6);
574 : }
575 :
576 4 : return 0;
577 : }
578 :
579 : /* RFC 5798 section 8.3.2 says to take care not to configure more than
580 : * one VRRP router as the "IPvX address owner" of a VRID. Make sure that
581 : * all of the addresses configured for this VR are configured on the
582 : * interface.
583 : */
584 : static int
585 2 : vrrp_vr_valid_addrs_owner (vrrp_vr_config_t * vr_conf)
586 : {
587 : ip46_address_t *addr;
588 2 : u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
589 :
590 4 : vec_foreach (addr, vr_conf->vr_addrs)
591 : {
592 2 : if (!ip_interface_has_address (vr_conf->sw_if_index, addr, !is_ipv6))
593 0 : return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
594 : }
595 :
596 2 : return 0;
597 : }
598 :
599 : static int
600 2 : vrrp_vr_valid_addrs_unused (vrrp_vr_config_t *vr_conf, index_t vrrp_index)
601 : {
602 : ip46_address_t *vr_addr;
603 2 : u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
604 :
605 4 : vec_foreach (vr_addr, vr_conf->vr_addrs)
606 : {
607 : u32 vr_index;
608 : void *addr;
609 :
610 2 : addr = (is_ipv6) ? (void *) &vr_addr->ip6 : (void *) &vr_addr->ip4;
611 2 : vr_index = vrrp_vr_lookup_address (vr_conf->sw_if_index, is_ipv6, addr);
612 2 : if (vr_index != ~0 && vrrp_index != vr_index)
613 0 : return VNET_API_ERROR_ADDRESS_IN_USE;
614 : }
615 :
616 2 : return 0;
617 : }
618 :
619 : static int
620 2 : vrrp_vr_valid_addrs (vrrp_vr_config_t *vr_conf, index_t vrrp_index)
621 : {
622 2 : int ret = 0;
623 :
624 : /* If the VR owns the addresses, make sure they are configured */
625 4 : if (vr_conf->priority == 255 &&
626 2 : (ret = vrrp_vr_valid_addrs_owner (vr_conf)) < 0)
627 0 : return ret;
628 :
629 : /* make sure no other VR has already configured any of the VR addresses */
630 2 : ret = vrrp_vr_valid_addrs_unused (vr_conf, vrrp_index);
631 :
632 2 : return ret;
633 : }
634 :
635 : int
636 4 : vrrp_vr_addr_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addr)
637 : {
638 4 : vrrp_main_t *vmp = &vrrp_main;
639 : u32 vr_index;
640 : vrrp4_arp_key_t key4;
641 : vrrp6_nd_key_t key6;
642 : ip46_address_t *addr;
643 :
644 4 : if (!vr || !vr_addr)
645 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
646 :
647 4 : vr_index = vr - vmp->vrs;
648 :
649 4 : if (vrrp_vr_is_ipv6 (vr))
650 : {
651 2 : key6.sw_if_index = vr->config.sw_if_index;
652 2 : key6.addr = vr_addr->ip6;
653 2 : if (is_add)
654 : {
655 1 : hash_set_mem_alloc (&vmp->vrrp6_nd_lookup, &key6, vr_index);
656 1 : vec_add1 (vr->config.vr_addrs, vr_addr[0]);
657 : }
658 : else
659 : {
660 1 : hash_unset_mem_free (&vmp->vrrp6_nd_lookup, &key6);
661 1 : vec_foreach (addr, vr->config.vr_addrs)
662 : {
663 1 : if (!ip46_address_cmp (addr, vr_addr))
664 : {
665 1 : vec_del1 (vr->config.vr_addrs, addr - vr->config.vr_addrs);
666 1 : break;
667 : }
668 : }
669 : }
670 : }
671 : else
672 : {
673 2 : key4.sw_if_index = vr->config.sw_if_index;
674 2 : key4.addr = vr_addr->ip4;
675 2 : if (is_add)
676 : {
677 1 : hash_set (vmp->vrrp4_arp_lookup, key4.as_u64, vr_index);
678 1 : vec_add1 (vr->config.vr_addrs, vr_addr[0]);
679 : }
680 : else
681 : {
682 1 : hash_unset (vmp->vrrp4_arp_lookup, key4.as_u64);
683 1 : vec_foreach (addr, vr->config.vr_addrs)
684 : {
685 1 : if (!ip46_address_cmp (addr, vr_addr))
686 : {
687 1 : vec_del1 (vr->config.vr_addrs, addr - vr->config.vr_addrs);
688 1 : break;
689 : }
690 : }
691 : }
692 : }
693 :
694 4 : return 0;
695 : }
696 :
697 : static void
698 4 : vrrp_vr_addrs_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addrs)
699 : {
700 : ip46_address_t *vr_addr;
701 :
702 8 : vec_foreach (vr_addr, vr_addrs)
703 : {
704 4 : vrrp_vr_addr_add_del (vr, is_add, vr_addr);
705 : }
706 4 : }
707 :
708 : int
709 0 : vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf)
710 : {
711 0 : index_t index = *vrrp_index;
712 0 : vrrp_main_t *vrm = &vrrp_main;
713 0 : vrrp_vr_t *vr = NULL;
714 0 : vrrp_vr_key_t key = { 0 };
715 0 : uint8_t must_restart = 0;
716 0 : int ret = 0;
717 :
718 : /* no valid index -> create and return allocated index */
719 0 : if (index == INDEX_INVALID)
720 : {
721 0 : return vrrp_vr_add_del (1, vr_conf, vrrp_index);
722 : }
723 : /* update: lookup vrrp instance */
724 0 : if (pool_is_free_index (vrm->vrs, index))
725 0 : return (VNET_API_ERROR_NO_SUCH_ENTRY);
726 :
727 : /* fetch existing VR */
728 0 : vr = pool_elt_at_index (vrm->vrs, index);
729 :
730 : /* populate key */
731 0 : key.vr_id = vr->config.vr_id;
732 0 : key.is_ipv6 = !!(vr->config.flags & VRRP_VR_IPV6);
733 : ;
734 0 : key.sw_if_index = vr->config.sw_if_index;
735 :
736 : /* Do not allow changes to the keys of the VRRP instance */
737 0 : if (vr_conf->vr_id != key.vr_id || vr_conf->sw_if_index != key.sw_if_index ||
738 0 : !!(vr_conf->flags & VRRP_VR_IPV6) != key.is_ipv6)
739 : {
740 0 : clib_warning ("Attempt to change VR ID, IP version or interface index "
741 : "for VRRP instance with index %u",
742 : index);
743 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
744 : }
745 :
746 : /* were IPvX addresses included ? */
747 0 : if (!vec_len (vr_conf->vr_addrs))
748 : {
749 0 : clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
750 : " does not contain IP addresses",
751 : key.vr_id, key.is_ipv6 ? 6 : 4, key.sw_if_index);
752 0 : return VNET_API_ERROR_INVALID_SRC_ADDRESS;
753 : }
754 :
755 : /* Make sure the addresses are ok to use */
756 0 : if ((ret = vrrp_vr_valid_addrs (vr_conf, index)) < 0)
757 0 : return ret;
758 :
759 : /* stop it if needed */
760 0 : must_restart = (vr->runtime.state != VRRP_VR_STATE_INIT);
761 0 : if (must_restart)
762 0 : vrrp_vr_start_stop (0, &key);
763 :
764 : /* overwrite new config */
765 0 : vr->config.priority = vr_conf->priority;
766 0 : vr->config.adv_interval = vr_conf->adv_interval;
767 0 : vr->config.flags = vr_conf->flags;
768 :
769 : /* check if any address has changed */
770 : ip46_address_t *vr_addr, *conf_addr;
771 : uint8_t found;
772 0 : vec_foreach (vr_addr, vr->config.vr_addrs)
773 : {
774 0 : found = 0;
775 0 : vec_foreach (conf_addr, vr_conf->vr_addrs)
776 : {
777 0 : if (ip46_address_is_equal (vr_addr, conf_addr))
778 : {
779 0 : found = 1;
780 0 : break;
781 : }
782 : }
783 0 : if (!found)
784 : {
785 0 : vrrp_vr_addr_add_del (vr, 0, vr_addr);
786 : }
787 : }
788 0 : vec_foreach (conf_addr, vr_conf->vr_addrs)
789 : {
790 0 : found = 0;
791 0 : vec_foreach (vr_addr, vr->config.vr_addrs)
792 : {
793 0 : if (ip46_address_is_equal (vr_addr, conf_addr))
794 : {
795 0 : found = 1;
796 0 : break;
797 : }
798 : }
799 0 : if (!found)
800 : {
801 0 : vrrp_vr_addr_add_del (vr, 1, conf_addr);
802 : }
803 : }
804 :
805 : /* restart it if needed */
806 0 : if (must_restart)
807 0 : vrrp_vr_start_stop (1, &key);
808 :
809 0 : return 0;
810 : }
811 :
812 : static void
813 2 : vrrp_vr_del_common (vrrp_vr_t *vr, vrrp_vr_key_t *key)
814 : {
815 2 : vrrp_main_t *vrm = &vrrp_main;
816 : ip46_address_t *vr_addrs_del_copy;
817 :
818 2 : vrrp_vr_timer_cancel (vr);
819 2 : vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, 0);
820 2 : vr_addrs_del_copy = vec_dup (vr->config.vr_addrs);
821 2 : vrrp_vr_addrs_add_del (vr, 0, vr_addrs_del_copy);
822 2 : mhash_unset (&vrm->vr_index_by_key, key, 0);
823 2 : vec_free (vr_addrs_del_copy);
824 2 : vec_free (vr->config.peer_addrs);
825 2 : vec_free (vr->config.vr_addrs);
826 2 : vec_free (vr->tracking.interfaces);
827 2 : pool_put (vrm->vrs, vr);
828 2 : }
829 :
830 : int
831 0 : vrrp_vr_del (index_t vrrp_index)
832 : {
833 0 : vrrp_main_t *vrm = &vrrp_main;
834 : vrrp_vr_key_t key;
835 0 : vrrp_vr_t *vr = 0;
836 :
837 0 : if (pool_is_free_index (vrm->vrs, vrrp_index))
838 : {
839 0 : return (VNET_API_ERROR_NO_SUCH_ENTRY);
840 : }
841 : else
842 : {
843 0 : vr = pool_elt_at_index (vrm->vrs, vrrp_index);
844 0 : key.sw_if_index = vr->config.sw_if_index;
845 0 : key.vr_id = vr->config.vr_id;
846 0 : key.is_ipv6 = vrrp_vr_is_ipv6 (vr);
847 0 : vrrp_vr_del_common (vr, &key);
848 0 : return 0;
849 : }
850 : }
851 :
852 : /* Action function shared between message handler and debug CLI */
853 : int
854 4 : vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t *vr_conf, index_t *ret_index)
855 : {
856 4 : vrrp_main_t *vrm = &vrrp_main;
857 4 : vnet_main_t *vnm = vnet_get_main ();
858 : vrrp_vr_key_t key;
859 : uword *p;
860 : u32 vr_index;
861 4 : vrrp_vr_t *vr = 0;
862 : int ret;
863 :
864 8 : if (vr_conf->sw_if_index == ~0 ||
865 4 : !vnet_sw_interface_is_valid (vnm, vr_conf->sw_if_index))
866 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
867 :
868 4 : clib_memset (&key, 0, sizeof (key));
869 :
870 4 : key.sw_if_index = vr_conf->sw_if_index;
871 4 : key.vr_id = vr_conf->vr_id;
872 4 : key.is_ipv6 = ((vr_conf->flags & VRRP_VR_IPV6) != 0);
873 :
874 4 : p = mhash_get (&vrm->vr_index_by_key, &key);
875 :
876 4 : if (is_add)
877 : {
878 : /* does a VR matching this key already exist ? */
879 2 : if (p)
880 : {
881 0 : clib_warning ("VR %u for IPv%d already exists on sw_if_index %u",
882 : key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
883 0 : return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
884 : }
885 :
886 : /* were IPvX addresses included ? */
887 2 : if (!vec_len (vr_conf->vr_addrs))
888 : {
889 0 : clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
890 : " does not contain IP addresses",
891 : key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
892 0 : return VNET_API_ERROR_INVALID_SRC_ADDRESS;
893 : }
894 :
895 : /* Make sure the addresses are ok to use */
896 2 : if ((ret = vrrp_vr_valid_addrs (vr_conf, INDEX_INVALID)) < 0)
897 0 : return ret;
898 :
899 2 : pool_get_zero (vrm->vrs, vr);
900 2 : vr_index = vr - vrm->vrs;
901 :
902 2 : clib_memcpy (&vr->config, vr_conf, sizeof (vrrp_vr_config_t));
903 :
904 2 : vr->config.vr_addrs = 0; /* allocate our own memory */
905 2 : vrrp_vr_addrs_add_del (vr, is_add, vr_conf->vr_addrs);
906 :
907 2 : vr->runtime.state = VRRP_VR_STATE_INIT;
908 2 : vr->runtime.timer_index = ~0;
909 :
910 : /* set virtual MAC based on IP version and VR ID */
911 2 : vr->runtime.mac = (key.is_ipv6) ? ipv6_vmac : ipv4_vmac;
912 2 : vr->runtime.mac.bytes[5] = vr_conf->vr_id;
913 :
914 : /* recall pool index for stats */
915 2 : vr->stat_index = vr_index;
916 : /* and return it if we were asked to */
917 2 : if (ret_index != NULL)
918 : {
919 0 : *ret_index = vr_index;
920 : }
921 : /* allocate & reset stats */
922 12 : for (int i = 0; i < VRRP_STAT_COUNTER_MAX; i++)
923 : {
924 10 : vlib_validate_simple_counter (&vrrp_stats[i], vr_index);
925 10 : vlib_zero_simple_counter (&vrrp_stats[i], vr_index);
926 : }
927 :
928 2 : mhash_set (&vrm->vr_index_by_key, &key, vr_index, 0);
929 : }
930 : else
931 : {
932 2 : if (!p)
933 : {
934 0 : clib_warning ("No VR %u for IPv%d exists on sw_if_index %u",
935 : key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
936 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
937 : }
938 :
939 2 : vr_index = p[0];
940 2 : vr = pool_elt_at_index (vrm->vrs, vr_index);
941 2 : vrrp_vr_del_common (vr, &key);
942 : }
943 :
944 4 : vrrp_intf_vr_add_del (is_add, vr_conf->sw_if_index, vr_index, key.is_ipv6);
945 :
946 4 : return 0;
947 : }
948 :
949 : int
950 4 : vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key)
951 : {
952 4 : vrrp_main_t *vmp = &vrrp_main;
953 : uword *p;
954 4 : vrrp_vr_t *vr = 0;
955 :
956 4 : p = mhash_get (&vmp->vr_index_by_key, vr_key);
957 4 : if (!p)
958 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
959 :
960 4 : vr = pool_elt_at_index (vmp->vrs, p[0]);
961 :
962 : /* return success if already in the desired state */
963 4 : switch (vr->runtime.state)
964 : {
965 2 : case VRRP_VR_STATE_INIT:
966 2 : if (!is_start)
967 : {
968 0 : clib_warning ("Attempting to stop already stopped VR (%U)",
969 : format_vrrp_vr_key, vr);
970 0 : return 0;
971 : }
972 2 : break;
973 2 : default:
974 2 : if (is_start)
975 : {
976 0 : clib_warning ("Attempting to start already started VR (%U)",
977 : format_vrrp_vr_key, vr);
978 0 : return 0;
979 : }
980 2 : break;
981 : }
982 :
983 4 : if (is_start)
984 : {
985 2 : if (vrrp_vr_is_unicast (vr) && vec_len (vr->config.peer_addrs) == 0)
986 : {
987 0 : clib_warning ("Cannot start unicast VR without peers");
988 0 : return VNET_API_ERROR_INIT_FAILED;
989 : }
990 :
991 2 : vmp->n_vrs_started++;
992 :
993 2 : if (!vrrp_intf_is_up (vr->config.sw_if_index, vrrp_vr_is_ipv6 (vr),
994 : NULL))
995 : {
996 0 : clib_warning ("VRRP VR started on down interface (%U)",
997 : format_vrrp_vr_key, vr);
998 0 : vrrp_vr_transition (vr, VRRP_VR_STATE_INTF_DOWN, NULL);
999 : }
1000 2 : else if (vrrp_vr_is_owner (vr))
1001 2 : vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
1002 : else
1003 0 : vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, NULL);
1004 : }
1005 : else
1006 : {
1007 2 : vmp->n_vrs_started--;
1008 :
1009 2 : vrrp_vr_transition (vr, VRRP_VR_STATE_INIT, NULL);
1010 : }
1011 :
1012 4 : clib_warning ("%d VRs configured, %d VRs running",
1013 : pool_elts (vmp->vrs), vmp->n_vrs_started);
1014 :
1015 4 : return 0;
1016 : }
1017 :
1018 : static int
1019 0 : vrrp_vr_set_peers_validate (vrrp_vr_t * vr, ip46_address_t * peers)
1020 : {
1021 0 : if (!vrrp_vr_is_unicast (vr))
1022 : {
1023 0 : clib_warning ("Peers can only be set on a unicast VR");
1024 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
1025 : }
1026 :
1027 0 : if (vr->runtime.state != VRRP_VR_STATE_INIT)
1028 : {
1029 0 : clib_warning ("Cannot set peers on a running VR");
1030 0 : return VNET_API_ERROR_RSRC_IN_USE;
1031 : }
1032 :
1033 0 : if (vec_len (peers) == 0)
1034 : {
1035 0 : clib_warning ("No peer addresses provided");
1036 0 : return VNET_API_ERROR_INVALID_DST_ADDRESS;
1037 : }
1038 :
1039 0 : return 0;
1040 : }
1041 :
1042 : int
1043 0 : vrrp_vr_set_peers (vrrp_vr_key_t * vr_key, ip46_address_t * peers)
1044 : {
1045 0 : vrrp_main_t *vmp = &vrrp_main;
1046 : uword *p;
1047 0 : vrrp_vr_t *vr = 0;
1048 0 : int ret = 0;
1049 :
1050 0 : p = mhash_get (&vmp->vr_index_by_key, vr_key);
1051 0 : if (!p)
1052 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
1053 :
1054 0 : vr = pool_elt_at_index (vmp->vrs, p[0]);
1055 :
1056 0 : ret = vrrp_vr_set_peers_validate (vr, peers);
1057 0 : if (ret < 0)
1058 0 : return ret;
1059 :
1060 0 : if (vr->config.peer_addrs)
1061 0 : vec_free (vr->config.peer_addrs);
1062 :
1063 0 : vr->config.peer_addrs = vec_dup (peers);
1064 :
1065 0 : return 0;
1066 : }
1067 :
1068 : /* Manage reference on the interface to the VRs which track that interface */
1069 : static void
1070 0 : vrrp_intf_tracking_vr_add_del (u32 sw_if_index, vrrp_vr_t * vr, u8 is_add)
1071 : {
1072 : vrrp_intf_t *intf;
1073 : u32 vr_index;
1074 0 : u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
1075 : int i;
1076 :
1077 0 : intf = vrrp_intf_get (sw_if_index);
1078 0 : vr_index = vrrp_vr_index (vr);
1079 :
1080 : /* Try to find the VR index in the list of tracking VRs */
1081 0 : vec_foreach_index (i, intf->tracking_vrs[is_ipv6])
1082 : {
1083 0 : if (vec_elt (intf->tracking_vrs[is_ipv6], i) != vr_index)
1084 0 : continue;
1085 :
1086 : /* Current index matches VR index */
1087 0 : if (!is_add)
1088 0 : vec_delete (intf->tracking_vrs[is_ipv6], 1, i);
1089 :
1090 : /* If deleting, the job is done. If adding, it's already here */
1091 0 : return;
1092 : }
1093 :
1094 : /* vr index was not found. */
1095 0 : if (is_add)
1096 0 : vec_add1 (intf->tracking_vrs[is_ipv6], vr_index);
1097 : }
1098 :
1099 : /* Check if sw intf admin state is up or in the process of coming up */
1100 : static int
1101 6 : vrrp_intf_sw_admin_up (u32 sw_if_index, vrrp_intf_update_t * pending)
1102 : {
1103 6 : vnet_main_t *vnm = vnet_get_main ();
1104 : int admin_up;
1105 :
1106 6 : if (pending && (pending->type == VRRP_IF_UPDATE_SW_ADMIN))
1107 2 : admin_up = pending->intf_up;
1108 : else
1109 4 : admin_up = vnet_sw_interface_is_admin_up (vnm, sw_if_index);
1110 :
1111 6 : return admin_up;
1112 : }
1113 :
1114 : /* Check if hw intf link state is up or int the process of coming up */
1115 : static int
1116 6 : vrrp_intf_hw_link_up (u32 sw_if_index, vrrp_intf_update_t * pending)
1117 : {
1118 6 : vnet_main_t *vnm = vnet_get_main ();
1119 : vnet_sw_interface_t *sup_sw;
1120 : int link_up;
1121 :
1122 6 : sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
1123 :
1124 6 : if (pending && (pending->type == VRRP_IF_UPDATE_HW_LINK) &&
1125 2 : (pending->hw_if_index == sup_sw->hw_if_index))
1126 2 : link_up = pending->intf_up;
1127 : else
1128 4 : link_up = vnet_hw_interface_is_link_up (vnm, sup_sw->hw_if_index);
1129 :
1130 6 : return link_up;
1131 : }
1132 :
1133 : /* Check if interface has ability to send IP packets. */
1134 : static int
1135 6 : vrrp_intf_ip_up (u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t * pending)
1136 : {
1137 : int ip_up;
1138 :
1139 6 : if (pending && pending->type == VRRP_IF_UPDATE_IP)
1140 0 : ip_up = pending->intf_up;
1141 : else
1142 : /* Either a unicast address has to be explicitly assigned, or
1143 : * for IPv6 only, a link local assigned and multicast/ND enabled
1144 : */
1145 6 : ip_up =
1146 6 : ((ip_interface_get_first_ip (sw_if_index, !is_ipv6) != 0) ||
1147 0 : (is_ipv6 && ip6_link_is_enabled (sw_if_index)));
1148 :
1149 6 : return ip_up;
1150 : }
1151 :
1152 : static int
1153 6 : vrrp_intf_is_up (u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t * pending)
1154 : {
1155 : int admin_up, link_up, ip_up;
1156 :
1157 6 : admin_up = vrrp_intf_sw_admin_up (sw_if_index, pending);
1158 6 : link_up = vrrp_intf_hw_link_up (sw_if_index, pending);
1159 6 : ip_up = vrrp_intf_ip_up (sw_if_index, is_ipv6, pending);
1160 :
1161 6 : return (admin_up && link_up && ip_up);
1162 : }
1163 :
1164 : /* Examine the state of interfaces tracked by a VR and compute the priority
1165 : * adjustment that should be applied to the VR. If this is being called
1166 : * by the hw_link_up_down callback, the pending new flags on the sup hw
1167 : * interface have not been updated yet, so accept those as an optional
1168 : * argument.
1169 : */
1170 : void
1171 2 : vrrp_vr_tracking_ifs_compute (vrrp_vr_t * vr, vrrp_intf_update_t * pending)
1172 : {
1173 : vrrp_vr_tracking_if_t *intf;
1174 2 : u32 total_priority = 0;
1175 :
1176 2 : vec_foreach (intf, vr->tracking.interfaces)
1177 : {
1178 0 : if (vrrp_intf_is_up (intf->sw_if_index, vrrp_vr_is_ipv6 (vr), pending))
1179 0 : continue;
1180 :
1181 0 : total_priority += intf->priority;
1182 : }
1183 :
1184 2 : if (total_priority != vr->tracking.interfaces_dec)
1185 : {
1186 0 : clib_warning ("VR %U interface track adjustment change from %u to %u",
1187 : format_vrrp_vr_key, vr, vr->tracking.interfaces_dec,
1188 : total_priority);
1189 0 : vr->tracking.interfaces_dec = total_priority;
1190 : }
1191 2 : }
1192 :
1193 : /* Manage tracked interfaces on a VR */
1194 : int
1195 0 : vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index, u8 prio,
1196 : u8 is_add)
1197 : {
1198 0 : vnet_main_t *vnm = vnet_get_main ();
1199 : vrrp_vr_tracking_if_t *track_intf;
1200 :
1201 : /* VR can't track non-existent interface */
1202 0 : if (!vnet_sw_interface_is_valid (vnm, sw_if_index))
1203 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1204 :
1205 : /* VR can't track it's own interface */
1206 0 : if (sw_if_index == vr->config.sw_if_index)
1207 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
1208 :
1209 : /* update intf vector of tracking VRs */
1210 0 : vrrp_intf_tracking_vr_add_del (sw_if_index, vr, is_add);
1211 :
1212 : /* update VR vector of tracked interfaces */
1213 0 : vec_foreach (track_intf, vr->tracking.interfaces)
1214 : {
1215 0 : if (track_intf->sw_if_index != sw_if_index)
1216 0 : continue;
1217 :
1218 : /* found it */
1219 0 : if (!is_add)
1220 0 : vec_delete
1221 : (vr->tracking.interfaces, 1, track_intf - vr->tracking.interfaces);
1222 :
1223 0 : return 0;
1224 : }
1225 :
1226 0 : if (is_add)
1227 : {
1228 0 : vec_add2 (vr->tracking.interfaces, track_intf, 1);
1229 :
1230 0 : track_intf->sw_if_index = sw_if_index;
1231 0 : track_intf->priority = prio;
1232 : }
1233 :
1234 0 : return 0;
1235 : }
1236 :
1237 : int
1238 2 : vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
1239 : vrrp_vr_tracking_if_t * track_ifs, u8 is_add)
1240 : {
1241 : vrrp_vr_tracking_if_t *track_if, *ifs_copy;
1242 2 : int rv = 0;
1243 :
1244 : /* if deleting & track_ifs points to the VR list of tracked intfs, the
1245 : * vector could be modified as we iterate it. make a copy instead */
1246 2 : ifs_copy = vec_dup (track_ifs);
1247 :
1248 : /* add each tracked interface in the vector */
1249 2 : vec_foreach (track_if, ifs_copy)
1250 : {
1251 0 : rv = vrrp_vr_tracking_if_add_del (vr, track_if->sw_if_index,
1252 0 : track_if->priority, (is_add != 0));
1253 :
1254 : /* if operation failed, undo the previous changes */
1255 0 : if (rv)
1256 : {
1257 : vrrp_vr_tracking_if_t *rb_if;
1258 :
1259 0 : for (rb_if = track_if - 1; rb_if >= track_ifs; rb_if -= 1)
1260 0 : vrrp_vr_tracking_if_add_del (vr, rb_if->sw_if_index,
1261 0 : rb_if->priority, !(is_add != 0));
1262 0 : break;
1263 : }
1264 : }
1265 :
1266 2 : vec_free (ifs_copy);
1267 :
1268 2 : vrrp_vr_tracking_ifs_compute (vr, 0);
1269 :
1270 2 : return rv;
1271 : }
1272 :
1273 : /* Compute priority to advertise on all VRs which track the given interface
1274 : * and address family. The flags on an HW interface are not updated until
1275 : * after link up/down callbacks are invoked, so if this function is called
1276 : * by the link up/down callback, the flags about to be set will be passed
1277 : * via the 'pending' argument. Otherwise, pending will be NULL.
1278 : */
1279 : static void
1280 62772 : vrrp_intf_tracking_vrs_compute (u32 sw_if_index,
1281 : vrrp_intf_update_t * pending, u8 is_ipv6)
1282 : {
1283 : u32 *vr_index;
1284 : vrrp_vr_t *vr;
1285 62772 : vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);
1286 :
1287 62772 : vec_foreach (vr_index, intf->tracking_vrs[is_ipv6])
1288 : {
1289 0 : vr = vrrp_vr_lookup_index (*vr_index);
1290 0 : if (vr)
1291 0 : vrrp_vr_tracking_ifs_compute (vr, pending);
1292 : }
1293 62772 : }
1294 :
1295 : /* Interface being brought up/down is a quasi-{startup/shutdown} event.
1296 : * Execute an appropriate state transition for all VRs on the interface.
1297 : * This function may be invoked by:
1298 : * sw interface admin up/down event
1299 : * hw interface link up/down event
1300 : */
1301 : clib_error_t *
1302 26940 : vrrp_sw_interface_up_down (vrrp_intf_update_t * pending)
1303 : {
1304 : vrrp_intf_t *intf;
1305 : int i;
1306 : u32 *vr_index;
1307 : vrrp_vr_t *vr;
1308 :
1309 26940 : intf = vrrp_intf_get (pending->sw_if_index);
1310 26940 : if (!intf)
1311 0 : return 0;
1312 :
1313 : /* adjust state of VR's configured on this interface */
1314 80820 : for (i = 0; i < 2; i++)
1315 : {
1316 : int is_up;
1317 :
1318 53880 : if (!intf->vr_indices[i])
1319 53876 : continue;
1320 :
1321 4 : is_up = vrrp_intf_is_up (pending->sw_if_index, i, pending);
1322 :
1323 4 : vec_foreach (vr_index, intf->vr_indices[i])
1324 : {
1325 : vrrp_vr_state_t vr_state;
1326 :
1327 0 : vr = vrrp_vr_lookup_index (*vr_index);
1328 0 : if (!vr)
1329 0 : continue;
1330 :
1331 0 : if (vr->runtime.state == VRRP_VR_STATE_INIT)
1332 0 : continue; /* VR not started yet, no transition */
1333 :
1334 0 : if (!is_up)
1335 0 : vr_state = VRRP_VR_STATE_INTF_DOWN;
1336 : else
1337 : {
1338 0 : if (vr->runtime.state != VRRP_VR_STATE_INTF_DOWN)
1339 0 : continue; /* shouldn't happen */
1340 :
1341 0 : vr_state = (vrrp_vr_is_owner (vr)) ?
1342 0 : VRRP_VR_STATE_MASTER : VRRP_VR_STATE_BACKUP;
1343 : }
1344 :
1345 0 : vrrp_vr_transition (vr, vr_state, NULL);
1346 : }
1347 : }
1348 :
1349 : /* compute adjustments on any VR's tracking this interface */
1350 26940 : vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1351 : 0 /* is_ipv6 */ );
1352 26940 : vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1353 : 1 /* is_ipv6 */ );
1354 :
1355 26940 : return 0;
1356 : }
1357 :
1358 : /* Process change in admin status on an interface */
1359 : clib_error_t *
1360 13514 : vrrp_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index,
1361 : u32 flags)
1362 : {
1363 13514 : vrrp_intf_update_t pending = {
1364 : .type = VRRP_IF_UPDATE_SW_ADMIN,
1365 : .sw_if_index = sw_if_index,
1366 13514 : .intf_up = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0),
1367 : };
1368 :
1369 13514 : return vrrp_sw_interface_up_down (&pending);
1370 : }
1371 :
1372 1151 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (vrrp_sw_interface_admin_up_down);
1373 :
1374 : static walk_rc_t
1375 13426 : vrrp_hw_interface_link_up_down_walk (vnet_main_t * vnm,
1376 : u32 sw_if_index, void *arg)
1377 : {
1378 13426 : vrrp_intf_update_t *pending = arg;
1379 :
1380 13426 : pending->sw_if_index = sw_if_index;
1381 13426 : vrrp_sw_interface_up_down (pending);
1382 :
1383 13426 : return WALK_CONTINUE;
1384 : }
1385 :
1386 : static clib_error_t *
1387 13336 : vrrp_hw_interface_link_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1388 : {
1389 13336 : vrrp_intf_update_t pending = {
1390 : .type = VRRP_IF_UPDATE_HW_LINK,
1391 : .hw_if_index = hw_if_index,
1392 13336 : .intf_up = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) != 0),
1393 : };
1394 :
1395 : /* walk the sw interface and sub interfaces to adjust interface tracking */
1396 13336 : vnet_hw_interface_walk_sw (vnm, hw_if_index,
1397 : vrrp_hw_interface_link_up_down_walk, &pending);
1398 :
1399 13336 : return 0;
1400 : }
1401 :
1402 1151 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (vrrp_hw_interface_link_up_down);
1403 :
1404 : static void
1405 4838 : vrrp_ip4_add_del_interface_addr (ip4_main_t * im,
1406 : uword opaque,
1407 : u32 sw_if_index,
1408 : ip4_address_t * address,
1409 : u32 address_length,
1410 : u32 if_address_index, u32 is_del)
1411 : {
1412 4838 : vrrp_intf_tracking_vrs_compute (sw_if_index, NULL, 0 /* is_ipv6 */ );
1413 4838 : }
1414 :
1415 : static ip6_link_delegate_id_t vrrp_ip6_delegate_id;
1416 :
1417 : static u8 *
1418 0 : format_vrrp_ip6_link (u8 * s, va_list * args)
1419 : {
1420 0 : index_t indi = va_arg (*args, index_t);
1421 0 : u32 indent = va_arg (*args, u32);
1422 : vrrp_intf_t *intf;
1423 : u32 *vr_index;
1424 :
1425 0 : intf = vrrp_intf_get ((u32) indi);
1426 :
1427 0 : s = format (s, "%UVRRP VRs monitoring this link:\n",
1428 : format_white_space, indent);
1429 :
1430 0 : vec_foreach (vr_index, intf->tracking_vrs[1])
1431 : {
1432 0 : vrrp_vr_t *vr = vrrp_vr_lookup_index (*vr_index);
1433 :
1434 0 : s = format (s, "%U%U\n", format_white_space, indent + 2,
1435 : format_vrrp_vr_key, vr);
1436 : }
1437 :
1438 0 : return s;
1439 : }
1440 :
1441 : static void
1442 4054 : vrrp_intf_ip6_enable_disable (u32 sw_if_index, int enable)
1443 : {
1444 4054 : vrrp_intf_update_t pending = {
1445 : .type = VRRP_IF_UPDATE_IP,
1446 : .sw_if_index = sw_if_index,
1447 : .intf_up = enable,
1448 : };
1449 :
1450 4054 : vrrp_intf_tracking_vrs_compute (sw_if_index, &pending, 1 /* is_ipv6 */ );
1451 4054 : }
1452 :
1453 : static void
1454 2113 : vrrp_intf_ip6_enable (u32 sw_if_index)
1455 : {
1456 2113 : vrrp_intf_ip6_enable_disable (sw_if_index, 1 /* enable */ );
1457 2113 : ip6_link_delegate_update (sw_if_index, vrrp_ip6_delegate_id, sw_if_index);
1458 2113 : }
1459 :
1460 : static void
1461 1941 : vrrp_intf_ip6_disable (index_t indi)
1462 : {
1463 1941 : vrrp_intf_ip6_enable_disable (indi, 0 /* enable */ );
1464 1941 : }
1465 :
1466 : const static ip6_link_delegate_vft_t vrrp_ip6_delegate_vft = {
1467 : .ildv_enable = vrrp_intf_ip6_enable,
1468 : .ildv_disable = vrrp_intf_ip6_disable,
1469 : .ildv_format = format_vrrp_ip6_link,
1470 : };
1471 :
1472 : static clib_error_t *
1473 575 : vrrp_init (vlib_main_t * vm)
1474 : {
1475 575 : vrrp_main_t *vmp = &vrrp_main;
1476 575 : clib_error_t *error = 0;
1477 575 : ip4_main_t *im4 = &ip4_main;
1478 : ip4_add_del_interface_address_callback_t cb4;
1479 : vlib_node_t *intf_output_node;
1480 :
1481 575 : clib_memset (vmp, 0, sizeof (*vmp));
1482 :
1483 575 : if ((error = vlib_call_init_function (vm, ip4_lookup_init)) ||
1484 575 : (error = vlib_call_init_function (vm, ip6_lookup_init)))
1485 0 : return error;
1486 :
1487 575 : vmp->vlib_main = vm;
1488 575 : vmp->vnet_main = vnet_get_main ();
1489 :
1490 575 : intf_output_node = vlib_get_node_by_name (vm, (u8 *) "interface-output");
1491 575 : vmp->intf_output_node_idx = intf_output_node->index;
1492 :
1493 575 : error = vrrp_plugin_api_hookup (vm);
1494 :
1495 575 : if (error)
1496 0 : return error;
1497 :
1498 575 : mhash_init (&vmp->vr_index_by_key, sizeof (u32), sizeof (vrrp_vr_key_t));
1499 575 : vmp->vrrp4_arp_lookup = hash_create (0, sizeof (uword));
1500 575 : vmp->vrrp6_nd_lookup = hash_create_mem (0, sizeof (vrrp6_nd_key_t),
1501 : sizeof (uword));
1502 :
1503 575 : cb4.function = vrrp_ip4_add_del_interface_addr;
1504 575 : cb4.function_opaque = 0;
1505 575 : vec_add1 (im4->add_del_interface_address_callbacks, cb4);
1506 :
1507 575 : vrrp_ip6_delegate_id = ip6_link_delegate_register (&vrrp_ip6_delegate_vft);
1508 :
1509 : /* allocate & reset error counters */
1510 4025 : for (int i = 0; i < VRRP_ERR_COUNTER_MAX; i++)
1511 : {
1512 3450 : vlib_validate_simple_counter (&vrrp_errs[i], 0);
1513 3450 : vlib_zero_simple_counter (&vrrp_errs[i], 0);
1514 : }
1515 :
1516 575 : return error;
1517 : }
1518 :
1519 1151 : VLIB_INIT_FUNCTION (vrrp_init);
1520 :
1521 :
1522 : /* *INDENT-OFF* */
1523 : VLIB_PLUGIN_REGISTER () =
1524 : {
1525 : .version = VPP_BUILD_VER,
1526 : .description = "VRRP v3 (RFC 5798)",
1527 : };
1528 : /* *INDENT-ON* */
1529 :
1530 : /*
1531 : * fd.io coding-style-patch-verification: ON
1532 : *
1533 : * Local Variables:
1534 : * eval: (c-set-style "gnu")
1535 : * End:
1536 : */
|