Blob Blame History Raw
/*
 * Soft:        Keepalived is a failover program for the LVS project
 *              <www.linuxvirtualserver.org>. It monitor & manipulate
 *              a loadbalanced server pool using multi-layer checks.
 *
 * Part:        Dynamic data structure definition.
 *
 * 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>
 */

#include "config.h"

#include <unistd.h>
#include <time.h>

#include "utils.h"
#include "logger.h"
#include "bitops.h"
#include "rttables.h"

#include "global_data.h"
#include "vrrp_data.h"
#include "vrrp_sync.h"
#ifdef _HAVE_VRRP_VMAC_
#include "vrrp_vmac.h"
#endif
#include "vrrp_ipaddress.h"
#ifdef _HAVE_FIB_ROUTING_
#include "vrrp_iprule.h"
#include "vrrp_iproute.h"
#endif
#include "vrrp_track.h"
#include "vrrp_sock.h"
#ifdef _WITH_SNMP_RFCV3_
#include "vrrp_snmp.h"
#endif
#include "vrrp_static_track.h"
#include "parser.h"

/* global vars */
vrrp_data_t *vrrp_data = NULL;
vrrp_data_t *old_vrrp_data = NULL;
char *vrrp_buffer;
size_t vrrp_buffer_len;

static char *
get_state_str(int state)
{
	if (state == VRRP_STATE_INIT) return "INIT";
	if (state == VRRP_STATE_BACK) return "BACKUP";
	if (state == VRRP_STATE_MAST) return "MASTER";
	if (state == VRRP_STATE_FAULT) return "FAULT";
	if (state == VRRP_DISPATCHER) return "DISPATCHER";
	return "unknown";
}

/* Static addresses facility function */
void
alloc_saddress(vector_t *strvec)
{
	if (!LIST_EXISTS(vrrp_data->static_addresses))
		vrrp_data->static_addresses = alloc_list(free_ipaddress, dump_ipaddress);
	alloc_ipaddress(vrrp_data->static_addresses, strvec, NULL, true);
}

#ifdef _HAVE_FIB_ROUTING_
/* Static routes facility function */
void
alloc_sroute(vector_t *strvec)
{
	if (!LIST_EXISTS(vrrp_data->static_routes))
		vrrp_data->static_routes = alloc_list(free_iproute, dump_iproute);
	alloc_route(vrrp_data->static_routes, strvec, true);
}

/* Static rules facility function */
void
alloc_srule(vector_t *strvec)
{
	if (!LIST_EXISTS(vrrp_data->static_rules))
		vrrp_data->static_rules = alloc_list(free_iprule, dump_iprule);
	alloc_rule(vrrp_data->static_rules, strvec, true);
}
#endif

/* VRRP facility functions */
static void
free_vgroup(void *data)
{
	vrrp_sgroup_t *vgroup = data;

	if (vgroup->iname) {
		log_message(LOG_INFO, "sync group %s - iname vector exists when freeing group", vgroup->gname);
		free_strvec(vgroup->iname);
	}
	FREE(vgroup->gname);
	free_list(&vgroup->vrrp_instances);
	free_list(&vgroup->track_ifp);
	free_list(&vgroup->track_script);
	free_list(&vgroup->track_file);
#ifdef _WITH_BFD_
	free_list(&vgroup->track_bfd);
#endif
	free_notify_script(&vgroup->script_backup);
	free_notify_script(&vgroup->script_master);
	free_notify_script(&vgroup->script_fault);
	free_notify_script(&vgroup->script_stop);
	free_notify_script(&vgroup->script);
	FREE(vgroup);
}

static void
dump_notify_script(FILE *fp, notify_script_t *script, char *type)
{
	if (!script)
		return;

	conf_write(fp, "   %s state transition script = %s, uid:gid %d:%d", type,
	       cmd_str(script), script->uid, script->gid);
}

