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:        vrrp_if.c include file.
 *
 * Author:      Alexandre Cassen, <acassen@linux-vs.org>
 *
 *              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) 2001-2017 Alexandre Cassen, <acassen@gmail.com>
 */

#ifndef _VRRP_IF_H
#define _VRRP_IF_H

#include "config.h"

/* global includes */
#include <netinet/in.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <net/if.h>
#include <stdio.h>
#ifdef _HAVE_NET_LINUX_IF_H_COLLISION_
#define _LINUX_IF_H
#endif
#include <linux/netdevice.h>
#ifdef _HAVE_VRRP_VMAC_
#include <linux/if_link.h>
#endif

/* local includes */
#include "scheduler.h"
#include "list.h"
#include "timer.h"

#define LINK_UP   1
#define LINK_DOWN 0
#define POLLING_DELAY TIMER_HZ

/* Interface Linkbeat code selection */
#define LB_IOCTL   0x1
#define LB_MII     0x2
#define LB_ETHTOOL 0x4

/* I don't know what the correct type is.
 * The kernel has ifindex in the range [1, INT_MAX], but IFLA_LINK is defined
 * to be __u32. See dev_new_index() in net/core/dev.c and net/core/rtnetlink.c.
 * ifaddrmsg.ifa_index (See /usr/include/linux/if_addr.h> is __u32.
 * /usr/include/linux/rtnetlink.h has them as ints.
 * RTA_OIF and RTA_IIF are u32.
 * RFC2553 defines sin6_scopeid to be a uint32_t, and it can hold an ifindex */
typedef uint32_t ifindex_t;

/* Structure for delayed sending of gratuitous ARP/NA messages */
typedef struct _garp_delay {
	timeval_t		garp_interval;		/* Delay between sending gratuitous ARP messages on an interface */
	bool			have_garp_interval;	/* True if delay */
	timeval_t		gna_interval;		/* Delay between sending gratuitous NA messages on an interface */
	bool			have_gna_interval;	/* True if delay */
	timeval_t		garp_next_time;		/* Time when next gratuitous ARP message can be sent */
	timeval_t		gna_next_time;		/* Time when next gratuitous NA message can be sent */
	int			aggregation_group;	/* Index of multi-interface group */
} garp_delay_t;

/* Interface structure definition */
typedef struct _interface {
	char			ifname[IFNAMSIZ];	/* Interface name */
	ifindex_t		ifindex;		/* Interface index */
	struct in_addr		sin_addr;		/* IPv4 primary IPv4 address */
	struct in6_addr		sin6_addr;		/* IPv6 link address */
	unsigned		ifi_flags;		/* Kernel flags */
	bool			linkbeat_use_polling;	/* Poll the interface for status, rather than use netlink */
	uint32_t		mtu;			/* MTU for this interface_t */
	unsigned short		hw_type;		/* Type of hardware address */
	u_char			hw_addr[MAX_ADDR_LEN];	/* MAC address */
	u_char			hw_addr_bcast[MAX_ADDR_LEN]; /* broadcast address */
	size_t			hw_addr_len;		/* MAC addresss length */
	int			lb_type;		/* Interface regs selection */
#ifdef _HAVE_VRRP_VMAC_
	int			vmac_type;		/* Set if interface is a VMAC interface */
	ifindex_t		base_ifindex;		/* Only used at startup if we find vmac i/f before base i/f */
	struct _interface	*base_ifp;		/* Base interface (if interface is a VMAC interface),
							   otherwise the physical interface */
	bool			is_ours;		/* keepalived created the interface */
	bool			seen_interface;		/* The interface has existed at some point since we started */
	bool			changeable_type;	/* The interface type or underlying interface can be changed */
#ifdef _HAVE_VRF_
	ifindex_t		vrf_master_ifindex;	/* Only used at startup if we find i/f before master i/f */
	struct _interface	*vrf_master_ifp;	/* VRF master interface - pointer to self if VRF master */
#endif
	int			reset_arp_config;	/* Count of how many vrrps have changed arp parameters on interface */
	bool			arp_ignore;		/* Original value of arp_ignore to be restored */
	bool			arp_filter;		/* Original value of arp_filter to be restored */
	unsigned		rp_filter;		/* < UINT_MAX if we have changed the value */
#endif
	garp_delay_t		*garp_delay;		/* Delays for sending gratuitous ARP/NA */
	bool			gna_router;		/* Router flag for NA messages */
	bool			promote_secondaries;	/* Original value of promote_secondaries to be restored */
	uint32_t		reset_promote_secondaries; /* Count of how many vrrps have changed promote_secondaries on interface */
	list			tracking_vrrp;		/* List of tracking_vrrp_t for vrrp instances tracking this interface */
} interface_t;

