|
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: Manipulation functions for IPVS & IPFW wrappers.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Author: Alexandre Cassen, <acassen@linux-vs.org>
|
|
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) 2001-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "config.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include <unistd.h>
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "ipwrapper.h"
|
|
Packit |
c22fc9 |
#include "check_api.h"
|
|
Packit |
c22fc9 |
#include "logger.h"
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
#include "main.h"
|
|
Packit |
c22fc9 |
#ifdef _WITH_SNMP_CHECKER_
|
|
Packit |
c22fc9 |
#include "check_snmp.h"
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#include "global_data.h"
|
|
Packit |
c22fc9 |
#include "smtp.h"
|
|
Packit |
c22fc9 |
#include "check_daemon.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns the sum of all alive RS weight in a virtual server. */
|
|
Packit |
c22fc9 |
static unsigned long
|
|
Packit |
c22fc9 |
weigh_live_realservers(virtual_server_t * vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
real_server_t *svr;
|
|
Packit |
c22fc9 |
long count = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
svr = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (ISALIVE(svr))
|
|
Packit |
c22fc9 |
count += svr->weight;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
return count;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
notify_fifo_vs(virtual_server_t* vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
char *state = vs->quorum_state_up ? "UP" : "DOWN";
|
|
Packit |
c22fc9 |
size_t size;
|
|
Packit |
c22fc9 |
char *line;
|
|
Packit |
c22fc9 |
char *vs_str;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (global_data->notify_fifo.fd == -1 &&
|
|
Packit |
c22fc9 |
global_data->lvs_notify_fifo.fd == -1)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vs_str = FMT_VS(vs);
|
|
Packit |
c22fc9 |
size = strlen(vs_str) + strlen(state) + 6;
|
|
Packit |
c22fc9 |
line = MALLOC(size);
|
|
Packit |
c22fc9 |
if (!line)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
snprintf(line, size, "VS %s %s\n", vs_str, state);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (global_data->notify_fifo.fd != -1) {
|
|
Packit |
c22fc9 |
if (write(global_data->notify_fifo.fd, line, size - 1) == -1) {}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
if (global_data->lvs_notify_fifo.fd != -1) {
|
|
Packit |
c22fc9 |
if (write(global_data->lvs_notify_fifo.fd, line, size - 1) == -1) {}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
FREE(line);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
notify_fifo_rs(virtual_server_t* vs, real_server_t* rs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
char *state = rs->alive ? "UP" : "DOWN";
|
|
Packit |
c22fc9 |
size_t size;
|
|
Packit |
c22fc9 |
char *line;
|
|
Packit |
c22fc9 |
char *str;
|
|
Packit |
c22fc9 |
char *rs_str;
|
|
Packit |
c22fc9 |
char *vs_str;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (global_data->notify_fifo.fd == -1 &&
|
|
Packit |
c22fc9 |
global_data->lvs_notify_fifo.fd == -1)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
str = FMT_RS(rs, vs);
|
|
Packit |
c22fc9 |
rs_str = MALLOC(strlen(str)+1);
|
|
Packit |
c22fc9 |
strcpy(rs_str, str);
|
|
Packit |
c22fc9 |
vs_str = FMT_VS(vs);
|
|
Packit |
c22fc9 |
size = strlen(rs_str) + strlen(vs_str) + strlen(state) + 7;
|
|
Packit |
c22fc9 |
line = MALLOC(size);
|
|
Packit |
c22fc9 |
if (!line)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
snprintf(line, size, "RS %s %s %s\n", rs_str, vs_str, state);
|
|
Packit |
c22fc9 |
FREE(rs_str);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (global_data->notify_fifo.fd != -1) {
|
|
Packit |
c22fc9 |
if (write(global_data->notify_fifo.fd, line, size - 1) == - 1) {}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
if (global_data->lvs_notify_fifo.fd != -1) {
|
|
Packit |
c22fc9 |
if (write(global_data->lvs_notify_fifo.fd, line, size - 1) == -1) {}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
FREE(line);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
do_vs_notifies(virtual_server_t* vs, bool init, long threshold, long weight_sum, bool stopping)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
notify_script_t *notify_script = vs->quorum_state_up ? vs->notify_quorum_up : vs->notify_quorum_down;
|
|
Packit |
c22fc9 |
char message[80];
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _WITH_SNMP_CHECKER_
|
|
Packit |
c22fc9 |
check_snmp_quorum_trap(vs, stopping);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Only send non SNMP notifies when stopping if omega set */
|
|
Packit |
c22fc9 |
if (stopping && !vs->omega)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (notify_script) {
|
|
Packit |
c22fc9 |
if (stopping)
|
|
Packit |
c22fc9 |
system_call_script(master, child_killed_thread, NULL, TIMER_HZ, notify_script);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
notify_exec(notify_script);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
notify_fifo_vs(vs);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vs->smtp_alert) {
|
|
Packit |
c22fc9 |
if (stopping)
|
|
Packit |
c22fc9 |
snprintf(message, sizeof(message), "=> Shutting down <=");
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
snprintf(message, sizeof(message), "=> %s %u+%u=%ld <= %ld <=",
|
|
Packit |
c22fc9 |
vs->quorum_state_up ?
|
|
Packit |
c22fc9 |
init ? "Starting with quorum up" :
|
|
Packit |
c22fc9 |
"Gained quorum" :
|
|
Packit |
c22fc9 |
init ? "Starting with quorum down" :
|
|
Packit |
c22fc9 |
"Lost quorum",
|
|
Packit |
c22fc9 |
vs->quorum,
|
|
Packit |
c22fc9 |
vs->hysteresis,
|
|
Packit |
c22fc9 |
threshold,
|
|
Packit |
c22fc9 |
weight_sum);
|
|
Packit |
c22fc9 |
smtp_alert(SMTP_MSG_VS, vs, vs->quorum_state_up ? "UP" : "DOWN", message);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
do_rs_notifies(virtual_server_t* vs, real_server_t* rs, bool stopping)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
notify_script_t *notify_script = rs->alive ? rs->notify_up : rs->notify_down;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (notify_script) {
|
|
Packit |
c22fc9 |
if (stopping)
|
|
Packit |
c22fc9 |
system_call_script(master, child_killed_thread, NULL, TIMER_HZ, notify_script);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
notify_exec(notify_script);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
notify_fifo_rs(vs, rs);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* The sending of smtp_alerts is handled by the individual checker
|
|
Packit |
c22fc9 |
* so that the message can have context for the checker */
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _WITH_SNMP_CHECKER_
|
|
Packit |
c22fc9 |
check_snmp_rs_trap(rs, vs, stopping);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Remove a realserver IPVS rule */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
clear_service_rs(virtual_server_t * vs, list l, bool stopping)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
real_server_t *rs;
|
|
Packit |
c22fc9 |
long weight_sum;
|
|
Packit |
c22fc9 |
long threshold = vs->quorum - vs->hysteresis;
|
|
Packit |
c22fc9 |
bool sav_inhibit;
|
|
Packit |
c22fc9 |
smtp_rs rs_info = { .vs = vs };
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(l, rs, e) {
|
|
Packit |
c22fc9 |
if (rs->set || stopping)
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "%s %sservice %s from VS %s",
|
|
Packit |
c22fc9 |
stopping ? "Shutting down" : "Removing",
|
|
Packit |
c22fc9 |
rs->inhibit && !rs->alive ? "(inhibited) " : "",
|
|
Packit |
c22fc9 |
FMT_RS(rs, vs),
|
|
Packit |
c22fc9 |
FMT_VS(vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!rs->set)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Force removal of real servers with inhibit_on_failure set */
|
|
Packit |
c22fc9 |
sav_inhibit = rs->inhibit;
|
|
Packit |
c22fc9 |
rs->inhibit = false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_DEL_DEST, vs, rs);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
rs->inhibit = sav_inhibit; /* Restore inhibit flag */
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!rs->alive)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
UNSET_ALIVE(rs);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* We always want to send SNMP messages on shutdown */
|
|
Packit |
c22fc9 |
if (!vs->omega && stopping) {
|
|
Packit |
c22fc9 |
#ifdef _WITH_SNMP_CHECKER_
|
|
Packit |
c22fc9 |
check_snmp_rs_trap(rs, vs, true);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* In Omega mode we call VS and RS down notifiers
|
|
Packit |
c22fc9 |
* all the way down the exit, as necessary.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
do_rs_notifies(vs, rs, stopping);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Send SMTP alert */
|
|
Packit |
c22fc9 |
if (rs->smtp_alert) {
|
|
Packit |
c22fc9 |
rs_info.rs = rs;
|
|
Packit |
c22fc9 |
smtp_alert(SMTP_MSG_RS_SHUT, &rs_info, "DOWN", stopping ? "=> Shutting down <=" : "=> Removing <=");
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Sooner or later VS will lose the quorum (if any). However,
|
|
Packit |
c22fc9 |
* we don't push in a sorry server then, hence the regression
|
|
Packit |
c22fc9 |
* is intended.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
weight_sum = weigh_live_realservers(vs);
|
|
Packit |
c22fc9 |
if (stopping ||
|
|
Packit |
c22fc9 |
(vs->quorum_state_up &&
|
|
Packit |
c22fc9 |
(!weight_sum || weight_sum < threshold))) {
|
|
Packit |
c22fc9 |
vs->quorum_state_up = false;
|
|
Packit |
c22fc9 |
do_vs_notifies(vs, false, threshold, weight_sum, stopping);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Remove a virtualserver IPVS rule */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
clear_service_vs(virtual_server_t * vs, bool stopping)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bool sav_inhibit;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Processing real server queue */
|
|
Packit |
c22fc9 |
if (vs->s_svr && vs->s_svr->set) {
|
|
Packit |
c22fc9 |
/* Ensure removed if inhibit_on_failure set */
|
|
Packit |
c22fc9 |
sav_inhibit = vs->s_svr->inhibit;
|
|
Packit |
c22fc9 |
vs->s_svr->inhibit = false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_DEL_DEST, vs, vs->s_svr);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vs->s_svr->inhibit = sav_inhibit;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
UNSET_ALIVE(vs->s_svr);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Even if the sorry server was configured, if we are using
|
|
Packit |
c22fc9 |
* inhibit_on_failure, then real servers may be configured. */
|
|
Packit |
c22fc9 |
clear_service_rs(vs, vs->rs, stopping);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* The above will handle Omega case for VS as well. */
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_DEL, vs, NULL);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
UNSET_ALIVE(vs);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* IPVS cleaner processing */
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
clear_services(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
virtual_server_t *vs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!check_data || !check_data->vs)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(check_data->vs, vs, e) {
|
|
Packit |
c22fc9 |
/* Remove the real servers, and clear the vs unless it is
|
|
Packit |
c22fc9 |
* using a VS group and it is not the last vs of the same
|
|
Packit |
c22fc9 |
* protocol or address family using the group. */
|
|
Packit |
c22fc9 |
clear_service_vs(vs, true);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set a realserver IPVS rules */
|
|
Packit |
c22fc9 |
static bool
|
|
Packit |
c22fc9 |
init_service_rs(virtual_server_t * vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
real_server_t *rs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(vs->rs, rs, e) {
|
|
Packit |
c22fc9 |
if (rs->reloaded) {
|
|
Packit |
c22fc9 |
if (rs->iweight != rs->pweight)
|
|
Packit |
c22fc9 |
update_svr_wgt(rs->iweight, vs, rs, false);
|
|
Packit |
c22fc9 |
/* Do not re-add failed RS instantly on reload */
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* In alpha mode, be pessimistic (or realistic?) and don't
|
|
Packit |
c22fc9 |
* add real servers into the VS pool unless inhibit_on_failure.
|
|
Packit |
c22fc9 |
* They will get there later upon healthchecks recovery (if ever).
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
if ((!rs->num_failed_checkers && !ISALIVE(rs)) ||
|
|
Packit |
c22fc9 |
(rs->inhibit && !rs->set)) {
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_ADD_DEST, vs, rs);
|
|
Packit |
c22fc9 |
if (!rs->num_failed_checkers) {
|
|
Packit |
c22fc9 |
SET_ALIVE(rs);
|
|
Packit |
c22fc9 |
if (global_data->rs_init_notifies)
|
|
Packit |
c22fc9 |
do_rs_notifies(vs, rs, false);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
sync_service_vsg(virtual_server_t * vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
virtual_server_group_t *vsg;
|
|
Packit |
c22fc9 |
virtual_server_group_entry_t *vsge;
|
|
Packit |
c22fc9 |
list *l;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vsg = vs->vsg;
|
|
Packit |
c22fc9 |
list ll[] = {
|
|
Packit |
c22fc9 |
vsg->addr_range,
|
|
Packit |
c22fc9 |
vsg->vfwmark,
|
|
Packit |
c22fc9 |
NULL,
|
|
Packit |
c22fc9 |
};
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (l = ll; *l; l++)
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(*l); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
vsge = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (vs->reloaded && !vsge->reloaded) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "VS [%s:%d:%u] added into group %s"
|
|
Packit |
c22fc9 |
// Does this work with no address?
|
|
Packit |
c22fc9 |
, inet_sockaddrtotrio(&vsge->addr, vs->service_type)
|
|
Packit |
c22fc9 |
, vsge->range
|
|
Packit |
c22fc9 |
, vsge->vfwmark
|
|
Packit |
c22fc9 |
, vs->vsgname);
|
|
Packit |
c22fc9 |
/* add all reloaded and alive/inhibit-set dests
|
|
Packit |
c22fc9 |
* to the newly created vsg item */
|
|
Packit |
c22fc9 |
ipvs_group_sync_entry(vs, vsge);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* add or remove _alive_ real servers from a virtual server */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
perform_quorum_state(virtual_server_t *vs, bool add)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
real_server_t *rs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "%s the pool for VS %s"
|
|
Packit |
c22fc9 |
, add?"Adding alive servers to":"Removing alive servers from"
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
LIST_FOREACH(vs->rs, rs, e) {
|
|
Packit |
c22fc9 |
if (!ISALIVE(rs)) /* We only handle alive servers */
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
// ??? The following seems unnecessary
|
|
Packit |
c22fc9 |
if (add)
|
|
Packit |
c22fc9 |
rs->alive = false;
|
|
Packit |
c22fc9 |
ipvs_cmd(add?LVS_CMD_ADD_DEST:LVS_CMD_DEL_DEST, vs, rs);
|
|
Packit |
c22fc9 |
rs->alive = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
set_quorum_states(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
virtual_server_t *vs;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(check_data->vs))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(check_data->vs); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
vs = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vs->quorum_state_up = (weigh_live_realservers(vs) >= vs->quorum + vs->hysteresis);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* set quorum state depending on current weight of real servers */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
update_quorum_state(virtual_server_t * vs, bool init)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
long weight_sum = weigh_live_realservers(vs);
|
|
Packit |
c22fc9 |
long threshold;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
threshold = vs->quorum + (vs->quorum_state_up ? -1 : 1) * vs->hysteresis;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If we have just gained quorum, it's time to consider notify_up. */
|
|
Packit |
c22fc9 |
if (!vs->quorum_state_up &&
|
|
Packit |
c22fc9 |
weight_sum >= threshold) {
|
|
Packit |
c22fc9 |
vs->quorum_state_up = true;
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Gained quorum %u+%u=%ld <= %ld for VS %s"
|
|
Packit |
c22fc9 |
, vs->quorum
|
|
Packit |
c22fc9 |
, vs->hysteresis
|
|
Packit |
c22fc9 |
, threshold
|
|
Packit |
c22fc9 |
, weight_sum
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
if (vs->s_svr && ISALIVE(vs->s_svr)) {
|
|
Packit |
c22fc9 |
/* Adding back alive real servers */
|
|
Packit |
c22fc9 |
perform_quorum_state(vs, true);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "%s sorry server %s from VS %s"
|
|
Packit |
c22fc9 |
, (vs->s_svr->inhibit ? "Disabling" : "Removing")
|
|
Packit |
c22fc9 |
, FMT_RS(vs->s_svr, vs)
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_DEL_DEST, vs, vs->s_svr);
|
|
Packit |
c22fc9 |
vs->s_svr->alive = false;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
do_vs_notifies(vs, init, threshold, weight_sum, false);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else if ((vs->quorum_state_up &&
|
|
Packit |
c22fc9 |
(!weight_sum || weight_sum < threshold)) ||
|
|
Packit |
c22fc9 |
(init && !vs->quorum_state_up &&
|
|
Packit |
c22fc9 |
vs->s_svr && !ISALIVE(vs->s_svr))) {
|
|
Packit |
c22fc9 |
/* We have just lost quorum for the VS, we need to consider
|
|
Packit |
c22fc9 |
* VS notify_down and sorry_server cases
|
|
Packit |
c22fc9 |
* or
|
|
Packit |
c22fc9 |
* We are starting up and need to add the sorry server
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
vs->quorum_state_up = false;
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "%s %u-%u=%ld > %ld for VS %s"
|
|
Packit |
c22fc9 |
, init ? "Starting with quorum down" : "Lost quorum"
|
|
Packit |
c22fc9 |
, vs->quorum
|
|
Packit |
c22fc9 |
, vs->hysteresis
|
|
Packit |
c22fc9 |
, threshold
|
|
Packit |
c22fc9 |
, weight_sum
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vs->s_svr && !ISALIVE(vs->s_svr)) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "%s sorry server %s to VS %s"
|
|
Packit |
c22fc9 |
, (vs->s_svr->inhibit ? "Enabling" : "Adding")
|
|
Packit |
c22fc9 |
, FMT_RS(vs->s_svr, vs)
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* the sorry server is now up in the pool, we flag it alive */
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_ADD_DEST, vs, vs->s_svr);
|
|
Packit |
c22fc9 |
vs->s_svr->alive = true;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Remove remaining alive real servers */
|
|
Packit |
c22fc9 |
perform_quorum_state(vs, false);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
do_vs_notifies(vs, init, threshold, weight_sum, false);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* manipulate add/remove rs according to alive state */
|
|
Packit |
c22fc9 |
static bool
|
|
Packit |
c22fc9 |
perform_svr_state(bool alive, checker_t *checker)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* | ISALIVE(rs) | alive | context
|
|
Packit |
c22fc9 |
* | false | false | first check failed under alpha mode, unreachable here
|
|
Packit |
c22fc9 |
* | false | true | RS went up, add it to the pool
|
|
Packit |
c22fc9 |
* | true | false | RS went down, remove it from the pool
|
|
Packit |
c22fc9 |
* | true | true | first check succeeded w/o alpha mode, unreachable here
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
virtual_server_t * vs = checker->vs;
|
|
Packit |
c22fc9 |
real_server_t * rs = checker->rs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ISALIVE(rs) == alive)
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "%sing service %s to VS %s"
|
|
Packit |
c22fc9 |
, alive ? (rs->inhibit) ? "Enabl" : "Add" :
|
|
Packit |
c22fc9 |
(rs->inhibit) ? "Disabl" : "Remov"
|
|
Packit |
c22fc9 |
, FMT_RS(rs, vs)
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Change only if we have quorum or no sorry server */
|
|
Packit |
c22fc9 |
if (vs->quorum_state_up || !vs->s_svr || !ISALIVE(vs->s_svr)) {
|
|
Packit |
c22fc9 |
if (ipvs_cmd(alive ? LVS_CMD_ADD_DEST : LVS_CMD_DEL_DEST, vs, rs))
|
|
Packit |
c22fc9 |
return false;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
rs->alive = alive;
|
|
Packit |
c22fc9 |
do_rs_notifies(vs, rs, false);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* We may have changed quorum state. If the quorum wasn't up
|
|
Packit |
c22fc9 |
* but is now up, this is where the rs is added. */
|
|
Packit |
c22fc9 |
update_quorum_state(vs, false);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set a virtualserver IPVS rules */
|
|
Packit |
c22fc9 |
static bool
|
|
Packit |
c22fc9 |
init_service_vs(virtual_server_t * vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
/* Init the VS root */
|
|
Packit |
c22fc9 |
if (!ISALIVE(vs) || vs->vsg) {
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_ADD, vs, NULL);
|
|
Packit |
c22fc9 |
SET_ALIVE(vs);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Processing real server queue */
|
|
Packit |
c22fc9 |
if (!init_service_rs(vs))
|
|
Packit |
c22fc9 |
return false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vs->reloaded && vs->vsgname) {
|
|
Packit |
c22fc9 |
/* add reloaded dests into new vsg entries */
|
|
Packit |
c22fc9 |
sync_service_vsg(vs);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* we may have got/lost quorum due to quorum setting changed */
|
|
Packit |
c22fc9 |
/* also update, in case we need the sorry server in alpha mode */
|
|
Packit |
c22fc9 |
update_quorum_state(vs, true);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If we have a sorry server with inhibit, add it now */
|
|
Packit |
c22fc9 |
if (vs->s_svr && vs->s_svr->inhibit && !vs->s_svr->set) {
|
|
Packit |
c22fc9 |
/* Make sure the sorry server is configured with weight 0 */
|
|
Packit |
c22fc9 |
vs->s_svr->num_failed_checkers = 1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_ADD_DEST, vs, vs->s_svr);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vs->s_svr->num_failed_checkers = 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set IPVS rules */
|
|
Packit |
c22fc9 |
bool
|
|
Packit |
c22fc9 |
init_services(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
virtual_server_t *vs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(check_data->vs, vs, e) {
|
|
Packit |
c22fc9 |
if (!init_service_vs(vs))
|
|
Packit |
c22fc9 |
return false;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Store new weight in real_server struct and then update kernel. */
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
update_svr_wgt(int weight, virtual_server_t * vs, real_server_t * rs
|
|
Packit |
c22fc9 |
, bool update_quorum)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (weight != rs->weight) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Changing weight from %d to %d for %s service %s of VS %s"
|
|
Packit |
c22fc9 |
, rs->weight
|
|
Packit |
c22fc9 |
, weight
|
|
Packit |
c22fc9 |
, ISALIVE(rs) ? "active" : "inactive"
|
|
Packit |
c22fc9 |
, FMT_RS(rs, vs)
|
|
Packit |
c22fc9 |
, FMT_VS(vs));
|
|
Packit |
c22fc9 |
rs->weight = weight;
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Have weight change take effect now only if rs is in
|
|
Packit |
c22fc9 |
* the pool and alive and the quorum is met (or if
|
|
Packit |
c22fc9 |
* there is no sorry server). If not, it will take
|
|
Packit |
c22fc9 |
* effect later when it becomes alive.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
if (rs->set && ISALIVE(rs) &&
|
|
Packit |
c22fc9 |
(vs->quorum_state_up || !vs->s_svr || !ISALIVE(vs->s_svr)))
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_EDIT_DEST, vs, rs);
|
|
Packit |
c22fc9 |
if (update_quorum)
|
|
Packit |
c22fc9 |
update_quorum_state(vs, false);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
set_checker_state(checker_t *checker, bool up)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (checker->is_up == up)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
checker->is_up = up;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!up)
|
|
Packit |
c22fc9 |
checker->rs->num_failed_checkers++;
|
|
Packit |
c22fc9 |
else if (checker->rs->num_failed_checkers)
|
|
Packit |
c22fc9 |
checker->rs->num_failed_checkers--;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Update checker's state */
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
update_svr_checker_state(bool alive, checker_t *checker)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (checker->is_up == alive) {
|
|
Packit |
c22fc9 |
if (!checker->has_run) {
|
|
Packit |
c22fc9 |
if (checker->alpha || !alive)
|
|
Packit |
c22fc9 |
do_rs_notifies(checker->vs, checker->rs, false);
|
|
Packit |
c22fc9 |
checker->has_run = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
checker->has_run = true;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (alive) {
|
|
Packit |
c22fc9 |
/* call the UP handler unless any more failed checks found */
|
|
Packit |
c22fc9 |
if (checker->rs->num_failed_checkers <= 1) {
|
|
Packit |
c22fc9 |
if (!perform_svr_state(true, checker))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
/* Handle not alive state */
|
|
Packit |
c22fc9 |
if (checker->rs->num_failed_checkers == 0) {
|
|
Packit |
c22fc9 |
if (!perform_svr_state(false, checker))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
set_checker_state(checker, alive);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check if a vsg entry is in new data */
|
|
Packit |
c22fc9 |
static virtual_server_group_entry_t *
|
|
Packit |
c22fc9 |
vsge_exist(virtual_server_group_entry_t *vsg_entry, list l)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
virtual_server_group_entry_t *vsge;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
vsge = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (VSGE_ISEQ(vsg_entry, vsge))
|
|
Packit |
c22fc9 |
return vsge;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Clear the diff vsge of old group */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
clear_diff_vsge(list old, list new, virtual_server_t * old_vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
virtual_server_group_entry_t *vsge, *new_vsge;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(old); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
vsge = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
new_vsge = vsge_exist(vsge, new);
|
|
Packit |
c22fc9 |
if (new_vsge) {
|
|
Packit |
c22fc9 |
new_vsge->tcp_alive = vsge->tcp_alive;
|
|
Packit |
c22fc9 |
new_vsge->udp_alive = vsge->udp_alive;
|
|
Packit |
c22fc9 |
new_vsge->sctp_alive = vsge->sctp_alive;
|
|
Packit |
c22fc9 |
new_vsge->fwm4_alive = vsge->fwm4_alive;
|
|
Packit |
c22fc9 |
new_vsge->fwm6_alive = vsge->fwm6_alive;
|
|
Packit |
c22fc9 |
new_vsge->reloaded = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "VS [%s:%d:%u] in group %s no longer exists"
|
|
Packit |
c22fc9 |
, inet_sockaddrtotrio(&vsge->addr, old_vs->service_type)
|
|
Packit |
c22fc9 |
, vsge->range
|
|
Packit |
c22fc9 |
, vsge->vfwmark
|
|
Packit |
c22fc9 |
, old_vs->vsgname);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ipvs_group_remove_entry(old_vs, vsge);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Clear the diff vsg of the old vs */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
clear_diff_vsg(virtual_server_t * old_vs, virtual_server_t * new_vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
virtual_server_group_t *old = old_vs->vsg;
|
|
Packit |
c22fc9 |
virtual_server_group_t *new = new_vs->vsg;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Diff the group entries */
|
|
Packit |
c22fc9 |
clear_diff_vsge(old->addr_range, new->addr_range, old_vs);
|
|
Packit |
c22fc9 |
clear_diff_vsge(old->vfwmark, new->vfwmark, old_vs);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check if a vs exist in new data and returns pointer to it */
|
|
Packit |
c22fc9 |
static virtual_server_t*
|
|
Packit |
c22fc9 |
vs_exist(virtual_server_t * old_vs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
list l = check_data->vs;
|
|
Packit |
c22fc9 |
virtual_server_t *vs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(l))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
vs = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (VS_ISEQ(old_vs, vs))
|
|
Packit |
c22fc9 |
return vs;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check if rs is in new vs data */
|
|
Packit |
c22fc9 |
static real_server_t *
|
|
Packit |
c22fc9 |
rs_exist(real_server_t * old_rs, list l)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
real_server_t *rs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(l))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
rs = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (RS_ISEQ(rs, old_rs))
|
|
Packit |
c22fc9 |
return rs;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
migrate_checkers(real_server_t *old_rs, real_server_t *new_rs, list old_checkers_queue)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
list l;
|
|
Packit |
c22fc9 |
element e, e1;
|
|
Packit |
c22fc9 |
checker_t *old_c, *new_c;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
l = alloc_list(NULL, NULL);
|
|
Packit |
c22fc9 |
LIST_FOREACH(old_checkers_queue, old_c, e) {
|
|
Packit |
c22fc9 |
if (old_c->rs == old_rs)
|
|
Packit |
c22fc9 |
list_add(l, old_c);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(l)) {
|
|
Packit |
c22fc9 |
LIST_FOREACH(checkers_queue, new_c, e) {
|
|
Packit |
c22fc9 |
if (new_c->rs != new_rs || !new_c->compare)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
LIST_FOREACH(l, old_c, e1) {
|
|
Packit |
c22fc9 |
if (old_c->compare == new_c->compare && new_c->compare(old_c, new_c)) {
|
|
Packit |
c22fc9 |
/* Update status if different */
|
|
Packit |
c22fc9 |
if (old_c->is_up != new_c->is_up)
|
|
Packit |
c22fc9 |
set_checker_state(new_c, old_c->is_up);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Transfer some other state flags */
|
|
Packit |
c22fc9 |
new_c->has_run = old_c->has_run;
|
|
Packit |
c22fc9 |
new_c->retry_it = old_c->retry_it;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!new_rs->num_failed_checkers)
|
|
Packit |
c22fc9 |
SET_ALIVE(new_rs);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
free_list(&l);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Clear the diff rs of the old vs */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
clear_diff_rs(virtual_server_t *old_vs, virtual_server_t *new_vs, list old_checkers_queue)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
real_server_t *rs, *new_rs;
|
|
Packit |
c22fc9 |
list rs_to_remove;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If old vs didn't own rs then nothing return */
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(old_vs->rs))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* remove RS from old vs which are not found in new vs */
|
|
Packit |
c22fc9 |
rs_to_remove = alloc_list (NULL, NULL);
|
|
Packit |
c22fc9 |
LIST_FOREACH(old_vs->rs, rs, e) {
|
|
Packit |
c22fc9 |
new_rs = rs_exist(rs, new_vs->rs);
|
|
Packit |
c22fc9 |
if (!new_rs) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "service %s no longer exist"
|
|
Packit |
c22fc9 |
, FMT_RS(rs, old_vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
list_add (rs_to_remove, rs);
|
|
Packit |
c22fc9 |
} else {
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* We reflect the previous alive
|
|
Packit |
c22fc9 |
* flag value to not try to set
|
|
Packit |
c22fc9 |
* already set IPVS rule.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
if (new_rs->alive)
|
|
Packit |
c22fc9 |
new_rs->alive = rs->alive;
|
|
Packit |
c22fc9 |
new_rs->set = rs->set;
|
|
Packit |
c22fc9 |
new_rs->weight = rs->weight;
|
|
Packit |
c22fc9 |
new_rs->pweight = rs->iweight;
|
|
Packit |
c22fc9 |
new_rs->reloaded = true;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* We must migrate the state of the old checkers.
|
|
Packit |
c22fc9 |
* If we do not, the new RS is in a state where it’s reported
|
|
Packit |
c22fc9 |
* as down with no check failed. As a result, the server will never
|
|
Packit |
c22fc9 |
* be put back up when it’s alive again in check_tcp.c#83 because
|
|
Packit |
c22fc9 |
* of the check that put a rs up only if it was not previously up.
|
|
Packit |
c22fc9 |
* For alpha mode checkers, if it was up, we don't need another
|
|
Packit |
c22fc9 |
* success to say it is now up.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
migrate_checkers(rs, new_rs, old_checkers_queue);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
clear_service_rs(old_vs, rs_to_remove, false);
|
|
Packit |
c22fc9 |
free_list(&rs_to_remove);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* clear sorry server, but only if changed */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
clear_diff_s_srv(virtual_server_t *old_vs, real_server_t *new_rs)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
real_server_t *old_rs = old_vs->s_svr;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!old_rs)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (new_rs && RS_ISEQ(old_rs, new_rs)) {
|
|
Packit |
c22fc9 |
/* which fields are really used on s_svr? */
|
|
Packit |
c22fc9 |
new_rs->alive = old_rs->alive;
|
|
Packit |
c22fc9 |
new_rs->set = old_rs->set;
|
|
Packit |
c22fc9 |
new_rs->weight = old_rs->weight;
|
|
Packit |
c22fc9 |
new_rs->pweight = old_rs->iweight;
|
|
Packit |
c22fc9 |
new_rs->reloaded = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
if (old_rs->inhibit) {
|
|
Packit |
c22fc9 |
if (!ISALIVE(old_rs) && old_rs->set)
|
|
Packit |
c22fc9 |
SET_ALIVE(old_rs);
|
|
Packit |
c22fc9 |
old_rs->inhibit = 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
if (ISALIVE(old_rs)) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Removing sorry server %s from VS %s"
|
|
Packit |
c22fc9 |
, FMT_RS(old_rs, old_vs)
|
|
Packit |
c22fc9 |
, FMT_VS(old_vs));
|
|
Packit |
c22fc9 |
ipvs_cmd(LVS_CMD_DEL_DEST, old_vs, old_rs);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* When reloading configuration, remove negative diff entries
|
|
Packit |
c22fc9 |
* and copy status of existing entries to the new ones */
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
clear_diff_services(list old_checkers_queue)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
virtual_server_t *vs, *new_vs;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Remove diff entries from previous IPVS rules */
|
|
Packit |
c22fc9 |
LIST_FOREACH(old_check_data->vs, vs, e) {
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Try to find this vs into the new conf data
|
|
Packit |
c22fc9 |
* reloaded.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
new_vs = vs_exist(vs);
|
|
Packit |
c22fc9 |
if (!new_vs) {
|
|
Packit |
c22fc9 |
if (vs->vsgname)
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Removing Virtual Server Group [%s]", vs->vsgname);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Removing Virtual Server %s", FMT_VS(vs));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Clear VS entry */
|
|
Packit |
c22fc9 |
clear_service_vs(vs, false);
|
|
Packit |
c22fc9 |
} else {
|
|
Packit |
c22fc9 |
/* copy status fields from old VS */
|
|
Packit |
c22fc9 |
SET_ALIVE(new_vs);
|
|
Packit |
c22fc9 |
new_vs->quorum_state_up = vs->quorum_state_up;
|
|
Packit |
c22fc9 |
new_vs->reloaded = true;
|
|
Packit |
c22fc9 |
if (using_ha_suspend)
|
|
Packit |
c22fc9 |
new_vs->ha_suspend_addr_count = vs->ha_suspend_addr_count;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vs->vsgname)
|
|
Packit |
c22fc9 |
clear_diff_vsg(vs, new_vs);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If vs exist, perform rs pool diff */
|
|
Packit |
c22fc9 |
/* omega = false must not prevent the notifiers from being called,
|
|
Packit |
c22fc9 |
because the VS still exists in new configuration */
|
|
Packit |
c22fc9 |
vs->omega = true;
|
|
Packit |
c22fc9 |
clear_diff_rs(vs, new_vs, old_checkers_queue);
|
|
Packit |
c22fc9 |
clear_diff_s_srv(vs, new_vs->s_svr);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
link_vsg_to_vs(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e, e1, next;
|
|
Packit |
c22fc9 |
virtual_server_t *vs;
|
|
Packit |
c22fc9 |
int vsg_af;
|
|
Packit |
c22fc9 |
virtual_server_group_t *vsg;
|
|
Packit |
c22fc9 |
virtual_server_group_entry_t *vsge;
|
|
Packit |
c22fc9 |
unsigned vsg_member_no;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(check_data->vs))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(check_data->vs); e; e = next) {
|
|
Packit |
c22fc9 |
next = e->next;
|
|
Packit |
c22fc9 |
vs = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vs->vsgname) {
|
|
Packit |
c22fc9 |
vs->vsg = ipvs_get_group_by_name(vs->vsgname, check_data->vs_group);
|
|
Packit |
c22fc9 |
if (!vs->vsg) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Virtual server group %s specified but not configured - ignoring virtual server %s", vs->vsgname, FMT_VS(vs));
|
|
Packit |
c22fc9 |
free_vs_checkers(vs);
|
|
Packit |
c22fc9 |
free_list_element(check_data->vs, e);
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check the vsg has some configuration */
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(vs->vsg->addr_range) &&
|
|
Packit |
c22fc9 |
LIST_ISEMPTY(vs->vsg->vfwmark)) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Virtual server group %s has no configuration - ignoring virtual server %s", vs->vsgname, FMT_VS(vs));
|
|
Packit |
c22fc9 |
free_vs_checkers(vs);
|
|
Packit |
c22fc9 |
free_list_element(check_data->vs, e);
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check the vs and vsg address families match */
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vs->vsg->addr_range)) {
|
|
Packit |
c22fc9 |
vsge = ELEMENT_DATA(LIST_HEAD(vs->vsg->addr_range));
|
|
Packit |
c22fc9 |
vsg_af = vsge->addr.ss_family;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
/* fwmark only */
|
|
Packit |
c22fc9 |
vsg_af = AF_UNSPEC;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vsg_af != AF_UNSPEC && vsg_af != vs->af) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Virtual server group %s address family doesn't match virtual server %s - ignoring", vs->vsgname, FMT_VS(vs));
|
|
Packit |
c22fc9 |
free_vs_checkers(vs);
|
|
Packit |
c22fc9 |
free_list_element(check_data->vs, e);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* The virtual server port number is used to identify the sequence number of the virtual server in the group */
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(check_data->vs_group))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(check_data->vs_group); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
vsg_member_no = 0;
|
|
Packit |
c22fc9 |
vsg = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e1 = LIST_HEAD(check_data->vs); e1; ELEMENT_NEXT(e1)) {
|
|
Packit |
c22fc9 |
vs = ELEMENT_DATA(e1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!vs->vsgname)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!strcmp(vs->vsgname, vsg->gname)) {
|
|
Packit |
c22fc9 |
/* We use the IPv4 port since there is no address family */
|
|
Packit |
c22fc9 |
((struct sockaddr_in *)&vs->addr)->sin_port = htons(vsg_member_no);
|
|
Packit |
c22fc9 |
vsg_member_no++;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|