|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Soft: Keepalived is a failover program for the LVS project
|
|
Packit |
c22fc9 |
* <www.linuxvirtualserver.org>. It monitor & manipulate
|
|
Packit |
c22fc9 |
* a loadbalanced server pool using multi-layer checks.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Part: Dynamic data structure definition
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Author: Ilya Voronin, <ivoronin@gmail.com>
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
c22fc9 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
c22fc9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
c22fc9 |
* See the GNU General Public License for more details.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
c22fc9 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
c22fc9 |
* as published by the Free Software Foundation; either version
|
|
Packit |
c22fc9 |
* 2 of the License, or (at your option) any later version.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Copyright (C) 2015-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "config.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include <assert.h>
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "bfd.h"
|
|
Packit |
c22fc9 |
#include "bfd_data.h"
|
|
Packit |
c22fc9 |
#include "logger.h"
|
|
Packit |
c22fc9 |
#include "parser.h"
|
|
Packit |
c22fc9 |
#include "memory.h"
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
#include "main.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Global vars */
|
|
Packit |
c22fc9 |
bfd_data_t *bfd_data;
|
|
Packit |
c22fc9 |
bfd_data_t *old_bfd_data;
|
|
Packit |
c22fc9 |
char *bfd_buffer;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* bfd_t functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
/* Initialize bfd_t */
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
alloc_bfd(char *name)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(name);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd = (bfd_t *) MALLOC(sizeof (bfd_t));
|
|
Packit |
c22fc9 |
strcpy(bfd->iname, name);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set defaults */
|
|
Packit |
c22fc9 |
bfd->local_min_rx_intv = BFD_MINRX_DEFAULT * 1000;
|
|
Packit |
c22fc9 |
bfd->local_min_tx_intv = BFD_MINTX_DEFAULT * 1000;
|
|
Packit |
c22fc9 |
bfd->local_idle_tx_intv = BFD_IDLETX_DEFAULT * 1000;
|
|
Packit |
c22fc9 |
bfd->local_detect_mult = BFD_MULTIPLIER_DEFAULT;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->ttl = 0;
|
|
Packit |
c22fc9 |
bfd->max_hops = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Initialize internal variables */
|
|
Packit |
c22fc9 |
bfd->fd_out = -1;
|
|
Packit |
c22fc9 |
bfd->thread_out = NULL;
|
|
Packit |
c22fc9 |
bfd->thread_exp = NULL;
|
|
Packit |
c22fc9 |
bfd->thread_rst = NULL;
|
|
Packit |
c22fc9 |
bfd->sands_out = -1;
|
|
Packit |
c22fc9 |
bfd->sands_exp = -1;
|
|
Packit |
c22fc9 |
bfd->sands_rst = -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
list_add(bfd_data->bfd, bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
free_bfd(void *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
FREE(data);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Dump BFD instance configuration parameters */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
dump_bfd(FILE *fp, void *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
bfd = (bfd_t *)data;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " BFD Instance = %s", bfd->iname);
|
|
Packit |
c22fc9 |
conf_write(fp, " Neighbor IP = %s",
|
|
Packit |
c22fc9 |
inet_sockaddrtos(&bfd->nbr_addr));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->src_addr.ss_family != AF_UNSPEC)
|
|
Packit |
c22fc9 |
conf_write(fp, " Source IP = %s",
|
|
Packit |
c22fc9 |
inet_sockaddrtos(&bfd->src_addr));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " Required min RX interval = %i ms",
|
|
Packit |
c22fc9 |
bfd->local_min_rx_intv / (TIMER_HZ / 1000));
|
|
Packit |
c22fc9 |
conf_write(fp, " Desired min TX interval = %i ms",
|
|
Packit |
c22fc9 |
bfd->local_min_tx_intv / (TIMER_HZ / 1000));
|
|
Packit |
c22fc9 |
conf_write(fp, " Desired idle TX interval = %i ms",
|
|
Packit |
c22fc9 |
bfd->local_idle_tx_intv / (TIMER_HZ / 1000));
|
|
Packit |
c22fc9 |
conf_write(fp, " Detection multiplier = %i",
|
|
Packit |
c22fc9 |
bfd->local_detect_mult);
|
|
Packit |
c22fc9 |
conf_write(fp, " %s = %d",
|
|
Packit |
c22fc9 |
bfd->nbr_addr.ss_family == AF_INET ? "TTL" : "hoplimit",
|
|
Packit |
c22fc9 |
bfd->ttl);
|
|
Packit |
c22fc9 |
conf_write(fp, " max_hops = %d",
|
|
Packit |
c22fc9 |
bfd->max_hops);
|
|
Packit |
c22fc9 |
#ifdef _WITH_VRRP_
|
|
Packit |
c22fc9 |
conf_write(fp, " send event to VRRP process = %s",
|
|
Packit |
c22fc9 |
bfd->vrrp ? "Yes" : "No");
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#ifdef _WITH_LVS_
|
|
Packit |
c22fc9 |
conf_write(fp, " send event to checker process = %s",
|
|
Packit |
c22fc9 |
bfd->checker ? "Yes" : "No");
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Looks up bfd instance by name */
|
|
Packit |
c22fc9 |
static bfd_t *
|
|
Packit |
c22fc9 |
find_bfd_by_name2(const char *name, const bfd_data_t *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(name);
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
assert(data->bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(data->bfd))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (!strcmp(name, bfd->iname))
|
|
Packit |
c22fc9 |
return bfd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_t *
|
|
Packit |
c22fc9 |
find_bfd_by_name(const char *name)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
return find_bfd_by_name2(name, bfd_data);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* compares old and new timers, returns 0 if they are the same */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_cmp_timers(bfd_t * old_bfd, bfd_t * bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
return (old_bfd->local_min_rx_intv != bfd->local_min_rx_intv
|
|
Packit |
c22fc9 |
|| old_bfd->local_min_tx_intv != bfd->local_min_tx_intv);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* bfd_data_t functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
bfd_data_t *
|
|
Packit |
c22fc9 |
alloc_bfd_data(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_data_t *data;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
data = (bfd_data_t *) MALLOC(sizeof (bfd_data_t));
|
|
Packit |
c22fc9 |
data->bfd = alloc_list(free_bfd, dump_bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Initialize internal variables */
|
|
Packit |
c22fc9 |
data->thread_in = NULL;
|
|
Packit |
c22fc9 |
data->fd_in = -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return data;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
free_bfd_data(bfd_data_t * data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
free_list(&data->bfd);
|
|
Packit |
c22fc9 |
FREE(data);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
dump_bfd_data(FILE *fp, bfd_data_t * data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(data->bfd)) {
|
|
Packit |
c22fc9 |
conf_write(fp, "------< BFD Topology >------");
|
|
Packit |
c22fc9 |
dump_list(fp, data->bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
bfd_complete_init(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd, *bfd_old;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(bfd_data);
|
|
Packit |
c22fc9 |
assert(bfd_data->bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Build configuration */
|
|
Packit |
c22fc9 |
LIST_FOREACH(bfd_data->bfd, bfd, e) {
|
|
Packit |
c22fc9 |
/* If there was an old instance with the same name
|
|
Packit |
c22fc9 |
copy its state and thread sands during reload */
|
|
Packit |
c22fc9 |
if (reload && (bfd_old = find_bfd_by_name2(bfd->iname, old_bfd_data))) {
|
|
Packit |
c22fc9 |
bfd_copy_state(bfd, bfd_old, true);
|
|
Packit |
c22fc9 |
bfd_copy_sands(bfd, bfd_old);
|
|
Packit |
c22fc9 |
if (bfd_cmp_timers(bfd_old, bfd))
|
|
Packit |
c22fc9 |
bfd_set_poll(bfd);
|
|
Packit |
c22fc9 |
} else
|
|
Packit |
c22fc9 |
bfd_init_state(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Copy old input fd on reload */
|
|
Packit |
c22fc9 |
if (reload)
|
|
Packit |
c22fc9 |
bfd_data->fd_in = old_bfd_data->fd_in;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* bfd_buffer functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
alloc_bfd_buffer(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (!bfd_buffer)
|
|
Packit |
c22fc9 |
bfd_buffer = (char *) MALLOC(BFD_BUFFER_SIZE);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
free_bfd_buffer(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
FREE(bfd_buffer);
|
|
Packit |
c22fc9 |
bfd_buffer = NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Lookup functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
/* Looks up bfd instance by neighbor address */
|
|
Packit |
c22fc9 |
bfd_t *
|
|
Packit |
c22fc9 |
find_bfd_by_addr(const struct sockaddr_storage *addr)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
assert(addr);
|
|
Packit |
c22fc9 |
assert(bfd_data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(bfd_data->bfd))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(bfd_data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (!inet_sockaddrcmp(&bfd->nbr_addr, addr))
|
|
Packit |
c22fc9 |
return bfd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Looks up bfd instance by local discriminator */
|
|
Packit |
c22fc9 |
bfd_t *
|
|
Packit |
c22fc9 |
find_bfd_by_discr(const uint32_t discr)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(bfd_data->bfd))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(bfd_data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (bfd->local_discr == discr)
|
|
Packit |
c22fc9 |
return bfd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Utility functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
/* Generates a random number in the specified interval */
|
|
Packit |
c22fc9 |
uint32_t
|
|
Packit |
c22fc9 |
rand_intv(uint32_t min, uint32_t max)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
double scaled = (double) rand() / RAND_MAX;
|
|
Packit |
c22fc9 |
return (max - min + 1) * scaled + min;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns random disciminator number */
|
|
Packit |
c22fc9 |
uint32_t
|
|
Packit |
c22fc9 |
bfd_get_random_discr(bfd_data_t *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
uint32_t discr;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
do {
|
|
Packit |
c22fc9 |
discr = rand_intv(1, UINT32_MAX);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check for collisions */
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (bfd->local_discr == discr) {
|
|
Packit |
c22fc9 |
discr = 0;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
} while (!discr);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return discr;
|
|
Packit |
c22fc9 |
}
|