/* Tracked interface structure definition */
typedef struct _tracked_if {
	int			weight;		/* tracking weight when non-zero */
	interface_t		*ifp;		/* interface backpointer, cannot be NULL */
} tracked_if_t;

/* Macros */
#define IF_NAME(X) ((X)->ifname)
#define IF_INDEX(X) ((X)->ifindex)
#ifdef _HAVE_VRRP_VMAC_
#define IF_BASE_INDEX(X) ((X)->base_ifp->ifindex)
#define IF_BASE_IFP(X) ((X)->base_ifp)
#else
#define IF_BASE_INDEX(X) ((X)->ifindex)
#define IF_BASE_IFP(X) (X)
#endif
#define IF_ADDR(X) ((X)->sin_addr.s_addr)
#define IF_ADDR6(X)	((X)->sin6_addr)
#define IF_HWADDR(X) ((X)->hw_addr)
#define IF_MII_SUPPORTED(X) ((X)->lb_type & LB_MII)
#define IF_ETHTOOL_SUPPORTED(X) ((X)->lb_type & LB_ETHTOOL)
#define FLAGS_UP(X) (((X) & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
#define IF_FLAGS_UP(X) (FLAGS_UP((X)->ifi_flags))
#ifdef _HAVE_VRRP_VMAC_
#define IF_ISUP(X) (IF_FLAGS_UP(X) && (!(X)->vmac_type || IF_FLAGS_UP((X)->base_ifp)))
#else
#define IF_ISUP(X) (IF_FLAGS_UP(X))
#endif

typedef enum if_lookup {
	IF_NO_CREATE,
	IF_CREATE_IF_DYNAMIC,
	IF_CREATE_ALWAYS,
	IF_CREATE_NETLINK
} if_lookup_t;

/* Global data */
list garp_delay;

/* prototypes */
extern interface_t *if_get_by_ifindex(ifindex_t);
extern interface_t *if_get_by_ifname(const char *, if_lookup_t);
extern list get_if_list(void);
extern void reset_interface_queue(void);
extern void alloc_garp_delay(void);
extern void set_default_garp_delay(void);
extern void if_add_queue(interface_t *);
extern void init_interface_queue(void);
extern void init_interface_linkbeat(void);
extern void free_interface_queue(void);
extern void free_old_interface_queue(void);
extern int if_join_vrrp_group(sa_family_t, int *, interface_t *);
extern int if_leave_vrrp_group(sa_family_t, int, interface_t *);
extern int if_setsockopt_bindtodevice(int *, interface_t *);
extern int if_setsockopt_hdrincl(int *);
extern int if_setsockopt_ipv6_checksum(int *);
#if HAVE_DECL_IP_MULTICAST_ALL  /* Since Linux 2.6.31 */
extern int if_setsockopt_mcast_all(sa_family_t, int *);
#endif
extern int if_setsockopt_mcast_loop(sa_family_t, int *);
extern int if_setsockopt_mcast_hops(sa_family_t, int *);
extern int if_setsockopt_mcast_if(sa_family_t, int *, interface_t *);
extern int if_setsockopt_priority(int *, int);
extern int if_setsockopt_rcvbuf(int *, int);
extern int if_setsockopt_no_receive(int *);
extern void interface_up(interface_t *);
extern void interface_down(interface_t *);
extern void cleanup_lost_interface(interface_t *);
extern int recreate_vmac_thread(thread_t *);
extern void update_added_interface(interface_t *);
#ifdef THREAD_DUMP
extern void register_vrrp_if_addresses(void);
#endif

#endif