|
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: Interfaces manipulation.
|
|
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 |
/* global include */
|
|
Packit |
c22fc9 |
#include <unistd.h>
|
|
Packit |
c22fc9 |
#include <stdint.h>
|
|
Packit |
c22fc9 |
#include <stdio.h>
|
|
Packit |
c22fc9 |
#include <sys/ioctl.h>
|
|
Packit |
c22fc9 |
#include <errno.h>
|
|
Packit |
c22fc9 |
#include <syslog.h>
|
|
Packit |
c22fc9 |
#include <linux/ip.h>
|
|
Packit |
c22fc9 |
#include <netinet/in.h>
|
|
Packit |
c22fc9 |
#include <stdio.h>
|
|
Packit |
c22fc9 |
#include <linux/mii.h>
|
|
Packit |
c22fc9 |
#if defined _HAVE_NETINET_LINUX_IF_ETHER_H_COLLISION_ && \
|
|
Packit |
c22fc9 |
defined _LINUX_IF_ETHER_H && \
|
|
Packit |
c22fc9 |
!defined _NETINET_IF_ETHER_H
|
|
Packit |
c22fc9 |
/* musl libc throws an error if <linux/if_ether.h> is included before <netinet/if_ether.h>,
|
|
Packit |
c22fc9 |
* so we stop <netinet/if_ether.h> being included if <linux/if_ether.h> has been included. */
|
|
Packit |
c22fc9 |
#define _NETINET_IF_ETHER_H
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#if !HAVE_DECL_SOCK_CLOEXEC
|
|
Packit |
c22fc9 |
#include "old_socket.h"
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#include <linux/sockios.h> /* needed to get correct values for SIOC* */
|
|
Packit |
c22fc9 |
#include <linux/ethtool.h>
|
|
Packit |
c22fc9 |
#include <net/if_arp.h>
|
|
Packit |
c22fc9 |
#include <time.h>
|
|
Packit |
c22fc9 |
#include <linux/filter.h>
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* local include */
|
|
Packit |
c22fc9 |
#include "global_data.h"
|
|
Packit |
c22fc9 |
#include "vrrp.h"
|
|
Packit |
c22fc9 |
#include "vrrp_if.h"
|
|
Packit |
c22fc9 |
#include "vrrp_daemon.h"
|
|
Packit |
c22fc9 |
#include "keepalived_netlink.h"
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
#include "logger.h"
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
#include "vrrp_vmac.h"
|
|
Packit |
c22fc9 |
#include "bitops.h"
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#include "vrrp_track.h"
|
|
Packit |
c22fc9 |
#include "vrrp_scheduler.h"
|
|
Packit |
c22fc9 |
#include "vrrp_iproute.h"
|
|
Packit |
c22fc9 |
#ifdef THREAD_DUMP
|
|
Packit |
c22fc9 |
#include "scheduler.h"
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Local vars */
|
|
Packit |
c22fc9 |
static list if_queue;
|
|
Packit |
c22fc9 |
static struct ifreq ifr;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static list old_garp_delay;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Global vars */
|
|
Packit |
c22fc9 |
list garp_delay;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Helper functions */
|
|
Packit |
c22fc9 |
/* Return interface from interface index */
|
|
Packit |
c22fc9 |
interface_t *
|
|
Packit |
c22fc9 |
if_get_by_ifindex(ifindex_t ifindex)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(if_queue))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
ifp = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
if (ifp->ifindex == ifindex)
|
|
Packit |
c22fc9 |
return ifp;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
interface_t *
|
|
Packit |
c22fc9 |
if_get_by_ifname(const char *ifname, if_lookup_t create)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(if_queue, ifp, e) {
|
|
Packit |
c22fc9 |
if (!strcmp(ifp->ifname, ifname))
|
|
Packit |
c22fc9 |
return ifp;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (create == IF_NO_CREATE ||
|
|
Packit |
c22fc9 |
(create == IF_CREATE_IF_DYNAMIC && (!global_data || !global_data->dynamic_interfaces))) {
|
|
Packit |
c22fc9 |
if (create == IF_CREATE_IF_DYNAMIC)
|
|
Packit |
c22fc9 |
non_existent_interface_specified = true;
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!(ifp = MALLOC(sizeof(interface_t))))
|
|
Packit |
c22fc9 |
return NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
strcpy(ifp->ifname, ifname);
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
ifp->base_ifp = ifp;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
if_add_queue(ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (create == IF_CREATE_IF_DYNAMIC)
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Configuration specifies interface %s which doesn't currently exist - will use if created", ifname);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return ifp;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
/* Set the base_ifp for VMACs and vrf_master_ifp for VRFs - only used at startup */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
set_base_ifp(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRF_
|
|
Packit |
c22fc9 |
interface_t *master_ifp;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(if_queue))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(if_queue, ifp, e) {
|
|
Packit |
c22fc9 |
if (!ifp->base_ifp &&
|
|
Packit |
c22fc9 |
ifp->base_ifindex) {
|
|
Packit |
c22fc9 |
ifp->base_ifp = if_get_by_ifindex(ifp->base_ifindex);
|
|
Packit |
c22fc9 |
ifp->base_ifindex = 0; /* This is only used at startup, so ensure not used later */
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRF_
|
|
Packit |
c22fc9 |
/* Now see if the interface is enslaved to a VRF */
|
|
Packit |
c22fc9 |
if (ifp->vrf_master_ifindex) {
|
|
Packit |
c22fc9 |
master_ifp = if_get_by_ifindex(ifp->vrf_master_ifindex);
|
|
Packit |
c22fc9 |
if (master_ifp && master_ifp->vrf_master_ifp == master_ifp)
|
|
Packit |
c22fc9 |
ifp->vrf_master_ifp = master_ifp;
|
|
Packit |
c22fc9 |
ifp->vrf_master_ifindex = 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Return the interface list itself */
|
|
Packit |
c22fc9 |
list
|
|
Packit |
c22fc9 |
get_if_list(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
return if_queue;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
reset_interface_queue(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
old_garp_delay = garp_delay;
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
garp_delay = NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(if_queue, ifp, e) {
|
|
Packit |
c22fc9 |
ifp->linkbeat_use_polling = false;
|
|
Packit |
c22fc9 |
ifp->garp_delay = NULL;
|
|
Packit |
c22fc9 |
free_list(&ifp->tracking_vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* MII Transceiver Registers poller functions */
|
|
Packit |
c22fc9 |
static uint16_t
|
|
Packit |
c22fc9 |
if_mii_read(int fd, uint16_t phy_id, uint16_t reg_num)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr.ifr_data;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
data->phy_id = phy_id;
|
|
Packit |
c22fc9 |
data->reg_num = reg_num;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ioctl(fd, SIOCGMIIREG, &ifr) < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "SIOCGMIIREG on %s failed: %s", ifr.ifr_name, strerror(errno));
|
|
Packit |
c22fc9 |
return 0xffff;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
return data->val_out;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _INCLUDE_UNUSED_CODE_
|
|
Packit |
c22fc9 |
static void if_mii_dump(const uint16_t *mii_regs, size_t num_regs unsigned phy_id)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int mii_reg;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
printf(" MII PHY #%d transceiver registers:", phy_id);
|
|
Packit |
c22fc9 |
for (mii_reg = 0; mii_reg < num_regs; mii_reg++)
|
|
Packit |
c22fc9 |
printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n ":"", mii_regs[mii_reg]);
|
|
Packit |
c22fc9 |
printf("\n");
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
if_mii_status(const int fd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr.ifr_data;
|
|
Packit |
c22fc9 |
uint16_t phy_id = data->phy_id;
|
|
Packit |
c22fc9 |
uint16_t bmsr, new_bmsr;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (if_mii_read(fd, phy_id, MII_BMCR) == 0xffff ||
|
|
Packit |
c22fc9 |
(bmsr = if_mii_read(fd, phy_id, MII_BMSR)) == 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "No MII transceiver present for %s !!!", ifr.ifr_name);
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// if_mii_dump(mii_regs, sizeof(mii_regs)/ sizeof(mii_regs[0], phy_id);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* For Basic Mode Status Register (BMSR).
|
|
Packit |
c22fc9 |
* Sticky field (Link established & Jabber detected), we need to read
|
|
Packit |
c22fc9 |
* a second time the BMSR to get current status.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
new_bmsr = if_mii_read(fd, phy_id, MII_BMSR);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// printf(" \nBasic Mode Status Register 0x%4.4x ... 0x%4.4x\n", bmsr, new_bmsr);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bmsr & BMSR_LSTATUS)
|
|
Packit |
c22fc9 |
return LINK_UP;
|
|
Packit |
c22fc9 |
else if (new_bmsr & BMSR_LSTATUS)
|
|
Packit |
c22fc9 |
return LINK_UP;
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
return LINK_DOWN;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
if_mii_probe(const char *ifname)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr.ifr_data;
|
|
Packit |
c22fc9 |
uint16_t phy_id;
|
|
Packit |
c22fc9 |
int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
|
Packit |
c22fc9 |
int status;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (fd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#if !HAVE_DECL_SOCK_CLOEXEC
|
|
Packit |
c22fc9 |
if (set_sock_flags(fd, F_SETFD, FD_CLOEXEC))
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Unable to set CLOEXEC on mii_probe socket - %s (%d)", strerror(errno), errno);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
memset(&ifr, 0, sizeof (struct ifreq));
|
|
Packit |
c22fc9 |
strcpy(ifr.ifr_name, ifname);
|
|
Packit |
c22fc9 |
if (ioctl(fd, SIOCGMIIPHY, &ifr) < 0) {
|
|
Packit |
c22fc9 |
close(fd);
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* check if the driver reports BMSR using the MII interface, as we
|
|
Packit |
c22fc9 |
* will need this and we already know that some don't support it.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
phy_id = data->phy_id; /* save it in case it is overwritten */
|
|
Packit |
c22fc9 |
data->reg_num = MII_BMSR;
|
|
Packit |
c22fc9 |
if (ioctl(fd, SIOCGMIIREG, &ifr) < 0) {
|
|
Packit |
c22fc9 |
close(fd);
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
data->phy_id = phy_id;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Dump the MII transceiver */
|
|
Packit |
c22fc9 |
status = if_mii_status(fd);
|
|
Packit |
c22fc9 |
close(fd);
|
|
Packit |
c22fc9 |
return status;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
if_ethtool_status(const int fd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct ethtool_value edata;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
edata.cmd = ETHTOOL_GLINK;
|
|
Packit |
c22fc9 |
ifr.ifr_data = (caddr_t) & edata;
|
|
Packit |
c22fc9 |
if (!ioctl(fd, SIOCETHTOOL, &ifr))
|
|
Packit |
c22fc9 |
return (edata.data) ? 1 : 0;
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
if_ethtool_probe(const char *ifname)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
|
Packit |
c22fc9 |
int status;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (fd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#if !HAVE_DECL_SOCK_CLOEXEC
|
|
Packit |
c22fc9 |
if (set_sock_flags(fd, F_SETFD, FD_CLOEXEC))
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Unable to set CLOEXEC on ethtool_probe socket - %s (%d)", strerror(errno), errno);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
memset(&ifr, 0, sizeof (struct ifreq));
|
|
Packit |
c22fc9 |
strcpy(ifr.ifr_name, ifname);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
status = if_ethtool_status(fd);
|
|
Packit |
c22fc9 |
close(fd);
|
|
Packit |
c22fc9 |
return status;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns false if interface is down */
|
|
Packit |
c22fc9 |
static bool
|
|
Packit |
c22fc9 |
if_ioctl_flags(interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (fd < 0)
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#if !HAVE_DECL_SOCK_CLOEXEC
|
|
Packit |
c22fc9 |
if (set_sock_flags(fd, F_SETFD, FD_CLOEXEC))
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Unable to set CLOEXEC on ioctl_flags socket - %s (%d)", strerror(errno), errno);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
memset(&ifr, 0, sizeof (struct ifreq));
|
|
Packit |
c22fc9 |
strcpy(ifr.ifr_name, ifp->ifname);
|
|
Packit |
c22fc9 |
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
Packit |
c22fc9 |
close(fd);
|
|
Packit |
c22fc9 |
return true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
close(fd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return FLAGS_UP(ifr.ifr_flags);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Interfaces lookup */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
free_if(void *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp = data;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
free_list(&ifp->tracking_vrrp);
|
|
Packit |
c22fc9 |
FREE(data);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* garp_delay facility function */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
free_garp_delay(void *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
FREE(data);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
dump_garp_delay(FILE *fp, void *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
garp_delay_t *gd = data;
|
|
Packit |
c22fc9 |
char time_str[26];
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, "------< GARP delay group %d >------", gd->aggregation_group);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (gd->have_garp_interval) {
|
|
Packit |
c22fc9 |
conf_write(fp, " GARP interval = %g", gd->garp_interval.tv_sec + ((double)gd->garp_interval.tv_usec) / 1000000);
|
|
Packit |
c22fc9 |
if (!ctime_r(&gd->garp_next_time.tv_sec, time_str))
|
|
Packit |
c22fc9 |
strcpy(time_str, "invalid time ");
|
|
Packit |
c22fc9 |
conf_write(fp, " GARP next time %ld.%6.6ld (%.19s.%6.6ld)", gd->garp_next_time.tv_sec, gd->garp_next_time.tv_usec, time_str, gd->garp_next_time.tv_usec);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (gd->have_gna_interval) {
|
|
Packit |
c22fc9 |
conf_write(fp, " GNA interval = %g", gd->gna_interval.tv_sec + ((double)gd->gna_interval.tv_usec) / 1000000);
|
|
Packit |
c22fc9 |
if (!ctime_r(&gd->gna_next_time.tv_sec, time_str))
|
|
Packit |
c22fc9 |
strcpy(time_str, "invalid time ");
|
|
Packit |
c22fc9 |
conf_write(fp, " GNA next time %ld.%6.6ld (%.19s.%6.6ld)", gd->gna_next_time.tv_sec, gd->gna_next_time.tv_usec, time_str, gd->gna_next_time.tv_usec);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else if (!gd->have_garp_interval)
|
|
Packit |
c22fc9 |
conf_write(fp, " No configuration");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " Interfaces");
|
|
Packit |
c22fc9 |
LIST_FOREACH(if_queue, ifp, e) {
|
|
Packit |
c22fc9 |
if (ifp->garp_delay == gd)
|
|
Packit |
c22fc9 |
conf_write(fp, " %s", ifp->ifname);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
alloc_garp_delay(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (!LIST_EXISTS(garp_delay))
|
|
Packit |
c22fc9 |
garp_delay = alloc_list(free_garp_delay, dump_garp_delay);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
list_add(garp_delay, MALLOC(sizeof(garp_delay_t)));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
set_default_garp_delay(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
garp_delay_t default_delay;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
garp_delay_t *delay;
|
|
Packit |
c22fc9 |
vrrp_t *vrrp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (global_data->vrrp_garp_interval) {
|
|
Packit |
c22fc9 |
default_delay.garp_interval.tv_sec = global_data->vrrp_garp_interval / 1000000;
|
|
Packit |
c22fc9 |
default_delay.garp_interval.tv_usec = global_data->vrrp_garp_interval % 1000000;
|
|
Packit |
c22fc9 |
default_delay.have_garp_interval = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
if (global_data->vrrp_gna_interval) {
|
|
Packit |
c22fc9 |
default_delay.gna_interval.tv_sec = global_data->vrrp_gna_interval / 1000000;
|
|
Packit |
c22fc9 |
default_delay.gna_interval.tv_usec = global_data->vrrp_gna_interval % 1000000;
|
|
Packit |
c22fc9 |
default_delay.have_gna_interval = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Allocate a delay structure to each physical interface that doesn't have one and
|
|
Packit |
c22fc9 |
* is being used by a VRRP instance */
|
|
Packit |
c22fc9 |
LIST_FOREACH(vrrp_data->vrrp, vrrp, e) {
|
|
Packit |
c22fc9 |
ifp = IF_BASE_IFP(vrrp->ifp);
|
|
Packit |
c22fc9 |
if (!ifp->garp_delay) {
|
|
Packit |
c22fc9 |
alloc_garp_delay();
|
|
Packit |
c22fc9 |
delay = LIST_TAIL_DATA(garp_delay);
|
|
Packit |
c22fc9 |
*delay = default_delay;
|
|
Packit |
c22fc9 |
ifp->garp_delay = delay;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
dump_if(FILE *fp, void *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp = data;
|
|
Packit |
c22fc9 |
char addr_str[INET6_ADDRSTRLEN];
|
|
Packit |
c22fc9 |
char *mac_buf;
|
|
Packit |
c22fc9 |
size_t mac_buf_len;
|
|
Packit |
c22fc9 |
char *p;
|
|
Packit |
c22fc9 |
size_t i;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " Name = %s", ifp->ifname);
|
|
Packit |
c22fc9 |
conf_write(fp, " index = %u", ifp->ifindex);
|
|
Packit |
c22fc9 |
conf_write(fp, " IPv4 address = %s",
|
|
Packit |
c22fc9 |
ifp->sin_addr.s_addr ? inet_ntop2(ifp->sin_addr.s_addr) : "(none)");
|
|
Packit |
c22fc9 |
inet_ntop(AF_INET6, &ifp->sin6_addr, addr_str, sizeof(addr_str));
|
|
Packit |
c22fc9 |
conf_write(fp, " IPv6 address = %s", ifp->sin6_addr.s6_addr32[0] ? addr_str : "(none)");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ifp->hw_addr_len) {
|
|
Packit |
c22fc9 |
mac_buf_len = 3 * ifp->hw_addr_len;
|
|
Packit |
c22fc9 |
mac_buf = MALLOC(mac_buf_len);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (i = 0, p = mac_buf; i < ifp->hw_addr_len; i++)
|
|
Packit |
c22fc9 |
p += snprintf(p, mac_buf_len - (p - mac_buf), "%.2x%s",
|
|
Packit |
c22fc9 |
ifp->hw_addr[i], i < ifp->hw_addr_len -1 ? ":" : "");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " MAC = %s", mac_buf);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (i = 0, p = mac_buf; i < ifp->hw_addr_len; i++)
|
|
Packit |
c22fc9 |
p += snprintf(p, mac_buf_len - (p - mac_buf), "%.2x%s",
|
|
Packit |
c22fc9 |
ifp->hw_addr_bcast[i], i < ifp->hw_addr_len - 1 ? ":" : "");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " MAC broadcast = %s", mac_buf);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
FREE(mac_buf);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " State = %sUP, %sRUNNING%s%s%s%s%s%s", ifp->ifi_flags & IFF_UP ? "" : "not ", ifp->ifi_flags & IFF_RUNNING ? "" : "not ",
|
|
Packit |
c22fc9 |
!(ifp->ifi_flags & IFF_BROADCAST) ? ", no broadcast" : "",
|
|
Packit |
c22fc9 |
ifp->ifi_flags & IFF_LOOPBACK ? ", loopback" : "",
|
|
Packit |
c22fc9 |
ifp->ifi_flags & IFF_POINTOPOINT ? ", point to point" : "",
|
|
Packit |
c22fc9 |
ifp->ifi_flags & IFF_NOARP ? ", no arp" : "",
|
|
Packit |
c22fc9 |
!(ifp->ifi_flags & IFF_MULTICAST) ? ", no multicast" : "",
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
ifp != ifp->base_ifp && !(ifp->base_ifp->ifi_flags & IFF_UP) ? ", master down" : ""
|
|
Packit |
c22fc9 |
#else
|
|
Packit |
c22fc9 |
""
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
if (ifp->vmac_type && ifp->base_ifp)
|
|
Packit |
c22fc9 |
conf_write(fp, " VMAC type %s, underlying interface = %s, state = %sUP, %sRUNNING",
|
|
Packit |
c22fc9 |
ifp->vmac_type == MACVLAN_MODE_PRIVATE ? "private" :
|
|
Packit |
c22fc9 |
ifp->vmac_type == MACVLAN_MODE_VEPA ? "vepa" :
|
|
Packit |
c22fc9 |
ifp->vmac_type == MACVLAN_MODE_BRIDGE ? "bridge" :
|
|
Packit |
c22fc9 |
#ifdef MACVLAN_MODE_PASSTHRU
|
|
Packit |
c22fc9 |
ifp->vmac_type == MACVLAN_MODE_PASSTHRU ? "passthru" :
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#ifdef MACVLAN_MODE_SOURCE
|
|
Packit |
c22fc9 |
ifp->vmac_type == MACVLAN_MODE_SOURCE ? "source" :
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
"unknown",
|
|
Packit |
c22fc9 |
ifp->base_ifp->ifname,
|
|
Packit |
c22fc9 |
ifp->base_ifp->ifi_flags & IFF_UP ? "" : "not ", ifp->base_ifp->ifi_flags & IFF_RUNNING ? "" : "not ");
|
|
Packit |
c22fc9 |
if (ifp->is_ours)
|
|
Packit |
c22fc9 |
conf_write(fp, " I/f created by keepalived");
|
|
Packit |
c22fc9 |
else if (global_data->allow_if_changes && ifp->changeable_type)
|
|
Packit |
c22fc9 |
conf_write(fp, " Interface type/base can be changed");
|
|
Packit |
c22fc9 |
if (ifp->seen_interface)
|
|
Packit |
c22fc9 |
conf_write(fp, " Done VRID check");
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
conf_write(fp, " MTU = %d", ifp->mtu);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
switch (ifp->hw_type) {
|
|
Packit |
c22fc9 |
case ARPHRD_LOOPBACK:
|
|
Packit |
c22fc9 |
conf_write(fp, " HW Type = LOOPBACK");
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case ARPHRD_ETHER:
|
|
Packit |
c22fc9 |
conf_write(fp, " HW Type = ETHERNET");
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case ARPHRD_INFINIBAND:
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, " HW Type = INFINIBAND");
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
default:
|
|
Packit |
c22fc9 |
conf_write(fp, " HW Type = UNKNOWN (%d)", ifp->hw_type);
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!ifp->linkbeat_use_polling)
|
|
Packit |
c22fc9 |
conf_write(fp, " NIC netlink status update");
|
|
Packit |
c22fc9 |
else if (IF_MII_SUPPORTED(ifp))
|
|
Packit |
c22fc9 |
conf_write(fp, " NIC support MII regs");
|
|
Packit |
c22fc9 |
else if (IF_ETHTOOL_SUPPORTED(ifp))
|
|
Packit |
c22fc9 |
conf_write(fp, " NIC support ETHTOOL GLINK interface");
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
conf_write(fp, " NIC ioctl refresh polling");
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRF_
|
|
Packit |
c22fc9 |
if (ifp->vrf_master_ifp == ifp)
|
|
Packit |
c22fc9 |
conf_write(fp, " VRF master");
|
|
Packit |
c22fc9 |
else if (ifp->vrf_master_ifp)
|
|
Packit |
c22fc9 |
conf_write(fp, " VRF slave of %s", ifp->vrf_master_ifp->ifname);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ifp->garp_delay) {
|
|
Packit |
c22fc9 |
if (ifp->garp_delay->have_garp_interval)
|
|
Packit |
c22fc9 |
conf_write(fp, " Gratuitous ARP interval %ldms",
|
|
Packit |
c22fc9 |
ifp->garp_delay->garp_interval.tv_sec * 100 +
|
|
Packit |
c22fc9 |
ifp->garp_delay->garp_interval.tv_usec / (TIMER_HZ / 100));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ifp->garp_delay->have_gna_interval)
|
|
Packit |
c22fc9 |
conf_write(fp, " Gratuitous NA interval %ldms",
|
|
Packit |
c22fc9 |
ifp->garp_delay->gna_interval.tv_sec * 100 +
|
|
Packit |
c22fc9 |
ifp->garp_delay->gna_interval.tv_usec / (TIMER_HZ / 100));
|
|
Packit |
c22fc9 |
if (ifp->garp_delay->aggregation_group)
|
|
Packit |
c22fc9 |
conf_write(fp, " Gratuitous ARP aggregation group %d", ifp->garp_delay->aggregation_group);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
conf_write(fp, " Reset ARP config counter %d", ifp->reset_arp_config);
|
|
Packit |
c22fc9 |
conf_write(fp, " Original arp_ignore %d", ifp->arp_ignore);
|
|
Packit |
c22fc9 |
conf_write(fp, " Original arp_filter %d", ifp->arp_filter);
|
|
Packit |
c22fc9 |
if (ifp->rp_filter < UINT_MAX)
|
|
Packit |
c22fc9 |
conf_write(fp, " rp_filter %d", ifp->rp_filter);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
conf_write(fp, " Original promote_secondaries %d", ifp->promote_secondaries);
|
|
Packit |
c22fc9 |
conf_write(fp, " Reset promote_secondaries counter %d", ifp->reset_promote_secondaries);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, " Tracking VRRP instances = %d", !LIST_ISEMPTY(ifp->tracking_vrrp) ? LIST_SIZE(ifp->tracking_vrrp) : 0);
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(ifp->tracking_vrrp))
|
|
Packit |
c22fc9 |
dump_list(fp, ifp->tracking_vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
init_if_queue(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if_queue = alloc_list(free_if, dump_if);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
if_add_queue(interface_t * ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
list_add(if_queue, ifp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
if_linkbeat_refresh_thread(thread_t * thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
bool if_up = true, was_up;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
was_up = IF_FLAGS_UP(ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (IF_MII_SUPPORTED(ifp))
|
|
Packit |
c22fc9 |
if_up = if_mii_probe(ifp->ifname);
|
|
Packit |
c22fc9 |
else if (IF_ETHTOOL_SUPPORTED(ifp))
|
|
Packit |
c22fc9 |
if_up = if_ethtool_probe(ifp->ifname);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* update ifp->flags to get the new IFF_RUNNING status.
|
|
Packit |
c22fc9 |
* Some buggy drivers need this...
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
if (if_up)
|
|
Packit |
c22fc9 |
if_up = if_ioctl_flags(ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ifp->ifi_flags = if_up ? IFF_UP | IFF_RUNNING : 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (if_up != was_up) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Linkbeat reports %s %s", ifp->ifname, if_up ? "up" : "down");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
process_if_status_change(ifp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Register next polling thread */
|
|
Packit |
c22fc9 |
thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY);
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
init_interface_linkbeat(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
int status;
|
|
Packit |
c22fc9 |
bool linkbeat_in_use = false;
|
|
Packit |
c22fc9 |
bool if_up;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
ifp = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!ifp->linkbeat_use_polling)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Don't poll an interface that we aren't using */
|
|
Packit |
c22fc9 |
if (!ifp->tracking_vrrp)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
/* netlink messages work for vmacs */
|
|
Packit |
c22fc9 |
if (ifp->vmac_type)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
linkbeat_in_use = true;
|
|
Packit |
c22fc9 |
ifp->ifi_flags = IFF_UP | IFF_RUNNING;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ifp->lb_type = LB_IOCTL;
|
|
Packit |
c22fc9 |
status = if_mii_probe(ifp->ifname);
|
|
Packit |
c22fc9 |
if (status >= 0) {
|
|
Packit |
c22fc9 |
ifp->lb_type = LB_MII;
|
|
Packit |
c22fc9 |
if_up = !!status;
|
|
Packit |
c22fc9 |
} else if ((status = if_ethtool_probe(ifp->ifname)) >= 0) {
|
|
Packit |
c22fc9 |
ifp->lb_type = LB_ETHTOOL;
|
|
Packit |
c22fc9 |
if_up = !!status;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
if_up = true;
|
|
Packit |
c22fc9 |
if (if_up)
|
|
Packit |
c22fc9 |
if_up = if_ioctl_flags(ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ifp->ifi_flags = if_up ? IFF_UP | IFF_RUNNING : 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Register new monitor thread */
|
|
Packit |
c22fc9 |
thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (linkbeat_in_use)
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Using MII-BMSR/ETHTOOL NIC polling thread...");
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Interface queue helpers*/
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
free_interface_queue(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
free_list(&if_queue);
|
|
Packit |
c22fc9 |
free_list(&garp_delay);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
free_old_interface_queue(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
free_list(&old_garp_delay);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
init_interface_queue(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
init_if_queue();
|
|
Packit |
c22fc9 |
netlink_interface_lookup(NULL);
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
/* Since we are reading all the interfaces, we might have received details of
|
|
Packit |
c22fc9 |
* a vmac/vrf before the underlying interface, so now we need to ensure the
|
|
Packit |
c22fc9 |
* interface pointers are all set */
|
|
Packit |
c22fc9 |
set_base_ifp();
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
// dump_list(NULL, if_queue);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_join_vrrp_group(sa_family_t family, int *sd, interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct ip_mreqn imr;
|
|
Packit |
c22fc9 |
struct ipv6_mreq imr6;
|
|
Packit |
c22fc9 |
int ret = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* -> outbound processing option
|
|
Packit |
c22fc9 |
* join the multicast group.
|
|
Packit |
c22fc9 |
* binding the socket to the interface for outbound multicast
|
|
Packit |
c22fc9 |
* traffic.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (family == AF_INET) {
|
|
Packit |
c22fc9 |
memset(&imr, 0, sizeof(imr));
|
|
Packit |
c22fc9 |
imr.imr_multiaddr = global_data->vrrp_mcast_group4.sin_addr;
|
|
Packit |
c22fc9 |
imr.imr_ifindex = (int)IF_INDEX(ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* -> Need to handle multicast convergance after takeover.
|
|
Packit |
c22fc9 |
* We retry until multicast is available on the interface.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
|
Packit |
c22fc9 |
(char *) &imr, (socklen_t)sizeof(struct ip_mreqn));
|
|
Packit |
c22fc9 |
} else {
|
|
Packit |
c22fc9 |
memset(&imr6, 0, sizeof(imr6));
|
|
Packit |
c22fc9 |
imr6.ipv6mr_multiaddr = global_data->vrrp_mcast_group6.sin6_addr;
|
|
Packit |
c22fc9 |
imr6.ipv6mr_interface = IF_INDEX(ifp);
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
|
|
Packit |
c22fc9 |
(char *) &imr6, (socklen_t)sizeof(struct ipv6_mreq));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "(%s) cant do IP%s_ADD_MEMBERSHIP errno=%s (%d)",
|
|
Packit |
c22fc9 |
ifp->ifname, (family == AF_INET) ? "" : "v6", strerror(errno), errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_leave_vrrp_group(sa_family_t family, int sd, interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct ip_mreqn imr;
|
|
Packit |
c22fc9 |
struct ipv6_mreq imr6;
|
|
Packit |
c22fc9 |
int ret = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If fd is -1 then we add a membership trouble */
|
|
Packit |
c22fc9 |
if (sd < 0 || !ifp)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Leaving the VRRP multicast group */
|
|
Packit |
c22fc9 |
if (family == AF_INET) {
|
|
Packit |
c22fc9 |
memset(&imr, 0, sizeof(imr));
|
|
Packit |
c22fc9 |
imr.imr_multiaddr = global_data->vrrp_mcast_group4.sin_addr;
|
|
Packit |
c22fc9 |
imr.imr_ifindex = (int)IF_INDEX(ifp);
|
|
Packit |
c22fc9 |
ret = setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
|
|
Packit |
c22fc9 |
(char *) &imr, sizeof(imr));
|
|
Packit |
c22fc9 |
} else {
|
|
Packit |
c22fc9 |
memset(&imr6, 0, sizeof(imr6));
|
|
Packit |
c22fc9 |
imr6.ipv6mr_multiaddr = global_data->vrrp_mcast_group6.sin6_addr;
|
|
Packit |
c22fc9 |
imr6.ipv6mr_interface = IF_INDEX(ifp);
|
|
Packit |
c22fc9 |
ret = setsockopt(sd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
|
|
Packit |
c22fc9 |
(char *) &imr6, sizeof(struct ipv6_mreq));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "(%s) cant do IP%s_DROP_MEMBERSHIP errno=%s (%d)",
|
|
Packit |
c22fc9 |
ifp->ifname, (family == AF_INET) ? "" : "V6", strerror(errno), errno);
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_bindtodevice(int *sd, interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* -> inbound processing option
|
|
Packit |
c22fc9 |
* Specify the bound_dev_if.
|
|
Packit |
c22fc9 |
* why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set
|
|
Packit |
c22fc9 |
* sk->bound_dev_if themself ??? !!!
|
|
Packit |
c22fc9 |
* Needed for filter multicasted advert per interface.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* -- If you read this !!! and know the answer to the question
|
|
Packit |
c22fc9 |
* please feel free to answer me ! :)
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, IF_NAME(ifp), (socklen_t)strlen(IF_NAME(ifp)) + 1);
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "can't bind to device %s. errno=%d. (try to run it as root)",
|
|
Packit |
c22fc9 |
IF_NAME(ifp), errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_hdrincl(int *sd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
int on = 1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Include IP header into RAW protocol packet */
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set HDRINCL IP option. errno=%d (%m)", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_ipv6_checksum(int *sd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
int offset = 6;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!sd && *sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set IPV6_CHECKSUM IP option. errno=%d (%m)", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#if HAVE_DECL_IP_MULTICAST_ALL /* Since Linux 2.6.31 */
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_mcast_all(sa_family_t family, int *sd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
unsigned char no = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (family == AF_INET6)
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Don't accept multicast packets we haven't requested */
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IP, IP_MULTICAST_ALL, &no, sizeof(no));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set IP_MULTICAST_ALL IP option. errno=%d (%m)",
|
|
Packit |
c22fc9 |
errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_mcast_loop(sa_family_t family, int *sd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
unsigned char loop = 0;
|
|
Packit |
c22fc9 |
int loopv6 = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set Multicast loop */
|
|
Packit |
c22fc9 |
if (family == AF_INET)
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loopv6, sizeof(loopv6));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set IP%s_MULTICAST_LOOP IP option. errno=%d (%m)",
|
|
Packit |
c22fc9 |
(family == AF_INET) ? "" : "V6", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_mcast_hops(sa_family_t family, int *sd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
int hops = 255;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Not applicable for IPv4 */
|
|
Packit |
c22fc9 |
if (*sd < 0 || family == AF_INET)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set HOP limit */
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set IPV6_MULTICAST_HOPS IP option. errno=%d (%m)", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_mcast_if(sa_family_t family, int *sd, interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
ifindex_t ifindex;
|
|
Packit |
c22fc9 |
int int_ifindex;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set interface for sending outbound datagrams */
|
|
Packit |
c22fc9 |
ifindex = IF_INDEX(ifp);
|
|
Packit |
c22fc9 |
if ( family == AF_INET)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct ip_mreqn imr;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
memset(&imr, 0, sizeof(imr));
|
|
Packit |
c22fc9 |
imr.imr_ifindex = (int)IF_INDEX(ifp);
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IP, IP_MULTICAST_IF, &imr, sizeof(imr));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
int_ifindex = (int)ifindex;
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &int_ifindex, sizeof(int_ifindex));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set IP%s_MULTICAST_IF IP option. errno=%d (%m)", (family == AF_INET) ? "" : "V6", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_priority(int *sd, int family)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
int val;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set PRIORITY for VRRP traffic */
|
|
Packit |
c22fc9 |
if (family == AF_INET) {
|
|
Packit |
c22fc9 |
val = IPTOS_PREC_INTERNETCONTROL;
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IP, IP_TOS, &val, sizeof(val));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
/* set tos to internet network control */
|
|
Packit |
c22fc9 |
val = 0xc0; /* 192, which translates to DCSP value 48, or cs6 */
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "can't set %s option. errno=%d (%m)", (family == AF_INET) ? "IP_TOS" : "IPV6_TCLASS", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_rcvbuf(int *sd, int val)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* rcvbuf option */
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "cant set SO_RCVBUF IP option. errno=%d (%m)", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
if_setsockopt_no_receive(int *sd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
struct sock_filter bpfcode[1] = {
|
|
Packit |
c22fc9 |
{0x06, 0, 0, 0}, /* ret #0 - means that all packets will be filtered out */
|
|
Packit |
c22fc9 |
};
|
|
Packit |
c22fc9 |
struct sock_fprog bpf = {1, bpfcode};
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (*sd < 0)
|
|
Packit |
c22fc9 |
return -1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ret = setsockopt(*sd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
|
|
Packit |
c22fc9 |
if (ret < 0) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Can't set SO_ATTACH_FILTER option. errno=%d (%m)", errno);
|
|
Packit |
c22fc9 |
close(*sd);
|
|
Packit |
c22fc9 |
*sd = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return *sd;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
interface_up(interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
/* We need to re-add static addresses and static routes */
|
|
Packit |
c22fc9 |
static_track_reinstate_config(ifp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
interface_down(interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
element e, e1;
|
|
Packit |
c22fc9 |
vrrp_t *vrrp;
|
|
Packit |
c22fc9 |
ip_route_t *route;
|
|
Packit |
c22fc9 |
bool route_found;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Unfortunately the kernel doesn't send RTM_DELROUTE for userspace added
|
|
Packit |
c22fc9 |
* routes that are deleted when the link goes down (?kernel bug). */
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(vrrp_data->vrrp, vrrp, e) {
|
|
Packit |
c22fc9 |
if (vrrp->state != VRRP_STATE_MAST)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
route_found = false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(vrrp->vroutes, route, e1) {
|
|
Packit |
c22fc9 |
if (!route->set)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Any route that has an oif will be tracking the interface,
|
|
Packit |
c22fc9 |
* so we only need to check for routes that dont specify an
|
|
Packit |
c22fc9 |
* oif */
|
|
Packit Service |
ada993 |
if (!route->oif && route->configured_ifindex != ifp->ifindex)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
route->set = false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (route->dont_track)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
route_found = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (route_found) {
|
|
Packit |
c22fc9 |
/* Bring down vrrp instance/sync group */
|
|
Packit |
c22fc9 |
down_instance(vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_FIB_ROUTING_
|
|
Packit |
c22fc9 |
/* Now check the static routes */
|
|
Packit |
c22fc9 |
LIST_FOREACH(vrrp_data->static_routes, route, e) {
|
|
Packit |
c22fc9 |
if (route->set && route->oif == ifp) {
|
|
Packit |
c22fc9 |
/* This route will have been deleted */
|
|
Packit |
c22fc9 |
route->set = false;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
cleanup_lost_interface(interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
vrrp_t *vrrp;
|
|
Packit |
c22fc9 |
tracking_vrrp_t *tvp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(ifp->tracking_vrrp, tvp, e) {
|
|
Packit |
c22fc9 |
vrrp = tvp->vrrp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If this is just a tracking interface, we don't need to do anything */
|
|
Packit |
c22fc9 |
if (vrrp->ifp != ifp && IF_BASE_IFP(vrrp->ifp) != ifp && VRRP_CONFIGURED_IFP(vrrp) != ifp)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If the vrrp instance's interface doesn't exist, skip it */
|
|
Packit |
c22fc9 |
if (!vrrp->ifp->ifindex)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
/* If vmac going, clear VMAC_UP_BIT on vrrp instance */
|
|
Packit |
c22fc9 |
if (vrrp->ifp->is_ours)
|
|
Packit |
c22fc9 |
__clear_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vrrp->configured_ifp == ifp &&
|
|
Packit |
c22fc9 |
vrrp->configured_ifp->base_ifp == vrrp->ifp->base_ifp &&
|
|
Packit |
c22fc9 |
vrrp->ifp->is_ours) {
|
|
Packit |
c22fc9 |
/* This is a changeable interface that the vrrp instance
|
|
Packit |
c22fc9 |
* was configured on. Delete the macvlan we created */
|
|
Packit |
c22fc9 |
netlink_link_del_vmac(vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vrrp->configured_ifp == ifp &&
|
|
Packit |
c22fc9 |
vrrp->configured_ifp->base_ifp != vrrp->configured_ifp)
|
|
Packit |
c22fc9 |
del_vrrp_from_interface(vrrp, vrrp->configured_ifp->base_ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If the interface type can be changed, and the vrrp had a
|
|
Packit |
c22fc9 |
* duplicate VRID, clear the error since when the underlying
|
|
Packit |
c22fc9 |
* interface is created again, it may be on another underlying
|
|
Packit |
c22fc9 |
* interface, and there may not be a duplicate VRID. */
|
|
Packit |
c22fc9 |
if (global_data->allow_if_changes &&
|
|
Packit |
c22fc9 |
ifp->changeable_type &&
|
|
Packit |
c22fc9 |
vrrp->configured_ifp == ifp &&
|
|
Packit |
c22fc9 |
vrrp->duplicate_vrid_fault) {
|
|
Packit |
c22fc9 |
vrrp->duplicate_vrid_fault = false;
|
|
Packit |
c22fc9 |
vrrp->num_script_if_fault--;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Find the sockpool entry. If none, then we have closed the socket */
|
|
Packit |
c22fc9 |
if (vrrp->sockets->fd_in != -1) {
|
|
Packit |
c22fc9 |
thread_cancel_read(master, vrrp->sockets->fd_in);
|
|
Packit |
c22fc9 |
close(vrrp->sockets->fd_in);
|
|
Packit |
c22fc9 |
vrrp->sockets->fd_in = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
if (vrrp->sockets->fd_out != -1) {
|
|
Packit |
c22fc9 |
close(vrrp->sockets->fd_out);
|
|
Packit |
c22fc9 |
vrrp->sockets->fd_out = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
vrrp->sockets->ifp->ifindex = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (IF_ISUP(ifp))
|
|
Packit |
c22fc9 |
down_instance(vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
interface_down(ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ifp->ifindex = 0;
|
|
Packit |
c22fc9 |
ifp->ifi_flags = 0;
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
if (!ifp->is_ours)
|
|
Packit |
c22fc9 |
ifp->base_ifp = ifp;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRF_
|
|
Packit |
c22fc9 |
ifp->vrf_master_ifp = NULL;
|
|
Packit |
c22fc9 |
ifp->vrf_master_ifindex = 0;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
setup_interface(vrrp_t *vrrp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
interface_t *ifp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
/* If the vrrp instance uses a vmac, and that vmac i/f doesn't
|
|
Packit |
c22fc9 |
* exist, then create it */
|
|
Packit |
c22fc9 |
if (__test_bit(VRRP_VMAC_BIT, &vrrp->vmac_flags) &&
|
|
Packit |
c22fc9 |
!vrrp->ifp->ifindex) {
|
|
Packit |
c22fc9 |
if (!netlink_link_add_vmac(vrrp))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
if (__test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->vmac_flags))
|
|
Packit |
c22fc9 |
ifp = vrrp->ifp->base_ifp;
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
ifp = vrrp->ifp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Find the sockpool entry. If none, then we open the socket */
|
|
Packit |
c22fc9 |
if (vrrp->sockets->fd_in == -1) {
|
|
Packit |
c22fc9 |
vrrp->sockets->fd_in = open_vrrp_read_socket(vrrp->sockets->family, vrrp->sockets->proto,
|
|
Packit |
c22fc9 |
ifp, vrrp->sockets->unicast, vrrp->sockets->rx_buf_size);
|
|
Packit |
c22fc9 |
if (vrrp->sockets->fd_in == -1)
|
|
Packit |
c22fc9 |
vrrp->sockets->fd_out = -1;
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
vrrp->sockets->fd_out = open_vrrp_send_socket(vrrp->sockets->family, vrrp->sockets->proto,
|
|
Packit |
c22fc9 |
ifp, vrrp->sockets->unicast);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vrrp->sockets->ifp = vrrp->ifp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vrrp_initialised) {
|
|
Packit |
c22fc9 |
vrrp->state = vrrp->num_script_if_fault ? VRRP_STATE_FAULT : VRRP_STATE_BACK;
|
|
Packit |
c22fc9 |
vrrp_init_instance_sands(vrrp);
|
|
Packit |
c22fc9 |
vrrp_thread_add_read(vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
recreate_vmac_thread(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
vrrp_t *vrrp;
|
|
Packit |
c22fc9 |
tracking_vrrp_t *tvp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
interface_t *ifp = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(ifp->tracking_vrrp))
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(ifp->tracking_vrrp, tvp, e) {
|
|
Packit |
c22fc9 |
vrrp = tvp->vrrp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If this isn't the vrrp's interface, skip */
|
|
Packit |
c22fc9 |
if (vrrp->ifp != ifp)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!__test_bit(VRRP_VMAC_BIT, &vrrp->vmac_flags))
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Don't attempt to create the VMAC if the configured
|
|
Packit |
c22fc9 |
* interface doesn't exist */
|
|
Packit |
c22fc9 |
if (!VRRP_CONFIGURED_IFP(vrrp)->ifindex)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
netlink_error_ignore = ENODEV;
|
|
Packit |
c22fc9 |
setup_interface(vrrp);
|
|
Packit |
c22fc9 |
netlink_error_ignore = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
update_added_interface(interface_t *ifp)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
vrrp_t *vrrp;
|
|
Packit |
c22fc9 |
tracking_vrrp_t *tvp;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
vrrp_t *vrrp1;
|
|
Packit |
c22fc9 |
tracking_vrrp_t *tvp1;
|
|
Packit |
c22fc9 |
element e1;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(ifp->tracking_vrrp))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
LIST_FOREACH(ifp->tracking_vrrp, tvp, e) {
|
|
Packit |
c22fc9 |
vrrp = tvp->vrrp;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
/* If this interface is a macvlan that we haven't created,
|
|
Packit |
c22fc9 |
* and the interface type can be changed or we haven't checked
|
|
Packit |
c22fc9 |
* this interface before, make sure that there is not VRID
|
|
Packit |
c22fc9 |
* conflict. */
|
|
Packit |
c22fc9 |
if (!ifp->is_ours &&
|
|
Packit |
c22fc9 |
(global_data->allow_if_changes || !ifp->seen_interface)) {
|
|
Packit |
c22fc9 |
LIST_FOREACH(ifp->base_ifp->tracking_vrrp, tvp1, e1) {
|
|
Packit |
c22fc9 |
vrrp1 = tvp1->vrrp;
|
|
Packit |
c22fc9 |
if (vrrp == vrrp1)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!VRRP_CONFIGURED_IFP(vrrp1)->ifindex)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (IF_BASE_IFP(VRRP_CONFIGURED_IFP(vrrp)) == IF_BASE_IFP(VRRP_CONFIGURED_IFP(vrrp1)) &&
|
|
Packit |
c22fc9 |
vrrp->family == vrrp1->family &&
|
|
Packit |
c22fc9 |
vrrp->vrid == vrrp1->vrid) {
|
|
Packit |
c22fc9 |
vrrp->num_script_if_fault++;
|
|
Packit |
c22fc9 |
vrrp->duplicate_vrid_fault = true;
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "VRID conflict between %s and %s IPv%d vrid %d",
|
|
Packit |
c22fc9 |
vrrp->iname, vrrp1->iname, vrrp->family == AF_INET ? 4 : 6, vrrp->vrid);
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ifp->vmac_type && tvp->type & TRACK_VRRP) {
|
|
Packit |
c22fc9 |
add_vrrp_to_interface(vrrp, ifp->base_ifp, tvp->weight, false, TRACK_VRRP_DYNAMIC);
|
|
Packit |
c22fc9 |
if (!IF_ISUP(vrrp->configured_ifp->base_ifp) && !vrrp->dont_track_primary)
|
|
Packit |
c22fc9 |
vrrp->num_script_if_fault++;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* We might be the configured interface for a vrrp instance that itself uses
|
|
Packit |
c22fc9 |
* a macvlan. If so, we can create the macvlans */
|
|
Packit |
c22fc9 |
if (__test_bit(VRRP_VMAC_BIT, &vrrp->vmac_flags) &&
|
|
Packit |
c22fc9 |
vrrp->configured_ifp == ifp &&
|
|
Packit |
c22fc9 |
!vrrp->ifp->ifindex)
|
|
Packit |
c22fc9 |
thread_add_event(master, recreate_vmac_thread, vrrp->ifp, 0);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If this is just a tracking interface, we don't need to do anything */
|
|
Packit |
c22fc9 |
if (vrrp->ifp != ifp && IF_BASE_IFP(vrrp->ifp) != ifp)
|
|
Packit |
c22fc9 |
continue;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Reopen any socket on this interface if necessary */
|
|
Packit |
c22fc9 |
if (
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
!__test_bit(VRRP_VMAC_BIT, &vrrp->vmac_flags) &&
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
vrrp->sockets->fd_in == -1)
|
|
Packit |
c22fc9 |
setup_interface(vrrp);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
ifp->seen_interface = true;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef THREAD_DUMP
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
register_vrrp_if_addresses(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
register_thread_address("if_linkbeat_refresh_thread", if_linkbeat_refresh_thread);
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
register_thread_address("recreate_vmac_thread", recreate_vmac_thread);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|