static void
dump_vgroup(FILE *fp, void *data)
{
	vrrp_sgroup_t *vgroup = data;
	element e;

	conf_write(fp, " VRRP Sync Group = %s, %s", vgroup->gname, get_state_str(vgroup->state));
	if (vgroup->vrrp_instances) {
		conf_write(fp, "   VRRP member instances = %d", LIST_SIZE(vgroup->vrrp_instances));
		for (e = LIST_HEAD(vgroup->vrrp_instances); e; ELEMENT_NEXT(e)) {
			vrrp_t *vrrp = ELEMENT_DATA(e);
			conf_write(fp, "     %s", vrrp->iname);
		}
	}
	if (vgroup->sgroup_tracking_weight)
		conf_write(fp, "   sync group tracking weight set");
	conf_write(fp, "   Using smtp notification = %s", vgroup->smtp_alert ? "yes" : "no");
	if (!LIST_ISEMPTY(vgroup->track_ifp)) {
		conf_write(fp, "   Tracked interfaces = %d", LIST_SIZE(vgroup->track_ifp));
		dump_list(fp, vgroup->track_ifp);
	}
	if (!LIST_ISEMPTY(vgroup->track_script)) {
		conf_write(fp, "   Tracked scripts = %d", LIST_SIZE(vgroup->track_script));
		dump_list(fp, vgroup->track_script);
	}
	if (!LIST_ISEMPTY(vgroup->track_file)) {
		conf_write(fp, "   Tracked files = %d", LIST_SIZE(vgroup->track_file));
		dump_list(fp, vgroup->track_file);
	}
#ifdef _WITH_BFD_
	if (!LIST_ISEMPTY(vgroup->track_bfd)) {
		conf_write(fp, "   Tracked BFDs = %d", LIST_SIZE(vgroup->track_bfd));
		dump_list(fp, vgroup->track_bfd);
	}
#endif
	dump_notify_script(fp, vgroup->script_backup, "Backup");
	dump_notify_script(fp, vgroup->script_master, "Master");
	dump_notify_script(fp, vgroup->script_fault, "Fault");
	dump_notify_script(fp, vgroup->script_stop, "Stop");
	dump_notify_script(fp, vgroup->script, "Generic");
}

void
dump_tracking_vrrp(FILE *fp, void *data)
{
	tracking_vrrp_t *tvp = (tracking_vrrp_t *)data;
	vrrp_t *vrrp = tvp->vrrp;

	conf_write(fp, "     %s, weight %d%s", vrrp->iname, tvp->weight, tvp->type == TRACK_VRRP_DYNAMIC ? " (dynamic)" : "");
}

static void
free_vscript(void *data)
{
	vrrp_script_t *vscript = data;

	free_list(&vscript->tracking_vrrp);
	FREE(vscript->sname);
	FREE_PTR(vscript->script.args);
	FREE(vscript);
}
static void
dump_vscript(FILE *fp, void *data)
{
	vrrp_script_t *vscript = data;
	const char *str;

	conf_write(fp, " VRRP Script = %s", vscript->sname);
	conf_write(fp, "   Command = %s", cmd_str(&vscript->script));
	conf_write(fp, "   Interval = %lu sec", vscript->interval / TIMER_HZ);
	conf_write(fp, "   Timeout = %lu sec", vscript->timeout / TIMER_HZ);
	conf_write(fp, "   Weight = %d", vscript->weight);
	conf_write(fp, "   Rise = %d", vscript->rise);
	conf_write(fp, "   Fall = %d", vscript->fall);
	conf_write(fp, "   Insecure = %s", vscript->insecure ? "yes" : "no");

	switch (vscript->init_state) {
	case SCRIPT_INIT_STATE_INIT:
		str = "INIT"; break;
	case SCRIPT_INIT_STATE_FAILED:
		str = "INIT/FAILED"; break;
	default:
		str = (vscript->result >= vscript->rise) ? "GOOD" : "BAD";
	}
	conf_write(fp, "   Status = %s", str);
	conf_write(fp, "   Script uid:gid = %d:%d", vscript->script.uid, vscript->script.gid);
	conf_write(fp, "   VRRP instances = %d", vscript->tracking_vrrp ? LIST_SIZE(vscript->tracking_vrrp) : 0);
	if (vscript->tracking_vrrp)
		dump_list(fp, vscript->tracking_vrrp);
	conf_write(fp, "   State = %s",
			vscript->state == SCRIPT_STATE_IDLE ? "idle" :
			vscript->state == SCRIPT_STATE_RUNNING ? "running" :
			vscript->state == SCRIPT_STATE_REQUESTING_TERMINATION ? "requested termination" :
			vscript->state == SCRIPT_STATE_FORCING_TERMINATION ? "forcing termination" : "unknown");
}

static void
free_vfile(void *data)
{
	vrrp_tracked_file_t *vfile = data;

	free_list(&vfile->tracking_vrrp);
	FREE(vfile->fname);
	FREE(vfile->file_path);
	FREE(vfile);
}
static void
dump_vfile(FILE *fp, void *data)
{
	vrrp_tracked_file_t *vfile = data;

	conf_write(fp, " VRRP Track file = %s", vfile->fname);
	conf_write(fp, "   File = %s", vfile->file_path);
	conf_write(fp, "   Status = %d", vfile->last_status);
	conf_write(fp, "   Weight = %d", vfile->weight);
	conf_write(fp, "   Tracking VRRP instances = %d", vfile->tracking_vrrp ? LIST_SIZE(vfile->tracking_vrrp) : 0);
	if (vfile->tracking_vrrp)
		dump_list(fp, vfile->tracking_vrrp);
}

