211 lines
4.6 KiB
C
211 lines
4.6 KiB
C
/*
|
|
* vrrp.c - init VRRP instance and VRRP state functions
|
|
*
|
|
* Copyright (C) 2014 Arnaud Andre
|
|
*
|
|
* This file is part of uvrrpd.
|
|
*
|
|
* uvrrpd 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* uvrrpd 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with uvrrpd. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
/* pselect() */
|
|
#include <sys/select.h>
|
|
#include <signal.h>
|
|
|
|
#include "vrrp.h"
|
|
#include "vrrp_timer.h"
|
|
#include "vrrp_net.h"
|
|
#include "vrrp_state.h"
|
|
#include "vrrp_ctrl.h"
|
|
|
|
#include "uvrrpd.h"
|
|
#include "bits.h"
|
|
|
|
#include "log.h"
|
|
|
|
extern unsigned long reg;
|
|
|
|
/**
|
|
* vrrp_init() - init struct vrrp with default values
|
|
*/
|
|
void vrrp_init(struct vrrp *vrrp)
|
|
{
|
|
/* VRRP version */
|
|
vrrp->version = RFC3768;
|
|
|
|
vrrp->vrid = 0;
|
|
vrrp->priority = PRIO_DFL;
|
|
vrrp->naddr = 0;
|
|
|
|
/* auth */
|
|
vrrp->auth_type = NOAUTH;
|
|
vrrp->auth_data = NULL;
|
|
|
|
/* state */
|
|
vrrp->state = INIT;
|
|
vrrp->preempt = PREEMPT_DFL;
|
|
|
|
/* script */
|
|
vrrp->scriptname = NULL;
|
|
vrrp->argv = NULL;
|
|
|
|
/* timers */
|
|
vrrp->adv_int = 0;
|
|
vrrp->master_adv_int = 0;
|
|
vrrp_timer_clear(&vrrp->adv_timer);
|
|
vrrp_timer_clear(&vrrp->masterdown_timer);
|
|
}
|
|
|
|
/**
|
|
* vrrp_context() - dump vrrp info
|
|
*/
|
|
static void vrrp_context(struct vrrp *vrrp)
|
|
{
|
|
log_notice("====================");
|
|
log_notice("VRID %d", vrrp->vrid);
|
|
log_notice("current_state %s", STR_STATE(vrrp->state));
|
|
log_notice("priority %d", vrrp->priority);
|
|
log_notice("adv_int %d", vrrp->adv_int);
|
|
if (vrrp->version == RFC5798)
|
|
log_notice("master_adv_int %d", vrrp->master_adv_int);
|
|
log_notice("preempt %s", STR_PREEMPT(vrrp->preempt));
|
|
log_notice("naddr %d", vrrp->naddr);
|
|
log_notice("====================");
|
|
}
|
|
|
|
|
|
/**
|
|
* vrrp_process() - vrrp control and state machine
|
|
*/
|
|
int vrrp_process(struct vrrp *vrrp, struct vrrp_net *vnet)
|
|
{
|
|
switch (vrrp->state) {
|
|
case INIT:
|
|
vrrp_state_init(vrrp, vnet);
|
|
break;
|
|
|
|
case BACKUP:
|
|
vrrp_state_backup(vrrp, vnet);
|
|
break;
|
|
|
|
case MASTER:
|
|
vrrp_state_master(vrrp, vnet);
|
|
break;
|
|
|
|
default:
|
|
/* invalid state */
|
|
return -ENOSYS;
|
|
break;
|
|
}
|
|
|
|
if (test_and_clear_bit(UVRRPD_DUMP, ®))
|
|
vrrp_context(vrrp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* vrrp_listen() - Wait for a event (VRRP pkt, msg on fifo ...)
|
|
*
|
|
* @return vrrp_event_t
|
|
* TIMER if current timer is expired
|
|
* another event else
|
|
*/
|
|
vrrp_event_t vrrp_listen(struct vrrp *vrrp, struct vrrp_net *vnet)
|
|
{
|
|
struct vrrp_timer *vt;
|
|
int max_fd;
|
|
|
|
/* Check which timer is running
|
|
* Advertisement timer or Masterdown timer ?
|
|
*/
|
|
if (vrrp_timer_is_running(&vrrp->adv_timer)) {
|
|
log_debug("vrid %d :: adv_timer is running", vrrp->vrid);
|
|
vt = &vrrp->adv_timer;
|
|
}
|
|
else if (vrrp_timer_is_running(&vrrp->masterdown_timer)) {
|
|
log_debug("vrid %d :: masterdown_timer is running", vrrp->vrid);
|
|
vt = &vrrp->masterdown_timer;
|
|
}
|
|
else { /* No timer ? ... exit */
|
|
log_error("vrid %d :: no timer running !", vrrp->vrid);
|
|
/* TODO die() */
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* update timer before pselect() */
|
|
if (vrrp_timer_update(vt)) {
|
|
log_debug("vrid %d :: timer expired before pselect",
|
|
vrrp->vrid);
|
|
/* timer expired or invalid */
|
|
return TIMER;
|
|
}
|
|
|
|
/* pselect */
|
|
fd_set readfds;
|
|
FD_ZERO(&readfds);
|
|
FD_SET(vnet->socket, &readfds);
|
|
FD_SET(vrrp->ctrl.fd, &readfds);
|
|
max_fd = max(vnet->socket, vrrp->ctrl.fd);
|
|
|
|
sigset_t emptyset;
|
|
sigemptyset(&emptyset);
|
|
|
|
/* Wait for packet or timer expiration */
|
|
if (pselect
|
|
(max_fd + 1, &readfds, NULL, NULL,
|
|
(const struct timespec *) &vt->delta, &emptyset) >= 0) {
|
|
|
|
|
|
/* Timer is expired */
|
|
if (vrrp_timer_is_expired(vt)) {
|
|
log_debug("vrid %d :: timer expired", vrrp->vrid);
|
|
return TIMER;
|
|
}
|
|
|
|
/* Else we have received a pkt */
|
|
log_debug("vrid %d :: VRRP pkt received", vrrp->vrid);
|
|
|
|
if (FD_ISSET(vnet->socket, &readfds))
|
|
/* check if received is valid or not */
|
|
return vrrp_net_recv(vnet, vrrp);
|
|
|
|
if (FD_ISSET(vrrp->ctrl.fd, &readfds)) {
|
|
return vrrp_ctrl_read(vrrp, vnet);
|
|
}
|
|
}
|
|
else { /* Signal or pselect error */
|
|
if (errno == EINTR) {
|
|
log_debug("vrid %d :: signal caught", vrrp->vrid);
|
|
|
|
return SIGNAL;
|
|
}
|
|
|
|
log_error("vrid %d :: pselect - %m", vrrp->vrid);
|
|
}
|
|
|
|
return INVALID;
|
|
}
|
|
|
|
|
|
/**
|
|
* vrrp_cleanup() - clean before exiting
|
|
*/
|
|
void vrrp_cleanup(struct vrrp *vrrp)
|
|
{
|
|
free(vrrp->scriptname);
|
|
free(vrrp->auth_data);
|
|
}
|