/*
* Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338.
* VRRP is a protocol which elect a master server on a LAN. If the
* master fails, a backup server takes over.
* The original implementation has been made by jerome etienne.
*
* Part: vrrp.c program include file.
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Copyright (C) 2001-2017 Alexandre Cassen, <acassen@gmail.com>
*/
#ifndef _VRRP_H
#define _VRRP_H
#include "config.h"
/* system include */
#include <stdint.h>
#include <stdbool.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
/* local include */
#include "vector.h"
#include "list.h"
#include "timer.h"
#include "notify.h"
#if defined _WITH_VRRP_AUTH_
#include "vrrp_ipsecah.h"
#endif
#include "vrrp_if.h"
#include "vrrp_sock.h"
#include "vrrp_track.h"
/* Special value for parameters when we want to know they haven't been set */
#define PARAMETER_UNSET UINT_MAX
typedef struct _vrrphdr { /* rfc2338.5.1 */
uint8_t vers_type; /* 0-3=type, 4-7=version */
uint8_t vrid; /* virtual router id */
uint8_t priority; /* router priority */
uint8_t naddr; /* address counter */
union {
struct {
uint8_t auth_type; /* authentification type */
uint8_t adver_int; /* advertisement interval (in sec) */
} v2;
struct {
uint16_t adver_int; /* advertisement interval (in centi-sec (100ms)) */
} v3;
};
uint16_t chksum; /* checksum (ip-like one) */
/* here <naddr> ip addresses */
/* here authentification infos */
} vrrphdr_t;
typedef struct {
uint32_t src;
uint32_t dst;
uint8_t zero;
uint8_t proto;
uint16_t len;
} ipv4_phdr_t;
/* protocol constants */
#define INADDR_VRRP_GROUP "224.0.0.18" /* multicast IPv4 addr - rfc2338.5.2.2 */
#define INADDR6_VRRP_GROUP "ff02::12" /* multicast IPv6 addr - rfc5798.5.1.2.2 */
#define VRRP_IP_TTL 255 /* in and out pkt ttl -- rfc2338.5.2.3 */
#define IPPROTO_VRRP 112 /* IP protocol number -- rfc2338.5.2.4 */
#define VRRP_VERSION_2 2 /* VRRP version 2 -- rfc2338.5.3.1 */
#define VRRP_VERSION_3 3 /* VRRP version 3 -- rfc5798.5.2.1 */
#define VRRP_PKT_ADVERT 1 /* packet type -- rfc2338.5.3.2 */
#define VRRP_PRIO_OWNER 255 /* priority of the ip owner -- rfc2338.5.3.4 */
#define VRRP_PRIO_DFL 100 /* default priority -- rfc2338.5.3.4 */
#define VRRP_PRIO_STOP 0 /* priority to stop -- rfc2338.5.3.4 */
#define VRRP_MAX_ADDR 0xFF /* count addr field is 8 bits wide */
#define VRRP_AUTH_NONE 0 /* no authentification -- rfc2338.5.3.6 */
#ifdef _WITH_VRRP_AUTH_
#define VRRP_AUTH_PASS 1 /* password authentification -- rfc2338.5.3.6 */
#define VRRP_AUTH_AH 2 /* AH(IPSec) authentification - rfc2338.5.3.6 */
#endif
#define VRRP_ADVER_DFL 1 /* advert. interval (in sec) -- rfc2338.5.3.7 */
#define VRRP_GARP_DELAY (5 * TIMER_HZ) /* Default delay to launch gratuitous arp */
#define VRRP_GARP_REP 5 /* Default repeat value for MASTER state gratuitous arp */
#define VRRP_GARP_REFRESH 0 /* Default interval for refresh gratuitous arp (0 = none) */
#define VRRP_GARP_REFRESH_REP 1 /* Default repeat value for refresh gratuitous arp */
/*
* parameters per vrrp sync group. A vrrp_sync_group is a set
* of VRRP instances that need to be state sync together.
*/
typedef struct _vrrp_sgroup {
char *gname; /* Group name */
vector_t *iname; /* Set of VRRP instances in this group, only used during initialisation */
list vrrp_instances; /* List of VRRP instances */
unsigned num_member_fault; /* Number of members of group in fault state */
unsigned num_member_init; /* Number of members of group in pending state */
int state; /* current stable state */
bool sgroup_tracking_weight; /* Use floating priority and scripts
* Used if need different priorities needed on a track object in a sync group.
* It probably won't work properly. */
list track_ifp; /* Interface state we monitor */
list track_script; /* Script state we monitor */
list track_file; /* Files whose value we monitor (list of tracked_file_t) */
#ifdef _WITH_BFD_
list track_bfd; /* List of tracked_bfd_t */
#endif
/* State transition notification */
bool notify_exec;
notify_script_t *script_backup;
notify_script_t *script_master;
notify_script_t *script_fault;
notify_script_t *script_stop;
notify_script_t *script;
int smtp_alert;
int last_email_state;
} vrrp_sgroup_t;
/* Statistics */
typedef struct _vrrp_stats {
uint64_t advert_rcvd;
uint32_t advert_sent;
uint32_t become_master;
uint32_t release_master;
uint64_t packet_len_err;
uint64_t advert_interval_err;
uint64_t ip_ttl_err;
uint64_t invalid_type_rcvd;
uint64_t addr_list_err;
uint32_t invalid_authtype;
#ifdef _WITH_VRRP_AUTH_
uint32_t authtype_mismatch;
uint32_t auth_failure;
#endif
uint64_t pri_zero_rcvd;
uint64_t pri_zero_sent;
#ifdef _WITH_SNMP_RFC_
uint32_t chk_err;
uint32_t vers_err;
uint32_t vrid_err;
timeval_t uptime;
#ifdef _WITH_SNMP_RFCV3_
uint32_t master_reason;
uint32_t next_master_reason;
uint32_t proto_err_reason;
#endif
#endif
} vrrp_stats;
#ifdef _WITH_UNICAST_CHKSUM_COMPAT_
/* Whether we are using v1.3.6 and earlier VRRPv3 unicast checksums */
typedef enum chksum_compatibility {
CHKSUM_COMPATIBILITY_NONE, /* Default setting, will revert to old if receive advert with old */
CHKSUM_COMPATIBILITY_NEVER, /* Do not auto set old checksum mode */
CHKSUM_COMPATIBILITY_MIN_COMPAT, /* Values before this are new chksum, values after are old */
CHKSUM_COMPATIBILITY_CONFIG, /* Configuration specifies old chksum */
CHKSUM_COMPATIBILITY_AUTO, /* Use old chksum mode due to received advert with old mode */
} chksum_compatibility_t;
#endif
/* parameters per virtual router -- rfc2338.6.1.2 */
typedef struct _vrrp_t {
sa_family_t family; /* AF_INET|AF_INET6 */
char *iname; /* Instance Name */
vrrp_sgroup_t *sync; /* Sync group we belong to */
vrrp_stats *stats; /* Statistics */
interface_t *ifp; /* Interface we belong to */
bool dont_track_primary; /* If set ignores ifp faults */
bool linkbeat_use_polling; /* Don't use netlink for interface status */
bool skip_check_adv_addr; /* If set, don't check the VIPs in subsequent
* adverts from the same master */
unsigned strict_mode; /* Enforces strict VRRP compliance */
#ifdef _HAVE_VRRP_VMAC_
unsigned long vmac_flags; /* VRRP VMAC flags */
char vmac_ifname[IFNAMSIZ]; /* Name of VRRP VMAC interface */
bool duplicate_vrid_fault; /* Set if we have a fault due to duplicate VRID */
#endif
interface_t *configured_ifp; /* Interface the configuration says we are on */
list track_ifp; /* Interface state we monitor */
list track_script; /* Script state we monitor */
list track_file; /* list of tracked_file_t - Files whose value we monitor */
#ifdef _WITH_BFD_
list track_bfd; /* List of tracked_bfd_t */
#endif
unsigned num_script_if_fault; /* Number of scripts and interfaces in fault state */
unsigned num_script_init; /* Number of scripts in init state */
struct sockaddr_storage saddr; /* Src IP address to use in VRRP IP header */
bool saddr_from_config; /* Set if the source address is from configuration */
bool track_saddr; /* Fault state if configured saddr is missing */
struct sockaddr_storage pkt_saddr; /* Src IP address received in VRRP IP header */
list unicast_peer; /* List of Unicast peer to send advert to */
#ifdef _WITH_UNICAST_CHKSUM_COMPAT_
chksum_compatibility_t unicast_chksum_compat; /* Whether v1.3.6 and earlier chksum is used */
#endif
struct sockaddr_storage master_saddr; /* Store last heard Master address */
uint8_t master_priority; /* Store last heard priority */
timeval_t last_transition; /* Store transition time */
unsigned garp_delay; /* Delay to launch gratuitous ARP */
timeval_t garp_refresh; /* Next scheduled gratuitous ARP refresh */
timeval_t garp_refresh_timer; /* Next scheduled gratuitous ARP timer */
unsigned garp_rep; /* gratuitous ARP repeat value */
unsigned garp_refresh_rep; /* refresh gratuitous ARP repeat value */
unsigned garp_lower_prio_delay; /* Delay to second set or ARP messages */
bool garp_pending; /* Are there gratuitous ARP messages still to be sent */
bool gna_pending; /* Are there gratuitous NA messages still to be sent */
unsigned garp_lower_prio_rep; /* Number of ARP messages to send at a time */
unsigned lower_prio_no_advert; /* Don't send advert after lower prio advert received */
unsigned higher_prio_send_advert; /* Send advert after higher prio advert received */
uint8_t vrid; /* virtual id. from 1(!) to 255 */
uint8_t base_priority; /* configured priority value */
uint8_t effective_priority; /* effective priority value */
int total_priority; /* base_priority +/- track_script, track_interface and track_file weights.
effective_priority is this within the range [1,254]. */
bool vipset; /* All the vips are set ? */
list vip; /* list of virtual ip addresses */
list evip; /* list of protocol excluded VIPs.
* Those VIPs will not be presents into the
* VRRP adverts
*/
bool promote_secondaries; /* Set promote_secondaries option on interface */
bool evip_add_ipv6; /* Enable IPv6 for eVIPs if this is an IPv4 instance */
list vroutes; /* list of virtual routes */
list vrules; /* list of virtual rules */
unsigned adver_int; /* locally configured delay between advertisements*/
unsigned master_adver_int; /* In v3, when we become BACKUP, we use the MASTER's
* adver_int. If we become MASTER again, we use the
* value we were originally configured with.
* In v2, this will always be the configured adver_int.
*/
unsigned accept; /* Allow the non-master owner to process
* the packets destined to VIP.
*/
size_t kernel_rx_buf_size; /* Socket receive buffer size */
bool iptable_rules_set; /* Iptable drop rules set to VIP list ? */
bool nopreempt; /* true if higher prio does not preempt lower */
unsigned long preempt_delay; /* Seconds*TIMER_HZ after startup until
* preemption based on higher prio over lower
* prio is allowed. 0 means no delay.
*/
timeval_t preempt_time; /* Time after which preemption can happen */
int state; /* internal state (init/backup/master/fault) */
#ifdef _WITH_SNMP_VRRP_
int configured_state; /* the configured state of the instance */
#endif
int wantstate; /* user explicitly wants a state (back/mast) */
bool reload_master; /* set if the instance is a master being reloaded */
sock_t *sockets; /* In and out socket descriptors */
int debug; /* Debug level 0-4 */
int version; /* VRRP version (2 or 3) */
/* State transition notification */
int smtp_alert;
int last_email_state;
bool notify_exec;
notify_script_t *script_backup;
notify_script_t *script_master;
notify_script_t *script_fault;
notify_script_t *script_stop;
notify_script_t *script_master_rx_lower_pri;
notify_script_t *script;
/* rfc2338.6.2 */
uint32_t ms_down_timer;
timeval_t sands;
/* Sending buffer */
char *send_buffer; /* Allocated send buffer */
size_t send_buffer_size;
uint32_t ipv4_csum; /* Checksum ip IPv4 pseudo header for VRRPv3 */
#if defined _WITH_VRRP_AUTH_
/* Authentication data (only valid for VRRPv2) */
uint8_t auth_type; /* authentification type. VRRP_AUTH_* */
uint8_t auth_data[8]; /* authentification data */
/* IPSEC AH counter def (only valid for VRRPv2) --rfc2402.3.3.2 */
seq_counter_t ipsecah_counter;
#endif
/*
* To have my own ip_id creates collision with kernel ip->id
* but it should be ok because the packets are unlikely to be
* fragmented (they are non routable and small)
* This packet isnt routed, i can check the outgoing MTU
* to warn the user only if the outoing mtu is too small
*/
int ip_id;
/* RB tree on a sock_t for receiving data */
rb_node_t rb_vrid;
/* RB tree on a sock_t for vrrp sands */
rb_node_t rb_sands;
} vrrp_t;
/* VRRP state machine -- rfc2338.6.4 */
#define VRRP_STATE_INIT 0 /* rfc2338.6.4.1 */
#define VRRP_STATE_BACK 1 /* rfc2338.6.4.2 */
#define VRRP_STATE_MAST 2 /* rfc2338.6.4.3 */
#define VRRP_STATE_FAULT 3 /* internal */
#define VRRP_STATE_STOP 98 /* internal */
#define VRRP_DISPATCHER 99 /* internal */
#define VRRP_EVENT_MASTER_RX_LOWER_PRI 1000 /* Dummy state for sending event notify */
/* VRRP packet handling */
#define VRRP_PACKET_OK 0
#define VRRP_PACKET_KO 1
#define VRRP_PACKET_DROP 2
#define VRRP_PACKET_NULL 3
#define VRRP_PACKET_OTHER 4 /* Multiple VRRP on LAN, Identify "other" VRRP */
/* VRRP Packet fixed length */
#define VRRP_AUTH_LEN 8
#define VRRP_VIP_TYPE (1 << 0)
#define VRRP_EVIP_TYPE (1 << 1)
/* We have to do some reduction of the calculation for VRRPv3 in order not to overflow a uint32; 625 / 16 == TIMER_CENTI_HZ / 256 */
#define VRRP_TIMER_SKEW(svr) ((svr)->version == VRRP_VERSION_3 ? (((256U-(svr)->effective_priority) * ((svr)->master_adver_int / TIMER_CENTI_HZ) * 625U) / 16U) : ((256U-(svr)->effective_priority) * TIMER_HZ/256U))
#define VRRP_TIMER_SKEW_MIN(svr) ((svr)->version == VRRP_VERSION_3 ? ((((svr)->master_adver_int / TIMER_CENTI_HZ) * 625U) / 16U) : (TIMER_HZ/256U))
#define VRRP_VIP_ISSET(V) ((V)->vipset)
#define VRRP_MIN(a, b) ((a) < (b)?(a):(b))
#define VRRP_MAX(a, b) ((a) > (b)?(a):(b))
#ifdef _HAVE_VRRP_VMAC_
#define VRRP_CONFIGURED_IFP(V) ((V)->configured_ifp)
#else
#define VRRP_CONFIGURED_IFP(V) ((V)->ifp)
#endif
#define VRRP_PKT_SADDR(V) (((V)->saddr.ss_family) ? ((struct sockaddr_in *) &(V)->saddr)->sin_addr.s_addr : IF_ADDR(VRRP_CONFIGURED_IFP(V)))
#define VRRP_ISUP(V) (!(V)->num_script_if_fault)
/* Global variables */
extern bool block_ipv4;
extern bool block_ipv6;
/* Configuration summary flags */
extern bool have_ipv4_instance;
extern bool have_ipv6_instance;
/* prototypes */
extern void clear_summary_flags(void);
extern size_t vrrp_adv_len(vrrp_t *);
extern vrrphdr_t *vrrp_get_header(sa_family_t, char *, unsigned *);
extern int open_vrrp_send_socket(sa_family_t, int, interface_t *, bool);
extern int open_vrrp_read_socket(sa_family_t, int, interface_t *, bool, int);
extern int new_vrrp_socket(vrrp_t *);
extern void vrrp_send_adv(vrrp_t *, uint8_t);
extern void vrrp_send_link_update(vrrp_t *, unsigned);
extern void add_vrrp_to_interface(vrrp_t *, interface_t *, int, bool, track_t);
extern void del_vrrp_from_interface(vrrp_t *, interface_t *);
extern bool vrrp_state_fault_rx(vrrp_t *, char *, ssize_t);
extern bool vrrp_state_master_rx(vrrp_t *, char *, ssize_t);
extern void vrrp_state_master_tx(vrrp_t *);
extern void vrrp_state_backup(vrrp_t *, char *, ssize_t);
extern void vrrp_state_goto_master(vrrp_t *);
extern void vrrp_state_leave_master(vrrp_t *, bool);
extern void vrrp_state_leave_fault(vrrp_t *);
extern bool vrrp_complete_init(void);
extern void vrrp_restore_interfaces_startup(void);
extern void restore_vrrp_interfaces(void);
extern void shutdown_vrrp_instances(void);
extern void clear_diff_vrrp(void);
extern void clear_diff_script(void);
extern void clear_diff_bfd(void);
extern void vrrp_restore_interface(vrrp_t *, bool, bool);
#ifdef THREAD_DUMP
extern void register_vrrp_fifo_addresses(void);
#endif
#endif