#ifdef _WITH_BFD_
/* Track bfd dump */
static void
dump_vrrp_bfd(FILE *fp, void *track_data)
{
	vrrp_tracked_bfd_t *vbfd = track_data;

	conf_write(fp, " VRRP Track BFD = %s", vbfd->bname);
	conf_write(fp, "   Weight = %d", vbfd->weight);
	conf_write(fp, "   Tracking VRRP instances = %d", vbfd->tracking_vrrp ? LIST_SIZE(vbfd->tracking_vrrp) : 0);
	if (vbfd->tracking_vrrp)
		dump_list(fp, vbfd->tracking_vrrp);
}

static void
free_vrrp_bfd(void *track_data)
{
	vrrp_tracked_bfd_t *vbfd = track_data;

	free_list(&vbfd->tracking_vrrp);
	FREE(track_data);
}
#endif

/* Socket pool functions */
static void
free_sock(void *sock_data)
{
	sock_t *sock = sock_data;

	/* First of all cancel pending thread */
	thread_cancel(sock->thread);

	/* Close related socket */
	if (sock->fd_in > 0)
		close(sock->fd_in);
	if (sock->fd_out > 0)
		close(sock->fd_out);
	FREE(sock_data);
}

static void
dump_sock(FILE *fp, void *sock_data)
{
	sock_t *sock = sock_data;

	conf_write(fp, "VRRP sockpool: [ifindex(%u), family(%s), proto(%u), unicast(%d), fd(%d,%d)]"
			    , sock->ifp->ifindex
			    , sock->family == AF_INET ? "IPv4" : sock->family == AF_INET6 ? "IPv6" : "unknown"
			    , sock->proto
			    , sock->unicast
			    , sock->fd_in
			    , sock->fd_out);
}

static void
free_unicast_peer(void *data)
{
	FREE(data);
}

static void
dump_unicast_peer(FILE *fp, void *data)
{
	struct sockaddr_storage *peer = data;

	conf_write(fp, "     %s", inet_sockaddrtos(peer));
}

static void
free_vrrp(void *data)
{
	vrrp_t *vrrp = data;

	FREE(vrrp->iname);
	FREE_PTR(vrrp->send_buffer);
	free_notify_script(&vrrp->script_backup);
	free_notify_script(&vrrp->script_master);
	free_notify_script(&vrrp->script_fault);
	free_notify_script(&vrrp->script_stop);
	free_notify_script(&vrrp->script);
	free_notify_script(&vrrp->script_master_rx_lower_pri);
	FREE_PTR(vrrp->stats);

	free_list(&vrrp->track_ifp);
	free_list(&vrrp->track_script);
	free_list(&vrrp->track_file);
#ifdef _WITH_BFD_
	free_list(&vrrp->track_bfd);
#endif
	free_list(&vrrp->unicast_peer);
	free_list(&vrrp->vip);
	free_list(&vrrp->evip);
	free_list(&vrrp->vroutes);
	free_list(&vrrp->vrules);
	FREE(vrrp);
}
static void
dump_vrrp(FILE *fp, void *data)
{
	vrrp_t *vrrp = data;
#ifdef _WITH_VRRP_AUTH_
	char auth_data[sizeof(vrrp->auth_data) + 1];
#endif
	char time_str[26];

	/* If fp is NULL, we are writing configuration to syslog at
	 * startup, so there is no point writing transient state information.
	 */

	conf_write(fp, " VRRP Instance = %s", vrrp->iname);
	conf_write(fp, "   VRRP Version = %d", vrrp->version);
	if (vrrp->sync)
		conf_write(fp, "   Sync group = %s", vrrp->sync->gname);
	if (vrrp->family == AF_INET6)
		conf_write(fp, "   Using Native IPv6");
	if (fp) {
		conf_write(fp, "   State = %s", get_state_str(vrrp->state));
		if (vrrp->state == VRRP_STATE_BACK) {
			conf_write(fp, "   Master router = %s", inet_sockaddrtos(&vrrp->master_saddr));
			conf_write(fp, "   Master priority = %d", vrrp->master_priority);
			if (vrrp->version == VRRP_VERSION_3)
				conf_write(fp, "   Master advert int = %.2f sec", (float)vrrp->master_adver_int / TIMER_HZ);
		}
	}
	conf_write(fp, "   Wantstate = %s", get_state_str(vrrp->wantstate));
	if (fp) {
		conf_write(fp, "   Number of interface and track script faults = %u", vrrp->num_script_if_fault);
#ifdef _HAVE_VRRP_VMAC_
		if (vrrp->duplicate_vrid_fault)
			conf_write(fp, "   Duplicate VRID");
#endif
		conf_write(fp, "   Number of track scripts init = %d", vrrp->num_script_init);
		ctime_r(&vrrp->last_transition.tv_sec, time_str);
		conf_write(fp, "   Last transition = %ld (%.24s)", vrrp->last_transition.tv_sec, time_str);
		if (!ctime_r(&vrrp->sands.tv_sec, time_str))
			strcpy(time_str, "invalid time ");
		if (vrrp->sands.tv_sec == TIMER_DISABLED)
			conf_write(fp, "   Read timeout = DISABLED");
		else
			conf_write(fp, "   Read timeout = %ld.%6.6ld (%.19s.%6.6ld)", vrrp->sands.tv_sec, vrrp->sands.tv_usec, time_str, vrrp->sands.tv_usec);
		conf_write(fp, "   Master down timer = %u usecs", vrrp->ms_down_timer);
	}
#ifdef _HAVE_VRRP_VMAC_
	if (__test_bit(VRRP_VMAC_BIT, &vrrp->vmac_flags))
		conf_write(fp, "   Use VMAC, is_up = %s,  xmit_base = %s",
				__test_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags) ? "true" : "false",
				__test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->vmac_flags) ? "true" : "false");
	if (vrrp->ifp->is_ours) {
		conf_write(fp, "   Interface = %s, vmac on %s, xmit %s i/f", IF_NAME(vrrp->ifp),
				vrrp->ifp->base_ifp->ifname, __test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->vmac_flags) ? "base" : "vmac");
	} else
