From 39e9428b90bc74d1bb15fc17759c8ef6ad712418 Mon Sep 17 00:00:00 2001 From: Matthew Smith Date: Tue, 11 Feb 2020 11:25:32 -0600 Subject: vrrp: add plugin providing vrrp support Type: feature Add a new plugin to support HA using VRRPv3 (RFC 5798). Change-Id: Iaa2c37e6172f8f41e9165f178f44d481f6e247b9 Signed-off-by: Matthew Smith --- src/plugins/vrrp/vrrp.h | 373 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 src/plugins/vrrp/vrrp.h (limited to 'src/plugins/vrrp/vrrp.h') diff --git a/src/plugins/vrrp/vrrp.h b/src/plugins/vrrp/vrrp.h new file mode 100644 index 00000000000..9c636c42802 --- /dev/null +++ b/src/plugins/vrrp/vrrp.h @@ -0,0 +1,373 @@ + +/* + * vrrp.h - vrrp plug-in header file + * + * Copyright 2019-2020 Rubicon Communications, LLC (Netgate) + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +#ifndef __included_vrrp_h__ +#define __included_vrrp_h__ + +#include +#include +#include + +#include +#include + +/* VRRP configuration */ +typedef enum vrrp_vr_flags +{ + VRRP_VR_PREEMPT = 0x1, + VRRP_VR_ACCEPT = 0x2, + VRRP_VR_UNICAST = 0x4, + VRRP_VR_IPV6 = 0x8, +} vrrp_vr_flags_t; + +typedef struct vrrp_vr_key +{ + u32 sw_if_index; + u8 vr_id; + u8 is_ipv6; +} vrrp_vr_key_t; + +/* *INDENT-OFF* */ +typedef CLIB_PACKED +(struct vrrp4_arp_key { + union { + struct { + u32 sw_if_index; + ip4_address_t addr; + }; + u64 as_u64; + }; +}) vrrp4_arp_key_t; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +typedef CLIB_PACKED +(struct vrrp6_nd_key { + u32 sw_if_index; + ip6_address_t addr; +}) vrrp6_nd_key_t; +/* *INDENT-ON* */ + +typedef struct vrrp_vr_tracking_if +{ + u32 sw_if_index; + u8 priority; +} vrrp_vr_tracking_if_t; + +typedef struct vrrp_vr_tracking +{ + vrrp_vr_tracking_if_t *interfaces; + u32 interfaces_dec; +} vrrp_vr_tracking_t; + +typedef struct vrrp_vr_config +{ + u32 sw_if_index; + u8 vr_id; + u8 priority; + u16 adv_interval; + vrrp_vr_flags_t flags; + ip46_address_t *vr_addrs; + ip46_address_t *peer_addrs; +} vrrp_vr_config_t; + +#define foreach_vrrp_vr_state \ +_(0, INIT, "Initialize") \ +_(1, BACKUP, "Backup") \ +_(2, MASTER, "Master") \ +_(3, INTF_DOWN, "Interface Down") + +/* VRRP runtime data */ +typedef enum vrrp_vr_state +{ +#define _(v,f,n) VRRP_VR_STATE_##f = v, + foreach_vrrp_vr_state +#undef _ +} vrrp_vr_state_t; + +typedef struct vrrp_vr_runtime +{ + vrrp_vr_state_t state; + u16 master_adv_int; + u16 skew; + u16 master_down_int; + mac_address_t mac; + f64 last_sent; + u32 timer_index; +} vrrp_vr_runtime_t; + +/* Per-VR data */ +typedef struct vrrp_vr +{ + vrrp_vr_config_t config; + vrrp_vr_runtime_t runtime; + vrrp_vr_tracking_t tracking; +} vrrp_vr_t; + +/* Timers */ +typedef enum vrrp_vr_timer_type +{ + VRRP_VR_TIMER_ADV, + VRRP_VR_TIMER_MASTER_DOWN, +} vrrp_vr_timer_type_t; + +typedef struct vrrp_vr_timer +{ + u32 vr_index; + f64 expire_time; /* monotonic, relative to vlib_time_now() */ + vrrp_vr_timer_type_t type; +} vrrp_vr_timer_t; + +typedef struct +{ + /* vectors of vr indices which are configured on this interface + * 0 -> ipv4, 1 -> ipv6 */ + u32 *vr_indices[2]; + + /* vector of VR indices which track the state of this interface + * 0 -> ipv4, 1*/ + u32 *tracking_vrs[2]; + + /* multicast adjacency indices. 0 -> ipv4, 1 -> ipv6 */ + adj_index_t mcast_adj_index[2]; + + /* number of VRs in master state on sw intf. 0 -> ipv4, 1 -> ipv6 */ + u8 n_master_vrs[2]; + +} vrrp_intf_t; + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + + /* pool of VRs */ + vrrp_vr_t *vrs; + + /* pool of timers and ordered vector of pool indices */ + vrrp_vr_timer_t *vr_timers; + u32 *pending_timers; + + /* number of running VRs - don't register for VRRP proto if not running */ + u16 n_vrs_started; + + /* hash mapping a VR key to a pool entry */ + mhash_t vr_index_by_key; + + /* hashes mapping sw_if_index and address to a vr index */ + uword *vrrp4_arp_lookup; + uword *vrrp6_nd_lookup; + + /* vector of interface data indexed by sw_if_index */ + vrrp_intf_t *vrrp_intfs; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; + ethernet_main_t *ethernet_main; + + u32 intf_output_node_idx; +} vrrp_main_t; + +extern vrrp_main_t vrrp_main; + +extern vlib_node_registration_t vrrp_node; +extern vlib_node_registration_t vrrp_periodic_node; + +/* Periodic function events */ +#define VRRP_EVENT_VR_TIMER_UPDATE 1 +#define VRRP_EVENT_VR_STOP 2 +#define VRRP_EVENT_PERIODIC_ENABLE_DISABLE 3 + +clib_error_t *vrrp_plugin_api_hookup (vlib_main_t * vm); + +int vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * conf); +int vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key); +extern u8 *format_vrrp_vr (u8 * s, va_list * args); +extern u8 *format_vrrp_vr_key (u8 * s, va_list * args); +extern u8 *format_vrrp_vr_state (u8 * s, va_list * args); +extern u8 *format_vrrp_packet_hdr (u8 * s, va_list * args); +void vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type); +void vrrp_vr_timer_cancel (vrrp_vr_t * vr); +void vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, + void *data); +int vrrp_vr_set_peers (vrrp_vr_key_t * key, ip46_address_t * peers); +int vrrp_vr_multicast_group_join (vrrp_vr_t * vr); +int vrrp_adv_send (vrrp_vr_t * vr, int shutdown); +int vrrp_garp_or_na_send (vrrp_vr_t * vr); +u16 vrrp_adv_csum (void *l3_hdr, void *payload, u8 is_ipv6, u16 len); +int vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index, + u8 priority, u8 is_add); +int vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr, + vrrp_vr_tracking_if_t * track_ifs, + u8 is_add); + + +always_inline void +vrrp_vr_skew_compute (vrrp_vr_t * vr) +{ + vrrp_vr_config_t *vrc = &vr->config; + vrrp_vr_runtime_t *vrt = &vr->runtime; + + vrt->skew = (((256 - vrc->priority) * vrt->master_adv_int) / 256); +} + +always_inline void +vrrp_vr_master_down_compute (vrrp_vr_t * vr) +{ + vrrp_vr_runtime_t *vrt = &vr->runtime; + + vrt->master_down_int = (3 * vrt->master_adv_int) + vrt->skew; +} + +always_inline vrrp_vr_t * +vrrp_vr_lookup (u32 sw_if_index, u8 vr_id, u8 is_ipv6) +{ + vrrp_main_t *vmp = &vrrp_main; + vrrp_vr_key_t key = { + .sw_if_index = sw_if_index, + .vr_id = vr_id, + .is_ipv6 = (is_ipv6 != 0), + }; + uword *p; + + p = mhash_get (&vmp->vr_index_by_key, &key); + if (p) + return pool_elt_at_index (vmp->vrs, p[0]); + + return 0; +} + +always_inline vrrp_vr_t * +vrrp_vr_lookup_index (u32 vr_index) +{ + vrrp_main_t *vmp = &vrrp_main; + + if (pool_is_free_index (vmp->vrs, vr_index)) + return 0; + + return pool_elt_at_index (vmp->vrs, vr_index); +} + +always_inline u32 +vrrp_vr_lookup_address (u32 sw_if_index, u8 is_ipv6, void *addr) +{ + vrrp_main_t *vmp = &vrrp_main; + uword *p; + vrrp4_arp_key_t key4; + vrrp6_nd_key_t key6; + + if (is_ipv6) + { + key6.sw_if_index = sw_if_index; + key6.addr = ((ip6_address_t *) addr)[0]; + p = hash_get_mem (vmp->vrrp6_nd_lookup, &key6); + } + else + { + key4.sw_if_index = sw_if_index; + key4.addr = ((ip4_address_t *) addr)[0]; + p = hash_get (vmp->vrrp4_arp_lookup, key4.as_u64); + } + + if (p) + return p[0]; + + return ~0; +} + +always_inline vrrp_intf_t * +vrrp_intf_get (u32 sw_if_index) +{ + vrrp_main_t *vrm = &vrrp_main; + + if (sw_if_index == ~0) + return NULL; + + vec_validate (vrm->vrrp_intfs, sw_if_index); + return vec_elt_at_index (vrm->vrrp_intfs, sw_if_index); +} + +always_inline int +vrrp_intf_num_vrs (u32 sw_if_index, u8 is_ipv6) +{ + vrrp_intf_t *intf = vrrp_intf_get (sw_if_index); + + if (intf) + return vec_len (intf->vr_indices[is_ipv6]); + + return 0; +} + +always_inline u8 +vrrp_vr_is_ipv6 (vrrp_vr_t * vr) +{ + return ((vr->config.flags & VRRP_VR_IPV6) != 0); +} + +always_inline u8 +vrrp_vr_is_unicast (vrrp_vr_t * vr) +{ + return ((vr->config.flags & VRRP_VR_UNICAST) != 0); +} + +always_inline u8 +vrrp_vr_is_owner (vrrp_vr_t * vr) +{ + return (vr->config.priority == 255); +} + +always_inline u8 +vrrp_vr_n_vr_addrs (vrrp_vr_t * vr) +{ + return vec_len (vr->config.vr_addrs); +} + +always_inline u8 +vrrp_vr_n_peer_addrs (vrrp_vr_t * vr) +{ + return vec_len (vr->config.peer_addrs); +} + +always_inline u8 +vrrp_vr_accept_mode_enabled (vrrp_vr_t * vr) +{ + return ((vr->config.flags & VRRP_VR_ACCEPT) != 0); +} + +always_inline u32 +vrrp_vr_index (vrrp_vr_t * vr) +{ + vrrp_main_t *vmp = &vrrp_main; + + return vr - vmp->vrs; +} + +always_inline u8 +vrrp_vr_priority (vrrp_vr_t * vr) +{ + u8 rv; + + if (vr->tracking.interfaces_dec < (u32) vr->config.priority) + rv = vr->config.priority - vr->tracking.interfaces_dec; + else + rv = 1; + + return rv; +} + +#endif /* __included_vrrp_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg