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:        Tracking static addresses/routes/rules framework.
 *
 * Author:      Quentin Armitage, <quentin@armitage.org.uk>
 *
 *              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) 2018-2018 Alexandre Cassen, <acassen@gmail.com>
 */

#include "config.h"

/* local include */
#include "vrrp_data.h"
#include "vrrp.h"
#include "vrrp_sync.h"
#include "logger.h"
#include "vrrp_static_track.h"
#include "vrrp_ipaddress.h"
#include "vrrp_track.h"
#if _HAVE_FIB_ROUTING_
#include "vrrp_iproute.h"
#include "vrrp_iprule.h"
#endif

void
free_tgroup(void *data)
{
	static_track_group_t *tgroup = data;

	if (tgroup->iname) {
		log_message(LOG_INFO, "track group %s - iname vector exists when freeing group", tgroup->gname);
		free_strvec(tgroup->iname);
	}
	FREE(tgroup->gname);
	free_list(&tgroup->vrrp_instances);
	FREE(tgroup);
}

void
dump_tgroup(FILE *fp, void *data)
{
	static_track_group_t *tgroup = data;
	vrrp_t *vrrp;
	element e;

	conf_write(fp, " Static Track Group = %s", tgroup->gname);
	if (tgroup->vrrp_instances) {
		conf_write(fp, "   VRRP member instances = %d", LIST_SIZE(tgroup->vrrp_instances));
		LIST_FOREACH(tgroup->vrrp_instances, vrrp, e)
			conf_write(fp, "     %s", vrrp->iname);
	}
}

static_track_group_t *
find_track_group(const char *gname)
{
	element e;
	static_track_group_t *tg;

	LIST_FOREACH(vrrp_data->static_track_groups, tg, e)
		if (!strcmp(gname, tg->gname))
			return tg;

	return NULL;
}

static void
static_track_set_group(static_track_group_t *tgroup)
{
	vrrp_t *vrrp;
	char *str;
	unsigned int i;

	/* Can't handle no members of the group */
	if (!tgroup->iname)
		return;

	tgroup->vrrp_instances = alloc_list(NULL, NULL);

	for (i = 0; i < vector_size(tgroup->iname); i++) {
		str = vector_slot(tgroup->iname, i);
		vrrp = vrrp_get_instance(str);
		if (!vrrp) {
			log_message(LOG_INFO, "vrrp instance %s specified in track group %s doesn't exist - ignoring", str, tgroup->gname);
			continue;
		}

		list_add(tgroup->vrrp_instances, vrrp);
	}

	/* The iname vector is only used for us to set up the sync groups, so delete it */
	free_strvec(tgroup->iname);
	tgroup->iname = NULL;
}

void
static_track_group_init(void)
{
	static_track_group_t *tg;
	vrrp_t *vrrp;
	ip_address_t *addr;
#if _HAVE_FIB_ROUTING_
	ip_route_t *route;
	ip_rule_t *rule;
#endif
	element e, e1, next;

	LIST_FOREACH_NEXT(vrrp_data->static_track_groups, tg, e, next) {
		if (!tg->iname) {
                        log_message(LOG_INFO, "Static track group %s has no virtual router(s) - removing", tg->gname);
                        free_list_element(vrrp_data->static_track_groups, e);
                        continue;
                }

		static_track_set_group(tg);

		if (!tg->vrrp_instances) {
                        free_list_element(vrrp_data->static_track_groups, e);
                        continue;
                }
	}

	/* Add the tracking vrrps to track the interface of each tracked address */
	LIST_FOREACH(vrrp_data->static_addresses, addr, e) {
		if (!addr->track_group)
			continue;
		if (addr->dont_track) {
			log_message(LOG_INFO, "Static address has both track_group and no_track set - not tracking");
			continue;
		}

		LIST_FOREACH(addr->track_group->vrrp_instances, vrrp, e1)
			add_vrrp_to_interface(vrrp, addr->ifp, 0, false, TRACK_SADDR);
	}

#if _HAVE_FIB_ROUTING_
	/* Add the tracking vrrps to track the interface of each tracked address */
	LIST_FOREACH(vrrp_data->static_routes, route, e) {
		if (!route->track_group)
			continue;
		if (route->dont_track) {
			log_message(LOG_INFO, "Static route has both track_group and no_track set - not tracking");
			continue;
		}

		LIST_FOREACH(route->track_group->vrrp_instances, vrrp, e1) {
			if (route->oif)
				add_vrrp_to_interface(vrrp, route->oif, 0, false, TRACK_SROUTE);
		}
	}

	LIST_FOREACH(vrrp_data->static_rules, rule, e) {
		if (!rule->track_group)
			continue;
		if (rule->dont_track) {
			log_message(LOG_INFO, "Static rule has both track_group and no_track set - not tracking");
			continue;
		}

		LIST_FOREACH(rule->track_group->vrrp_instances, vrrp, e1) {
			if (rule->iif)
				add_vrrp_to_interface(vrrp, rule->iif, 0, false, TRACK_SRULE);
		}
	}
#endif
}

void
static_track_reinstate_config(interface_t *ifp)
{
	ip_address_t *addr;
#if _HAVE_FIB_ROUTING_
	ip_route_t *route;
/*	ip_rule_t *rule; */
#endif
	element e;

	LIST_FOREACH(vrrp_data->static_addresses, addr, e) {
		if (addr->dont_track)
			continue;
		if (addr->ifp != ifp)
			continue;
		reinstate_static_address(addr);
	}

#if _HAVE_FIB_ROUTING_
	/* Add the tracking vrrps to track the interface of each tracked address */
	LIST_FOREACH(vrrp_data->static_routes, route, e) {
		if (route->dont_track)
			continue;
		if (route->oif != ifp)
			continue;
		reinstate_static_route(route);
	}

	/* Rules don't get deleted on interface deletion, so we don't need to do anything for them
	LIST_FOREACH(vrrp_data->static_rules, rule, e) {
		if (rule->dont_track)
			continue;
		if (rule->iif != ifp)
			continue;
		reinstate_static_route(route);
	}
	*/
#endif
}