#endif
		conf_write(fp, "   Interface = %s", IF_NAME(vrrp->ifp));
#ifdef _HAVE_VRRP_VMAC_
	if (vrrp->configured_ifp != vrrp->ifp->base_ifp && vrrp->ifp->is_ours)
		conf_write(fp, "   Configured interface = %s", vrrp->configured_ifp->ifname);
#endif
	if (vrrp->dont_track_primary)
		conf_write(fp, "   VRRP interface tracking disabled");
	if (vrrp->skip_check_adv_addr)
		conf_write(fp, "   Skip checking advert IP addresses");
	if (vrrp->strict_mode)
		conf_write(fp, "   Enforcing strict VRRP compliance");
	conf_write(fp, "   Using src_ip = %s%s", vrrp->saddr.ss_family != AF_UNSPEC
						    ? inet_sockaddrtos(&vrrp->saddr)
						    : "(none)",
						  vrrp->saddr_from_config ? " (from configuration)" : "");
	conf_write(fp, "   Gratuitous ARP delay = %d",
		       vrrp->garp_delay/TIMER_HZ);
	conf_write(fp, "   Gratuitous ARP repeat = %d", vrrp->garp_rep);
	conf_write(fp, "   Gratuitous ARP refresh = %lu",
		       vrrp->garp_refresh.tv_sec);
	conf_write(fp, "   Gratuitous ARP refresh repeat = %d", vrrp->garp_refresh_rep);
	conf_write(fp, "   Gratuitous ARP lower priority delay = %u", vrrp->garp_lower_prio_delay / TIMER_HZ);
	conf_write(fp, "   Gratuitous ARP lower priority repeat = %u", vrrp->garp_lower_prio_rep);
	conf_write(fp, "   Send advert after receive lower priority advert = %s", vrrp->lower_prio_no_advert ? "false" : "true");
	conf_write(fp, "   Send advert after receive higher priority advert = %s", vrrp->higher_prio_send_advert ? "true" : "false");
	conf_write(fp, "   Virtual Router ID = %d", vrrp->vrid);
	conf_write(fp, "   Priority = %d", vrrp->base_priority);
	if (fp) {
		conf_write(fp, "   Effective priority = %d", vrrp->effective_priority);
		conf_write(fp, "   Total priority = %d", vrrp->total_priority);
	}
	conf_write(fp, "   Advert interval = %d %s",
		(vrrp->version == VRRP_VERSION_2) ? (vrrp->adver_int / TIMER_HZ) :
		(vrrp->adver_int / (TIMER_HZ / 1000)),
		(vrrp->version == VRRP_VERSION_2) ? "sec" : "milli-sec");
	if (vrrp->state == VRRP_STATE_BACK && vrrp->version == VRRP_VERSION_3)
		conf_write(fp, "   Master advert interval = %d milli-sec", vrrp->master_adver_int / (TIMER_HZ / 1000));
	conf_write(fp, "   Accept = %s", vrrp->accept ? "enabled" : "disabled");
	conf_write(fp, "   Preempt = %s", vrrp->nopreempt ? "disabled" : "enabled");
	if (vrrp->preempt_delay)
		conf_write(fp, "   Preempt delay = %g secs",
		       (float)vrrp->preempt_delay / TIMER_HZ);
	conf_write(fp, "   Promote_secondaries = %s", vrrp->promote_secondaries ? "enabled" : "disabled");
#if defined _WITH_VRRP_AUTH_
	if (vrrp->auth_type) {
		conf_write(fp, "   Authentication type = %s",
		       (vrrp->auth_type ==
			VRRP_AUTH_AH) ? "IPSEC_AH" : "SIMPLE_PASSWORD");
		if (vrrp->auth_type != VRRP_AUTH_AH) {
			/* vrrp->auth_data is not \0 terminated */
			memcpy(auth_data, vrrp->auth_data, sizeof(vrrp->auth_data));
			auth_data[sizeof(vrrp->auth_data)] = '\0';
			conf_write(fp, "   Password = %s", auth_data);
		}
	}
	else if (vrrp->version == VRRP_VERSION_2)
		conf_write(fp, "   Authentication type = none");
#endif
	if (vrrp->kernel_rx_buf_size)
		conf_write(fp, "   Kernel rx buffer size = %lu", vrrp->kernel_rx_buf_size);

	if (vrrp->debug)
		conf_write(fp, "   Debug level = %d", vrrp->debug);

	if (!LIST_ISEMPTY(vrrp->vip)) {
		conf_write(fp, "   Virtual IP = %d", LIST_SIZE(vrrp->vip));
		dump_list(fp, vrrp->vip);
	}
	if (!LIST_ISEMPTY(vrrp->evip)) {
		conf_write(fp, "   Virtual IP Excluded = %d",
			LIST_SIZE(vrrp->evip));
		dump_list(fp, vrrp->evip);
	}
	if (!LIST_ISEMPTY(vrrp->unicast_peer)) {
		conf_write(fp, "   Unicast Peer = %d",
			LIST_SIZE(vrrp->unicast_peer));
		dump_list(fp, vrrp->unicast_peer);
#ifdef _WITH_UNICAST_CHKSUM_COMPAT_
		conf_write(fp, "   Unicast checksum compatibility = %s",
				vrrp->unicast_chksum_compat == CHKSUM_COMPATIBILITY_NONE ? "no" :
				vrrp->unicast_chksum_compat == CHKSUM_COMPATIBILITY_NEVER ? "never" :
				vrrp->unicast_chksum_compat == CHKSUM_COMPATIBILITY_CONFIG ? "config" :
				vrrp->unicast_chksum_compat == CHKSUM_COMPATIBILITY_AUTO ? "auto" : "unknown");
#endif
	}
	if (vrrp->sockets)
		conf_write(fp, "   fd_in %d, fd_out %d", vrrp->sockets->fd_in, vrrp->sockets->fd_out);
	else
		conf_write(fp, "   No sockets allocated");
#ifdef _HAVE_FIB_ROUTING_
	if (!LIST_ISEMPTY(vrrp->vroutes)) {
		conf_write(fp, "   Virtual Routes = %d", LIST_SIZE(vrrp->vroutes));
		dump_list(fp, vrrp->vroutes);
	}
	if (!LIST_ISEMPTY(vrrp->vrules)) {
		conf_write(fp, "   Virtual Rules = %d", LIST_SIZE(vrrp->vrules));
		dump_list(fp, vrrp->vrules);
	}
#endif

	if (!LIST_ISEMPTY(vrrp->track_ifp)) {
		conf_write(fp, "   Tracked interfaces = %d", LIST_SIZE(vrrp->track_ifp));
		dump_list(fp, vrrp->track_ifp);
	}
	if (!LIST_ISEMPTY(vrrp->track_script)) {
		conf_write(fp, "   Tracked scripts = %d", LIST_SIZE(vrrp->track_script));
		dump_list(fp, vrrp->track_script);
	}
	if (!LIST_ISEMPTY(vrrp->track_file)) {
		conf_write(fp, "   Tracked files = %d", LIST_SIZE(vrrp->track_file));
		dump_list(fp, vrrp->track_file);
	}
#ifdef _WITH_BFD_
	if (!LIST_ISEMPTY(vrrp->track_bfd)) {
		conf_write(fp, "   Tracked BFDs = %d", LIST_SIZE(vrrp->track_bfd));
		dump_list(fp, vrrp->track_bfd);
	}
#endif

	conf_write(fp, "   Using smtp notification = %s", vrrp->smtp_alert ? "yes" : "no");

	if (vrrp->script_backup)
		dump_notify_script(fp, vrrp->script_backup, "Backup");
	if (vrrp->script_master)
		dump_notify_script(fp, vrrp->script_master, "Master");
	if (vrrp->script_fault)
		dump_notify_script(fp, vrrp->script_fault, "Fault");
	if (vrrp->script_stop)
		dump_notify_script(fp, vrrp->script_stop, "Stop");
	if (vrrp->script)
		dump_notify_script(fp, vrrp->script, "Generic");
	if (vrrp->script_master_rx_lower_pri)
		dump_notify_script(fp, vrrp->script_master_rx_lower_pri, "Master rx lower pri");
}

void
alloc_static_track_group(char *gname)
{
	size_t size = strlen(gname);
	static_track_group_t *new;

	if (!LIST_EXISTS(vrrp_data->static_track_groups))
		vrrp_data->static_track_groups = alloc_list(free_tgroup, dump_tgroup);

	/* Allocate new VRRP group structure */
	new = (static_track_group_t *) MALLOC(sizeof(*new));
	new->gname = (char *) MALLOC(size + 1);
	memcpy(new->gname, gname, size);

	list_add(vrrp_data->static_track_groups, new);
}

void
alloc_vrrp_sync_group(char *gname)
{
	size_t size = strlen(gname);
	vrrp_sgroup_t *new;

	/* Allocate new VRRP group structure */
	new = (vrrp_sgroup_t *) MALLOC(sizeof(vrrp_sgroup_t));
	new->gname = (char *) MALLOC(size + 1);
	new->state = VRRP_STATE_INIT;
	new->last_email_state = VRRP_STATE_INIT;
	memcpy(new->gname, gname, size);
	new->sgroup_tracking_weight = false;
	new->smtp_alert = -1;

	list_add(vrrp_data->vrrp_sync_group, new);
}

vrrp_stats *
alloc_vrrp_stats(void)
{
	vrrp_stats *new;
	new = (vrrp_stats *) MALLOC(sizeof (vrrp_stats));
	new->become_master = 0;
	new->release_master = 0;
	new->invalid_authtype = 0;
#ifdef _WITH_VRRP_AUTH_
	new->authtype_mismatch = 0;
	new->auth_failure = 0;
#endif
	new->packet_len_err = 0;
	new->advert_rcvd = 0;
	new->advert_sent = 0;
	new->advert_interval_err = 0;
	new->ip_ttl_err = 0;
	new->pri_zero_rcvd = 0;
	new->pri_zero_sent = 0;
	new->invalid_type_rcvd = 0;
	new->addr_list_err = 0;
#ifdef _WITH_SNMP_RFCV3_
	new->master_reason = VRRPV3_MASTER_REASON_NOT_MASTER;
	new->next_master_reason = VRRPV3_MASTER_REASON_MASTER_NO_RESPONSE;
#endif
	return new;
}

void
alloc_vrrp(char *iname)
{
	size_t size = strlen(iname);
	vrrp_t *new;

	/* Allocate new VRRP structure */
	new = (vrrp_t *) MALLOC(sizeof(vrrp_t));

	/* Set default values */
	new->family = AF_UNSPEC;
	new->saddr.ss_family = AF_UNSPEC;
	new->wantstate = VRRP_STATE_INIT;
	new->last_email_state = VRRP_STATE_INIT;
	new->version = 0;
	new->master_priority = 0;
	new->last_transition = timer_now();
	new->iname = (char *) MALLOC(size + 1);
	memcpy(new->iname, iname, size);
	new->stats = alloc_vrrp_stats();
	new->accept = PARAMETER_UNSET;
	new->garp_rep = global_data->vrrp_garp_rep;
	new->garp_refresh = global_data->vrrp_garp_refresh;
	new->garp_refresh_rep = global_data->vrrp_garp_refresh_rep;
	new->garp_delay = global_data->vrrp_garp_delay;
	new->garp_lower_prio_delay = PARAMETER_UNSET;
	new->garp_lower_prio_rep = PARAMETER_UNSET;
	new->lower_prio_no_advert = PARAMETER_UNSET;
	new->higher_prio_send_advert = PARAMETER_UNSET;
#ifdef _WITH_UNICAST_CHKSUM_COMPAT_
	new->unicast_chksum_compat = CHKSUM_COMPATIBILITY_NONE;
#endif
	new->smtp_alert = -1;

	new->skip_check_adv_addr = global_data->vrrp_skip_check_adv_addr;
	new->strict_mode = PARAMETER_UNSET;

	list_add(vrrp_data->vrrp, new);
}

void
alloc_vrrp_unicast_peer(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
	struct sockaddr_storage *peer = NULL;

	if (!LIST_EXISTS(vrrp->unicast_peer))
		vrrp->unicast_peer = alloc_list(free_unicast_peer, dump_unicast_peer);

	/* Allocate new unicast peer */
	peer = (struct sockaddr_storage *) MALLOC(sizeof(struct sockaddr_storage));
	if (inet_stosockaddr(strvec_slot(strvec, 0), NULL, peer)) {
		report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: VRRP instance[%s] malformed unicast"
				     " peer address[%s]. Skipping..."
				   , vrrp->iname, FMT_STR_VSLOT(strvec, 0));
		FREE(peer);
		return;
	}

	if (!vrrp->family)
		vrrp->family = peer->ss_family;
	else if (peer->ss_family != vrrp->family) {
		report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: VRRP instance[%s] and unicast peer address"
				     "[%s] MUST be of the same family !!! Skipping..."
				   , vrrp->iname, FMT_STR_VSLOT(strvec, 0));
		FREE(peer);
		return;
	}

	list_add(vrrp->unicast_peer, peer);
}

void
alloc_vrrp_track_if(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->track_ifp))
		vrrp->track_ifp = alloc_list(free_track_if, dump_track_if);
	alloc_track_if(vrrp, strvec);
}

void
alloc_vrrp_track_script(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->track_script))
		vrrp->track_script = alloc_list(free_track_script, dump_track_script);
	alloc_track_script(vrrp, strvec);
}

void
alloc_vrrp_track_file(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->track_file))
		vrrp->track_file = alloc_list(free_track_file, dump_track_file);
	alloc_track_file(vrrp, strvec);
}

#ifdef _WITH_BFD_
void
alloc_vrrp_track_bfd(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->track_bfd))
		vrrp->track_bfd = alloc_list(free_vrrp_tracked_bfd, dump_vrrp_tracked_bfd);
	alloc_track_bfd(vrrp, strvec);
}
#endif

void
alloc_vrrp_group_track_if(vector_t *strvec)
{
	vrrp_sgroup_t *sgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);

	if (!LIST_EXISTS(sgroup->track_ifp))
		sgroup->track_ifp = alloc_list(free_track_if, dump_track_if);
	alloc_group_track_if(sgroup, strvec);
}

void
alloc_vrrp_group_track_script(vector_t *strvec)
{
	vrrp_sgroup_t *sgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);

	if (!LIST_EXISTS(sgroup->track_script))
		sgroup->track_script = alloc_list(free_track_script, dump_track_script);
	alloc_group_track_script(sgroup, strvec);
}

void
alloc_vrrp_group_track_file(vector_t *strvec)
{
	vrrp_sgroup_t *sgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);

	if (!LIST_EXISTS(sgroup->track_file))
		sgroup->track_file = alloc_list(free_track_file, dump_track_file);
	alloc_group_track_file(sgroup, strvec);
}

#ifdef _WITH_BFD_
void
alloc_vrrp_group_track_bfd(vector_t *strvec)
{
	vrrp_sgroup_t *sgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);

	if (!LIST_EXISTS(sgroup->track_bfd))
		sgroup->track_bfd = alloc_list(free_vrrp_tracked_bfd, dump_vrrp_tracked_bfd);
	alloc_group_track_bfd(sgroup, strvec);
}
#endif

void
alloc_vrrp_vip(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
	void *list_end = NULL;
	sa_family_t address_family;

	if (!LIST_EXISTS(vrrp->vip))
		vrrp->vip = alloc_list(free_ipaddress, dump_ipaddress);
	else if (!LIST_ISEMPTY(vrrp->vip))
		list_end = LIST_TAIL_DATA(vrrp->vip);

	alloc_ipaddress(vrrp->vip, strvec, vrrp->ifp, false);

	if (!LIST_ISEMPTY(vrrp->vip) && LIST_TAIL_DATA(vrrp->vip) != list_end) {
		address_family = IP_FAMILY((ip_address_t*)LIST_TAIL_DATA(vrrp->vip));

		if (vrrp->family == AF_UNSPEC)
			vrrp->family = address_family;
		else if (address_family != vrrp->family) {
			report_config_error(CONFIG_GENERAL_ERROR, "(%s): address family must match VRRP instance [%s] - ignoring", vrrp->iname, FMT_STR_VSLOT(strvec, 0));
			free_list_element(vrrp->vip, vrrp->vip->tail);
		}
	}
}

void
alloc_vrrp_evip(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->evip))
		vrrp->evip = alloc_list(free_ipaddress, dump_ipaddress);
	alloc_ipaddress(vrrp->evip, strvec, vrrp->ifp, false);
}

#ifdef _HAVE_FIB_ROUTING_
void
alloc_vrrp_vroute(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->vroutes))
		vrrp->vroutes = alloc_list(free_iproute, dump_iproute);
	alloc_route(vrrp->vroutes, strvec, false);
}

void
alloc_vrrp_vrule(vector_t *strvec)
{
	vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);

	if (!LIST_EXISTS(vrrp->vrules))
		vrrp->vrules = alloc_list(free_iprule, dump_iprule);
	alloc_rule(vrrp->vrules, strvec, false);
}
#endif

void
alloc_vrrp_script(char *sname)
{
	size_t size = strlen(sname);
	vrrp_script_t *new;

	/* Allocate new VRRP script structure */
	new = (vrrp_script_t *) MALLOC(sizeof(vrrp_script_t));
	new->sname = (char *) MALLOC(size + 1);
	memcpy(new->sname, sname, size + 1);
	new->interval = VRRP_SCRIPT_DI * TIMER_HZ;
	new->timeout = VRRP_SCRIPT_DT * TIMER_HZ;
	new->weight = VRRP_SCRIPT_DW;
//	new->last_status = VRRP_SCRIPT_STATUS_NOT_SET;
	new->init_state = SCRIPT_INIT_STATE_INIT;
	new->state = SCRIPT_STATE_IDLE;
	new->rise = 1;
	new->fall = 1;
	list_add(vrrp_data->vrrp_script, new);
}

void
alloc_vrrp_file(char *fname)
{
	size_t size = strlen(fname);
	vrrp_tracked_file_t *new;

	/* Allocate new VRRP file structure */
	new = (vrrp_tracked_file_t *) MALLOC(sizeof(vrrp_tracked_file_t));
	new->fname = (char *) MALLOC(size + 1);
	memcpy(new->fname, fname, size + 1);
	new->weight = 1;
	list_add(vrrp_data->vrrp_track_files, new);
}

/* data facility functions */
void
alloc_vrrp_buffer(size_t len)
{
	if (vrrp_buffer)
		return;

	vrrp_buffer = (char *) MALLOC(len);
	vrrp_buffer_len = (vrrp_buffer) ? len : 0;
}

void
free_vrrp_buffer(void)
{
	/* If the configuration failed, we may not have
	 * allocated a buffer */
	if (!vrrp_buffer)
		return;

	FREE(vrrp_buffer);
	vrrp_buffer = NULL;
	vrrp_buffer_len = 0;
}

vrrp_data_t *
alloc_vrrp_data(void)
{
	vrrp_data_t *new;

	new = (vrrp_data_t *) MALLOC(sizeof(vrrp_data_t));
	new->vrrp = alloc_list(free_vrrp, dump_vrrp);
	new->vrrp_sync_group = alloc_list(free_vgroup, dump_vgroup);
	new->vrrp_script = alloc_list(free_vscript, dump_vscript);
	new->vrrp_track_files = alloc_list(free_vfile, dump_vfile);
#ifdef _WITH_BFD_
	new->vrrp_track_bfds = alloc_list(free_vrrp_bfd, dump_vrrp_bfd);
#endif
	new->vrrp_socket_pool = alloc_list(free_sock, dump_sock);

	return new;
}

void
free_vrrp_data(vrrp_data_t * data)
{
	free_list(&data->static_addresses);
#ifdef _HAVE_FIB_ROUTING_
	free_list(&data->static_routes);
	free_list(&data->static_rules);
#endif
	free_list(&data->static_track_groups);
	free_list(&data->vrrp);
	free_list(&data->vrrp_sync_group);
	free_list(&data->vrrp_script);
	free_list(&data->vrrp_track_files);
#ifdef _WITH_BFD_
	free_list(&data->vrrp_track_bfds);
#endif
	FREE(data);
}

static void
dump_vrrp_data(FILE *fp, vrrp_data_t * data)
{
	if (!LIST_ISEMPTY(data->static_addresses)) {
		conf_write(fp, "------< Static Addresses >------");
		dump_list(fp, data->static_addresses);
	}
#ifdef _HAVE_FIB_ROUTING_
	if (!LIST_ISEMPTY(data->static_routes)) {
		conf_write(fp, "------< Static Routes >------");
		dump_list(fp, data->static_routes);
	}
	if (!LIST_ISEMPTY(data->static_rules)) {
		conf_write(fp, "------< Static Rules >------");
		dump_list(fp, data->static_rules);
	}
#endif
	if (!LIST_ISEMPTY(data->static_track_groups)) {
		conf_write(fp, "------< Static Track groups >------");
		dump_list(fp, data->static_track_groups);
	}
	if (!LIST_ISEMPTY(data->vrrp)) {
		conf_write(fp, "------< VRRP Topology >------");
		dump_list(fp, data->vrrp);
	}
	if (!LIST_ISEMPTY(data->vrrp_sync_group)) {
		conf_write(fp, "------< VRRP Sync groups >------");
		dump_list(fp, data->vrrp_sync_group);
	}
	if (!LIST_ISEMPTY(data->vrrp_script)) {
		conf_write(fp, "------< VRRP Scripts >------");
		dump_list(fp, data->vrrp_script);
	}
	if (!LIST_ISEMPTY(data->vrrp_track_files)) {
		conf_write(fp, "------< VRRP Track files >------");
		dump_list(fp, data->vrrp_track_files);
	}
#ifdef _WITH_BFD_
	if (!LIST_ISEMPTY(data->vrrp_track_bfds)) {
		conf_write(fp, "------< VRRP Track BFDs >------");
		dump_list(fp, data->vrrp_track_bfds);
	}
#endif
}

void
dump_data_vrrp(FILE *fp)
{
	list ifl;

	dump_global_data(fp, global_data);

	if (!LIST_ISEMPTY(garp_delay)) {
		conf_write(fp, "------< Gratuitous ARP delays >------");
		dump_list(fp, garp_delay);
	}

	dump_vrrp_data(fp, vrrp_data);

	ifl = get_if_list();
	if (!LIST_ISEMPTY(ifl)) {
		conf_write(fp, "------< Interfaces >------");
		dump_list(fp, ifl);
	}

	clear_rt_names();
}