* keepalived-0.4.8 released.
* Rewrite the whole VRRP previous code.
* VRRP : Created a hierarchic scheduling framework.
Handle VRRP instances multiplexing on the same I/O fd.
VRRP I/O events are handled by our global scheduling
framework. Then the global sheduling framework call a VRRP
I/O instance dispatcher to manage VRRP instances.
* VRRP : Created a temporary socket pool to handle register
our VRRP thread instances.
We create & allocate a socket pool here. The soft design
can be sum up by the following sketch :
fd1 fd2 fd3 fd4 fdi fdi+1
-----\__/--------\__/---........---\__/---
| ETH0 | | ETH1 | | ETHn |
+------+ +------+ +------+
Here we have n physical NIC. Each NIC own a maximum of 2 fds.
(one for VRRP the other for IPSEC_AH). All our VRRP instances
are multiplexed through this fds. So our design can handle 2*n
multiplexing points.
* VRRP : Review the multicast socket creating. We bind the socket
to a specific NIC. inbound & outbound traffic are bound to the
NIC.
=> why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set
sk->bound_dev_if themself ??? !!!
Needed for filter multicasted advert per interface.
=> For inbound binding we use SO_BINDTODEVICE kernel option.
* VRRP : Created a read dispatcher thread to deal with our sockpool.
Handle VRRP states & transition states.
* VRRP : Created a VRRP synchronization instance circuit. This
functionnality gave you the ability to monitor VRRP instance
each other. This mean that if 2 VRRP instances are monitoring
themself and if one of this instance change state, the other
follow the same state. ex.: With 2 VRRP instances (VI_1 & VI_2)
if VI_1 become backup then VI_2 become backup too. (symetricly
with master VRRP state).
* VRRP : Rewrite the netlink interface to use non blocking socket.
* VRRP : Rewrite the ipaddress handling to use the new netlink
interface.
* VRRP : Remove the VRPP VMAC handling since linux kernel only
permit to use one MAC address on a specific NIC. We use gratuitous
arp when setting up VRRP VIP, to uptade remote host arp caches.
=> In certain case this can cause a TCP session renegociation
which can cause a permature session end.
=> To be fully compliant with the VRRP RFC, need to patch the
kernel to gave it the possibility to deal with more than one
MAC address at a time. Give me clue on it please ! to same me
a little time :)
* Starting VRRP documentation.
* Patch a pidfile handling bug when forking the keepalived daemon.
Thanks goes to Gianni D'Aprile for pointing it to me.
* Patch a timer race condition into the scheduling framework.
This bug caused tcpcheck to respawn quickly...
Thanks goes to Gianni D'Aprile for pointing it to me.
* keepalived-0.3.8 released.
* Added support to native IPTABLE LVS CODE
=> using NAT on 2.4 kernel ipchains kernel support
has been removed.
* Added support to Direct Routing & Tunneling.
* Review the keepalived.init script to be much more generic.
-2001-09-14 Alexandre Cassen <acassen@linux-vs.org>
+2001-11-20 Alexandre Cassen <acassen@linux-vs.org>
+ * keepalived-0.4.8 released.
+ * Rewrite the whole VRRP previous code.
+ * VRRP : Created a hierarchic scheduling framework.
+ Handle VRRP instances multiplexing on the same I/O fd.
+ VRRP I/O events are handled by our global scheduling
+ framework. Then the global sheduling framework call a VRRP
+ I/O instance dispatcher to manage VRRP instances.
+ * VRRP : Created a temporary socket pool to handle register
+ our VRRP thread instances.
+ We create & allocate a socket pool here. The soft design
+ can be sum up by the following sketch :
+
+ fd1 fd2 fd3 fd4 fdi fdi+1
+ -----\__/--------\__/---........---\__/---
+ | ETH0 | | ETH1 | | ETHn |
+ +------+ +------+ +------+
+
+ Here we have n physical NIC. Each NIC own a maximum of 2 fds.
+ (one for VRRP the other for IPSEC_AH). All our VRRP instances
+ are multiplexed through this fds. So our design can handle 2*n
+ multiplexing points.
+ * VRRP : Review the multicast socket creating. We bind the socket
+ to a specific NIC. inbound & outbound traffic are bound to the
+ NIC.
+ => why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set
+ sk->bound_dev_if themself ??? !!!
+ Needed for filter multicasted advert per interface.
+ => For inbound binding we use SO_BINDTODEVICE kernel option.
+ * VRRP : Created a read dispatcher thread to deal with our sockpool.
+ Handle VRRP states & transition states.
+ * VRRP : Created a VRRP synchronization instance circuit. This
+ functionnality gave you the ability to monitor VRRP instance
+ each other. This mean that if 2 VRRP instances are monitoring
+ themself and if one of this instance change state, the other
+ follow the same state. ex.: With 2 VRRP instances (VI_1 & VI_2)
+ if VI_1 become backup then VI_2 become backup too. (symetricly
+ with master VRRP state).
+ * VRRP : Rewrite the netlink interface to use non blocking socket.
+ * VRRP : Rewrite the ipaddress handling to use the new netlink
+ interface.
+ * VRRP : Remove the VRPP VMAC handling since linux kernel only
+ permit to use one MAC address on a specific NIC. We use gratuitous
+ arp when setting up VRRP VIP, to uptade remote host arp caches.
+ => In certain case this can cause a TCP session renegociation
+ which can cause a permature session end.
+ => To be fully compliant with the VRRP RFC, need to patch the
+ kernel to gave it the possibility to deal with more than one
+ MAC address at a time. Give me clue on it please ! to same me
+ a little time :)
+ * Starting VRRP documentation.
+ * Patch a pidfile handling bug when forking the keepalived daemon.
+ Thanks goes to Gianni D'Aprile for pointing it to me.
+ * Patch a timer race condition into the scheduling framework.
+ This bug caused tcpcheck to respawn quickly...
+ Thanks goes to Gianni D'Aprile for pointing it to me.
+
+2001-11-04 Alexandre Cassen <acassen@linux-vs.org>
+ * keepalived-0.3.8 released.
+ * Added support to native IPTABLE LVS CODE
+ => using NAT on 2.4 kernel ipchains kernel support
+ has been removed.
+ * Added support to Direct Routing & Tunneling.
+ * Review the keepalived.init script to be much more generic.
+2001-09-14 Alexandre Cassen <acassen@linux-vs.org>
* keepalived-0.4.1 released.
* Added support to LVS kernel 2.4 code
-
2001-08-23 Alexandre Cassen <acassen@linux-vs.org>
-
* keepalived-0.4.0 released.
* Patch a race condition into the scheduler timer computation.
* Patch a race condition into the tcp checker thread. Only
or set by kernel. Only UNICAST route are stored.
* Added dropping packet support.
-
2001-07-15 Alexandre Cassen <acassen@linux-vs.org>
-
* keepalived-0.3.5 released.
* Rewrite the whole signal handling, registering a terminating
thread on signal.
Compile a kernel with the following options :
- IP aliasing
Kernel/User netlink socket
- Network firewalls
+ Network firewalls (for Kernel 2.2)
Routing messages
LinuxVirtualServer
- If you use KERNEL 2.4 build your kernel with ipchains support :
- => Network options
- IP: Netfilter Configuration
- <M> ipchains (2.2-style) support
-
- => Patch your 2.4 kernel with the LVS code
-
Installation
============
KERNEL := KERNEL_2_$(shell uname -r | cut -d'.' -f2)
# To compile with debug messages uncomment the following line
-CFLAGS= -g -Wall -DDEBUG -D$(KERNEL)
+CFLAGS= -g -Wall -Wunused -DDEBUG -D$(KERNEL)
#CFLAGS= -g -Wall -D$(KERNEL)
DEFS=
-LIB= libipfwc/libipfwc.a \
- libnetlink/libnetlink.a
+ifeq ($(KERNEL),KERNEL_2_2)
+ LIB := $(LIB) libipfwc/libipfwc.a
+endif
-#DEFS= main.h scheduler.h cfreader.h layer4.h check_tcp.h check_http.h md5.h smtp.h
-OBJECTS= main.o \
+DEFS= main.h \
+ scheduler.h \
+ cfreader.h \
+ layer4.h \
+ check_tcp.h \
+ check_http.h \
+ check_misc.h \
+ md5.h \
+ vrrp.h \
+ vrrp_scheduler.h \
+ vrrp_netlink.h \
+ vrrp_ipaddress.h \
+ vrrp_ipsecah.h \
+ smtp.h
+
+OBJECTS := main.o \
utils.o \
scheduler.o \
cfreader.o \
layer4.o \
check_tcp.o \
check_http.o \
+ check_misc.o \
md5.o \
ipwrapper.o \
- ipvswrapper.o \
- ipfwwrapper.o \
+ ipvswrapper.o
+ifeq ($(KERNEL),KERNEL_2_2)
+ OBJECTS := $(OBJECTS) ipfwwrapper.o
+endif
+OBJECTS := $(OBJECTS) \
pidfile.o \
smtp.o \
vrrp.o \
- vrrp_iproute.o \
+ vrrp_scheduler.o \
+ vrrp_netlink.o \
vrrp_ipaddress.o \
vrrp_ipsecah.o
$(EXEC): $(OBJECTS) $(DEFS) $(LIB)
$(CC) -o $(EXEC) $(CFLAGS) $(OBJECTS) $(LIB)
+ifeq ($(KERNEL),KERNEL_2_2)
libipfwc/libipfwc.a:
cd libipfwc/ && $(MAKE) libipfwc.a
-
-libnetlink/libnetlink.a:
- cd libnetlink/ && $(MAKE) libnetlink.a
+endif
subclean:
+ifeq ($(KERNEL),KERNEL_2_2)
cd libipfwc/ && $(MAKE) clean
- cd libnetlink/ && $(MAKE) clean
+endif
clean: subclean
rm -f core *.o $(EXEC)
-* VRRP : handle specific interface multicast binding.
* Documentation.
+* Synchronize IPVS topology with VRRP synchronization events.
* Insert LDAP, SSL, FTP, SSH, IMAP, POP, RADIUS checkers.
* Security auditing.
* Add minimum configuration verification (realserver must have
a checker defined, ...)
* Add system verification (must have LVS support in kernel,
must have netlink support in kernel,
- must have ip alias support in kernel,
must have routing messages in kernel).
* data structure representation the conf file representing
* the loadbalanced server pool.
*
- * Version: $Id: cfreader.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: cfreader.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
{KW_SSLGET, "SSL_GET"},
{KW_LDAPGET, "LDAP_GET"},
+ {KW_MISCCHECK, "MISC_CHECK"},
+ {KW_MISCPATH, "misc_path"},
+
{KW_VRRP, "vrrp_instance"},
+ {KW_VRRPSTATE, "state"},
{KW_VRRPINT, "interface"},
{KW_VRRPVRID, "virtual_router_id"},
{KW_VRRPAUTH, "authentication"},
break;
case LDAP_GET_ID:
break;
+ case MISC_CHECK_ID:
+ syslog(LOG_DEBUG," -> Keepalive method = MISC_CHECK");
+ syslog(LOG_DEBUG," -> Check path = %s",
+ pointersvr->method->misc_check_path);
+ break;
}
pointersvr = (realserver *)pointersvr->next;
ntohs(pointervs->addr_port));
syslog(LOG_DEBUG, " -> delay_loop = %d, lb_algo = %s, "
- "lb_kind = %s, persistence = %s, protocol = %s",
+ "persistence = %s, protocol = %s",
pointervs->delay_loop, pointervs->sched,
- (pointervs->loadbalancing_kind == 0)?"NAT":"UNKNOWN",
pointervs->timeout_persistence,
(pointervs->service_type == IPPROTO_TCP)?"TCP":"UDP");
- syslog(LOG_DEBUG, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
+ switch (pointervs->loadbalancing_kind) {
+#ifdef KERNEL_2_2
+ case 0:
+ syslog(LOG_DEBUG, " -> lb_kind = NAT");
+ syslog(LOG_DEBUG, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
+ break;
+ case IP_MASQ_F_VS_DROUTE:
+ syslog(LOG_DEBUG, " -> lb_kind = DR");
+ break;
+ case IP_MASQ_F_VS_TUNNEL:
+ syslog(LOG_DEBUG, " -> lb_kind = TUN");
+ break;
+#else
+ case IP_VS_CONN_F_MASQ:
+ syslog(LOG_DEBUG, " -> lb_kind = NAT");
+ break;
+ case IP_VS_CONN_F_DROUTE:
+ syslog(LOG_DEBUG, " -> lb_kind = DR");
+ break;
+ case IP_VS_CONN_F_TUNNEL:
+ syslog(LOG_DEBUG, " -> lb_kind = TUN");
+ break;
+#endif
+ }
if (pointervs->s_svr != NULL) {
- syslog(LOG_DEBUG, " -> sorry server = [%s:%d]",
+ syslog(LOG_DEBUG, " -> sorry server = [%s:%d]",
inet_ntoa(pointervs->s_svr->addr_ip),
ntohs(pointervs->s_svr->addr_port));
}
while (pointervrrp != NULL) {
syslog(LOG_DEBUG, " VRRP Instance = %s", pointervrrp->iname);
+ if (pointervrrp->vsrv->init_state == VRRP_STATE_BACK)
+ syslog(LOG_DEBUG, " Want State = BACKUP");
+ else
+ syslog(LOG_DEBUG, " Want State = MASTER");
syslog(LOG_DEBUG, " Device = %s", pointervrrp->vsrv->vif->ifname);
if (strlen(pointervrrp->isync) > 0)
syslog(LOG_DEBUG, " Sync with instance = %s", pointervrrp->isync);
svrfill->method = methodfill;
}
+void process_stream_misccheck(FILE *stream, realserver *svrfill)
+{
+ keepalive_check *methodfill;
+ char* pathstring = (char*)malloc(512);
+
+ /* Allocate new method structure */
+ methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
+ memset(methodfill, 0, sizeof(keepalive_check));
+
+ methodfill->type = MISC_CHECK_ID;
+ methodfill->http_get = NULL;
+ methodfill->misc_check_path = NULL;
+
+ do {
+ switch (key(string)) {
+ case KW_CTIMEOUT:
+ fscanf(stream, "%d", &methodfill->connection_to);
+ break;
+ case KW_MISCPATH:
+ fgets(pathstring,512,stream);
+ methodfill->misc_check_path=pathstring;
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+
+ svrfill->method = methodfill;
+}
+
void process_stream_url(FILE *stream, http_get_check *httpgetfill)
{
urls *urlfill;
break;
case KW_LDAPGET: /* not yet implemented */
break;
+ case KW_MISCCHECK:
+ process_stream_misccheck(stream, svrfill);
+ break;
case KW_UNKNOWN:
break;
}
fscanf(stream, "%s", string);
vsfill->addr_port = htons(atoi(string));
+ /* Setting default value */
+ vsfill->delay_loop = KEEPALIVED_DEFAULT_DELAY;
+
do {
switch (key(string)) {
case KW_DELAY:
break;
case KW_LBKIND:
fscanf(stream, "%s", string);
- /* For the moment only NAT is supported.
- * masq_flags : IP_MASQ_F_VS_DROUTE & IP_MASQ_F_VS_TUNNEL not supported.
- * So we just set masq_flags to 0.
- */
- vsfill->loadbalancing_kind = 0;
+
+#ifdef KERNEL_2_2
+ if (strcmp(string, "NAT") == 0)
+ vsfill->loadbalancing_kind = 0;
+ else
+ if (strcmp(string, "DR") == 0)
+ vsfill->loadbalancing_kind = IP_MASQ_F_VS_DROUTE;
+ else
+ if (strcmp(string, "TUN") == 0)
+ vsfill->loadbalancing_kind = IP_MASQ_F_VS_TUNNEL;
+ else
+ syslog(LOG_DEBUG,"CFREADER : unknown [%s] routing method."
+ , string);
+#else
+ if (strcmp(string, "NAT") == 0)
+ vsfill->loadbalancing_kind = IP_VS_CONN_F_MASQ;
+ else
+ if (strcmp(string, "DR") == 0)
+ vsfill->loadbalancing_kind = IP_VS_CONN_F_DROUTE;
+ else
+ if (strcmp(string, "TUN") == 0)
+ vsfill->loadbalancing_kind = IP_VS_CONN_F_TUNNEL;
+ else
+ syslog(LOG_DEBUG,"CFREADER : unknown [%s] routing method."
+ , string);
+#endif
+
break;
case KW_NATMASK:
fscanf(stream, "%s", string);
vrrpfill->vsrv->vaddr = NULL;
vrrpfill->next = NULL;
+ /* default value */
+ rtfill->wantstate = VRRP_STATE_BACK;
+ rtfill->init_state = VRRP_STATE_BACK;
+
conf_data->vrrp = add_item_vrrp(conf_data->vrrp, vrrpfill);
fscanf(stream, "%s", vrrpfill->iname);
case KW_VRRPSYNC:
fscanf(stream, "%s", vrrpfill->isync);
break;
+ case KW_VRRPSTATE:
+ fscanf(stream, "%s", string);
+ if (strcmp(string, "MASTER") == 0) {
+ rtfill->wantstate = VRRP_STATE_MAST;
+ rtfill->init_state = VRRP_STATE_MAST;
+ } else {
+ rtfill->wantstate = VRRP_STATE_BACK;
+ rtfill->init_state = VRRP_STATE_BACK;
+ }
+ break;
case KW_VRRPINT:
fscanf(stream, "%s", viffill->ifname);
break;
*
* Part: cfreader.c include file.
*
- * Version: $Id: cfreader.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: cfreader.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#ifdef KERNEL_2_2
#include <linux/ip_masq.h>
+ #include <net/ip_masq.h>
#else
#include <net/ip_vs.h>
#endif
#define KW_HTTPGET 26
#define KW_SSLGET 27
#define KW_LDAPGET 28
-
-#define KW_VRRP 29
-#define KW_VRRPINT 30
-#define KW_VRRPVRID 31
-#define KW_VRRPAUTH 32
-#define KW_VRRPAUTHTYPE 33
-#define KW_VRRPAUTHAH 34
-#define KW_VRRPAUTHPWD 35
-#define KW_VRRPAUTHPASS 36
-#define KW_VRRPPRIO 37
-#define KW_VRRPADVERT 38
-#define KW_VRRPIPADD 39
-#define KW_VRRPSYNC 40
-#define KW_VRRPPREEMPT 41
-
-#define KW_UNKNOWN 42
+#define KW_MISCCHECK 29
+#define KW_MISCPATH 30
+
+#define KW_VRRP 31
+#define KW_VRRPSTATE 32
+#define KW_VRRPINT 33
+#define KW_VRRPVRID 34
+#define KW_VRRPAUTH 35
+#define KW_VRRPAUTHTYPE 36
+#define KW_VRRPAUTHAH 37
+#define KW_VRRPAUTHPWD 38
+#define KW_VRRPAUTHPASS 39
+#define KW_VRRPPRIO 40
+#define KW_VRRPADVERT 41
+#define KW_VRRPIPADD 42
+#define KW_VRRPSYNC 43
+#define KW_VRRPPREEMPT 44
+
+#define KW_UNKNOWN 45
+
+#define KEEPALIVED_DEFAULT_DELAY 60
/* Structure definition */
typedef struct _urls {
#define HTTP_GET_ID (1 << 2)
#define SSL_GET_ID (1 << 3)
#define LDAP_GET_ID (1 << 4)
+#define MISC_CHECK_ID (1 << 5)
int connection_to;
http_get_check *http_get; /* FIXME : for new checker use union here */
+ char *misc_check_path;
} keepalive_check;
typedef struct _real_server {
*
* Part: Checkers arguments structures definitions.
*
- * Version: $Id: check.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: check.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* url, compute a MD5 over this result and match it to the
* expected value.
*
- * Version: $Id: check_http.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: check_http.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: check_http.c include file.
*
- * Version: $Id: check_http.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: check_http.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
--- /dev/null
+/*
+ * 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: MISC CHECK. Perform a system call to run an extra
+ * system prog or script.
+ *
+ * Version: $Id: check_misc.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ *
+ * Author: Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
+ *
+ * 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.
+ */
+
+#include "check_misc.h"
+
+/* does this need to be threaded? */
+int
+misc_check_call(char* cmdline)
+{
+ int retval;
+
+ retval = system(cmdline);
+
+ if (retval == 127) {
+ /* couldn't exec command */
+ syslog(LOG_DEBUG,"Couldn't exec command: %s", cmdline);
+ } else if (retval == -1) {
+ /* other error */
+ syslog(LOG_DEBUG,"Error exec-ing command: %s", cmdline);
+ } else {
+ /* everything is good */
+ syslog(LOG_DEBUG, "Successfully exec command: %s retval is %d"
+ , cmdline, retval);
+ }
+
+ return retval;
+}
+
+int
+misc_check_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ int status;
+
+ thread_arg = THREAD_ARG(thread);
+
+ status = misc_check_call(thread_arg->svr->method->misc_check_path);
+
+ if (status == 0) {
+ /* everything is good */
+ if (!thread_arg->svr->alive) {
+ perform_svr_state(UP, thread_arg->vs, thread_arg->svr);
+ }
+ } else {
+ if (thread_arg->svr->alive) {
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+ }
+
+ /* Register next timer checker */
+ thread_add_timer(thread->master, misc_check_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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: check_misc.c include file.
+ *
+ * Version: $Id: check_misc.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ *
+ * Author: Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
+ *
+ * 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.
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+/* system includes */
+#include <stdlib.h>
+
+/* local includes */
+#include "cfreader.h"
+#include "ipwrapper.h"
+#include "scheduler.h"
+#include "smtp.h"
+
+/* Prototypes defs */
+extern int misc_check_thread(struct thread *thread);
+
+#endif
*
* Part: TCP checker.
*
- * Version: $Id: check_tcp.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: check_tcp.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: check_tcp.c include file.
*
- * Version: $Id: check_tcp.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: check_tcp.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
# pidfile: /var/run/keepalived.pid
# config: /etc/keepalived/keepalived.conf
-
-# Source function library.
-. /etc/rc.d/init.d/functions
-
# See how we were called.
case "$1" in
start)
echo -n "Starting Keepalived for LVS: "
- daemon keepalived
+ keepalived
echo
;;
stop)
echo -n "Shutting down Keepalived for LVS: "
- killproc keepalived
+ PID=`ps ax | grep keepalived | awk '{print $1}'`
+ kill $PID
echo
;;
*)
* library to add/remove server MASQ rules to the kernel
* firewall framework.
*
- * Version: $Id: ipfwwrapper.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: ipfwwrapper.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: ipfwwrapper.c include file.
*
- * Version: $Id: ipfwwrapper.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: ipfwwrapper.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Part: IPVS Kernel wrapper. Use setsockopt call to add/remove
* server to/from the loadbalanced server pool.
*
- * Version: $Id: ipvswrapper.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: ipvswrapper.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
memset(&urule, 0, sizeof(struct ip_vs_rule_user));
strncpy(urule.sched_name, vserver->sched, IP_VS_SCHEDNAME_MAXLEN);
- urule.weight = -1;
- /*
- * Set MASQ as default forwarding method.
- * FIXME: In the current implementation we only support NAT.
- */
- urule.conn_flags = IP_VS_CONN_F_MASQ;
+ urule.weight = 1;
+ urule.conn_flags = vserver->loadbalancing_kind;
urule.netmask = ((u_int32_t) 0xffffffff);
urule.protocol = vserver->service_type;
*
* Part: ipvswrapper.c include file.
*
- * Version: $Id: ipvswrapper.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: ipvswrapper.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: Manipulation functions for IPVS & IPFW wrappers.
*
- * Version: $id: ipwrapper.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $id: ipwrapper.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
return 0;
}
+#ifdef KERNEL_2_2
/* IPFW cleaning server entry if granularity = /32 */
if (vserver->nat_mask.s_addr == HOST_NETMASK)
if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
return 0;
+#endif
vserver->svr = (realserver *)vserver->svr->next;
}
if (!clear_service_vs(vserver))
return 0;
+#ifdef KERNEL_2_2
/* IPFW cleaner processing */
- if (vserver->nat_mask.s_addr != HOST_NETMASK) {
+ if (vserver->nat_mask.s_addr != HOST_NETMASK)
if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
return 0;
- }
+#endif
vserver = (virtualserver *)vserver->next;
}
vserver->s_svr->alive = 0;
ipvs_cmd(LVS_CMD_DEL_DEST, vserver, vserver->s_svr);
+#ifdef KERNEL_2_2
ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->s_svr);
+#endif
}
}
inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port),
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
ipvs_cmd(LVS_CMD_ADD_DEST, vserver, rserver);
+
+#ifdef KERNEL_2_2
if (vserver->nat_mask.s_addr == HOST_NETMASK)
ipfw_cmd(IP_FW_CMD_ADD, vserver, rserver);
+#endif
} else {
/* server is down, it is removed from the LVS realserver pool */
ipvs_cmd(LVS_CMD_DEL_DEST, vserver, rserver);
+
+#ifdef KERNEL_2_2
if (vserver->nat_mask.s_addr == HOST_NETMASK)
ipfw_cmd(IP_FW_CMD_DEL, vserver, rserver);
+#endif
/* if all the realserver pool is down, we add sorry server */
if (vserver->s_svr && all_realservers_down(vserver)) {
/* the sorry server is now up in the pool, we flag it alive */
vserver->s_svr->alive = 1;
ipvs_cmd(LVS_CMD_ADD_DEST, vserver, vserver->s_svr);
+
+#ifdef KERNEL_2_2
ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->s_svr);
+#endif
}
}
return 0;
}
+#ifdef KERNEL_2_2
/* if we have a /32 mask, we create one nat rules per
* realserver.
*/
vserver->svr = pointersvr;
return 0;
}
+#endif
+
vserver->svr = (realserver *)vserver->svr->next;
}
vserver->svr = pointersvr;
if (!ipvs_cmd(LVS_CMD_ADD, vserver, vserver->svr))
return 0;
+#ifdef KERNEL_2_2
/* work if all realserver ip address are in the
* same network (it is assumed).
*/
if (vserver->nat_mask.s_addr != HOST_NETMASK)
if (!ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->svr))
return 0;
+#endif
if (!init_service_vs(vserver))
return 0;
*
* Part: ipwrapper.c include file.
*
- * Version: $Id: ipwrapper.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: ipwrapper.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Part: Layer4 checkers handling. Register worker threads &
* upper layer checkers.
*
- * Version: $Id: layer4.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: layer4.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: layer4.c include file.
*
- * Version: $Id: layer4.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: layer4.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+++ /dev/null
-CC = gcc
-COPTS = -g -O
-CFLAGS = -Wall -Wunused $(COPTS)
-
-libnetlink.a: libnetlink.a(libnetlink.o ll_map.o)
-
-libnetlink.o: libnetlink.h
-ll_map.o: ll_map.h
-
-clean:
- rm -f *.a *.o *~
+++ /dev/null
-/*
- * libnetlink.c RTnetlink service routines.
- *
- * 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.
- *
- * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <fcntl.h>
-#include <net/if_arp.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/uio.h>
-
-#include "libnetlink.h"
-
-#ifndef MSG_TRUNC
-# define MSG_TRUNC 0x20
-#endif
-
-#if 1
-# define nl_perror(str) perror(str)
-#else
-# define nl_perror(str)
-#endif
-
-int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
-{
- int addr_len;
-
- memset(rth, 0, sizeof(rth));
-
- rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (rth->fd < 0) {
- nl_perror("Cannot open netlink socket");
- return -1;
- }
-
- memset(&rth->local, 0, sizeof(rth->local));
- rth->local.nl_family = AF_NETLINK;
- rth->local.nl_groups = subscriptions;
-
- if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
- nl_perror("Cannot bind netlink socket");
- return -1;
- }
- addr_len = sizeof(rth->local);
- if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
- nl_perror("Cannot getsockname");
- return -1;
- }
- if (addr_len != sizeof(rth->local)) {
- fprintf(stderr, "Wrong address length %d\n", addr_len);
- return -1;
- }
- if (rth->local.nl_family != AF_NETLINK) {
- fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
- return -1;
- }
- rth->seq = time(NULL);
- return 0;
-}
-
-int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
-{
- struct {
- struct nlmsghdr nlh;
- struct rtgenmsg g;
- } req;
- struct sockaddr_nl nladdr;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- req.nlh.nlmsg_len = sizeof(req);
- req.nlh.nlmsg_type = type;
- req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
- req.nlh.nlmsg_pid = 0;
- req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
- req.g.rtgen_family = family;
-
- return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
-}
-
-int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
-{
- struct sockaddr_nl nladdr;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
-}
-
-int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
-{
- struct nlmsghdr nlh;
- struct sockaddr_nl nladdr;
- struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
- struct msghdr msg = {
- (void*)&nladdr, sizeof(nladdr),
- iov, 2,
- NULL, 0,
- 0
- };
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- nlh.nlmsg_len = NLMSG_LENGTH(len);
- nlh.nlmsg_type = type;
- nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
- nlh.nlmsg_pid = 0;
- nlh.nlmsg_seq = rth->dump = ++rth->seq;
-
- return sendmsg(rth->fd, &msg, 0);
-}
-
-int rtnl_dump_filter(struct rtnl_handle *rth,
- int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
- void *arg1,
- int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *arg2)
-{
- char buf[8192];
- struct sockaddr_nl nladdr;
- struct iovec iov = { buf, sizeof(buf) };
-
- while (1) {
- int status;
- struct nlmsghdr *h;
-
- struct msghdr msg = {
- (void*)&nladdr, sizeof(nladdr),
- &iov, 1,
- NULL, 0,
- 0
- };
-
- status = recvmsg(rth->fd, &msg, 0);
-
- if (status < 0) {
- if (errno == EINTR)
- continue;
- nl_perror("OVERRUN");
- continue;
- }
- if (status == 0) {
- fprintf(stderr, "EOF on netlink\n");
- return -1;
- }
- if (msg.msg_namelen != sizeof(nladdr)) {
- fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
- exit(1);
- }
-
- h = (struct nlmsghdr*)buf;
- while (NLMSG_OK(h, status)) {
- int err;
-
- if (h->nlmsg_pid != rth->local.nl_pid ||
- h->nlmsg_seq != rth->dump) {
- if (junk) {
- err = junk(&nladdr, h, arg2);
- if (err < 0)
- return err;
- }
- goto skip_it;
- }
-
- if (h->nlmsg_type == NLMSG_DONE)
- return 0;
- if (h->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
- if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
- fprintf(stderr, "ERROR truncated\n");
- } else {
- errno = -err->error;
- nl_perror("RTNETLINK answers");
- }
- return -1;
- }
- err = filter(&nladdr, h, arg1);
- if (err < 0)
- return err;
-
-skip_it:
- h = NLMSG_NEXT(h, status);
- }
- if (msg.msg_flags & MSG_TRUNC) {
- fprintf(stderr, "Message truncated\n");
- continue;
- }
- if (status) {
- fprintf(stderr, "!!!Remnant of size %d\n", status);
- exit(1);
- }
- }
-}
-
-int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
- unsigned groups, struct nlmsghdr *answer,
- int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *jarg)
-{
- int status;
- struct nlmsghdr *h;
- struct sockaddr_nl nladdr;
- struct iovec iov = { (void*)n, n->nlmsg_len };
- char buf[8192];
- struct msghdr msg = {
- (void*)&nladdr, sizeof(nladdr),
- &iov, 1,
- NULL, 0,
- 0
- };
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
- nladdr.nl_pid = peer;
- nladdr.nl_groups = groups;
-
- n->nlmsg_seq = ++rtnl->seq;
- if (answer == NULL)
- n->nlmsg_flags |= NLM_F_ACK;
-
- status = sendmsg(rtnl->fd, &msg, 0);
-
- if (status < 0) {
- nl_perror("Cannot talk to rtnetlink");
- return -1;
- }
-
- iov.iov_base = buf;
- iov.iov_len = sizeof(buf);
-
- while (1) {
- status = recvmsg(rtnl->fd, &msg, 0);
-
- if (status < 0) {
- if (errno == EINTR)
- continue;
- nl_perror("OVERRUN");
- continue;
- }
- if (status == 0) {
- fprintf(stderr, "EOF on netlink\n");
- return -1;
- }
- if (msg.msg_namelen != sizeof(nladdr)) {
- fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
- exit(1);
- }
- for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
- int err;
- int len = h->nlmsg_len;
- pid_t pid=h->nlmsg_pid;
- int l = len - sizeof(*h);
- unsigned seq=h->nlmsg_seq;
-
- if (l<0 || len>status) {
- if (msg.msg_flags & MSG_TRUNC) {
- fprintf(stderr, "Truncated message\n");
- return -1;
- }
- fprintf(stderr, "!!!malformed message: len=%d\n", len);
- exit(1);
- }
-
- if (h->nlmsg_pid != pid || h->nlmsg_seq != seq) {
- if (junk) {
- err = junk(&nladdr, h, jarg);
- if (err < 0)
- return err;
- }
- continue;
- }
-
- if (h->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
- if (l < sizeof(struct nlmsgerr)) {
- fprintf(stderr, "ERROR truncated\n");
- } else {
- errno = -err->error;
- if (errno == 0) {
- if (answer)
- memcpy(answer, h, h->nlmsg_len);
- return 0;
- }
- nl_perror("RTNETLINK answers");
- }
- return -1;
- }
- if (answer) {
- memcpy(answer, h, h->nlmsg_len);
- return 0;
- }
-
- fprintf(stderr, "Unexpected reply!!!\n");
-
- status -= NLMSG_ALIGN(len);
- h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
- }
- if (msg.msg_flags & MSG_TRUNC) {
- fprintf(stderr, "Message truncated\n");
- continue;
- }
- if (status) {
- fprintf(stderr, "!!!Remnant of size %d\n", status);
- exit(1);
- }
- }
-}
-
-int rtnl_listen(struct rtnl_handle *rtnl,
- int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *jarg)
-{
- int status;
- struct nlmsghdr *h;
- struct sockaddr_nl nladdr;
- struct iovec iov;
- char buf[8192];
- struct msghdr msg = {
- (void*)&nladdr, sizeof(nladdr),
- &iov, 1,
- NULL, 0,
- 0
- };
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
- nladdr.nl_pid = 0;
- nladdr.nl_groups = 0;
-
-
- iov.iov_base = buf;
- iov.iov_len = sizeof(buf);
-
- while (1) {
- status = recvmsg(rtnl->fd, &msg, 0);
-
- if (status < 0) {
- if (errno == EINTR)
- continue;
- nl_perror("OVERRUN");
- continue;
- }
- if (status == 0) {
- fprintf(stderr, "EOF on netlink\n");
- return -1;
- }
- if (msg.msg_namelen != sizeof(nladdr)) {
- fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
- exit(1);
- }
- for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
- int err;
- int len = h->nlmsg_len;
- int l = len - sizeof(*h);
-
- if (l<0 || len>status) {
- if (msg.msg_flags & MSG_TRUNC) {
- fprintf(stderr, "Truncated message\n");
- return -1;
- }
- fprintf(stderr, "!!!malformed message: len=%d\n", len);
- exit(1);
- }
-
- err = handler(&nladdr, h, jarg);
- if (err < 0)
- return err;
-
- status -= NLMSG_ALIGN(len);
- h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
- }
- if (msg.msg_flags & MSG_TRUNC) {
- fprintf(stderr, "Message truncated\n");
- continue;
- }
- if (status) {
- fprintf(stderr, "!!!Remnant of size %d\n", status);
- exit(1);
- }
- }
-}
-
-int rtnl_from_file(FILE *rtnl,
- int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *jarg)
-{
- int status;
- struct sockaddr_nl nladdr;
- char buf[8192];
- struct nlmsghdr *h = (void*)buf;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
- nladdr.nl_pid = 0;
- nladdr.nl_groups = 0;
-
- while (1) {
- int err, len, type;
- pid_t pid;
- int l;
- unsigned seq;
-
- status = fread(&buf, 1, sizeof(*h), rtnl);
-
- if (status < 0) {
- if (errno == EINTR)
- continue;
- nl_perror("rtnl_from_file: fread");
- return -1;
- }
- if (status == 0)
- return 0;
-
- len = h->nlmsg_len;
- type= h->nlmsg_type;
- pid=h->nlmsg_pid;
- l = len - sizeof(*h);
- seq=h->nlmsg_seq;
-
- if (l<0 || len>sizeof(buf)) {
- fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
- len, ftell(rtnl));
- return -1;
- }
-
- status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
-
- if (status < 0) {
- nl_perror("rtnl_from_file: fread");
- return -1;
- }
- if (status < l) {
- fprintf(stderr, "rtnl-from_file: truncated message\n");
- return -1;
- }
-
- err = handler(&nladdr, h, jarg);
- if (err < 0)
- return err;
- }
-}
-
-int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
-{
- int len = RTA_LENGTH(4);
- struct rtattr *rta;
- if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
- return -1;
- rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
- rta->rta_type = type;
- rta->rta_len = len;
- memcpy(RTA_DATA(rta), &data, 4);
- n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
- return 0;
-}
-
-int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
-{
- int len = RTA_LENGTH(alen);
- struct rtattr *rta;
-
- if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
- return -1;
- rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
- rta->rta_type = type;
- rta->rta_len = len;
- memcpy(RTA_DATA(rta), data, alen);
- n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
- return 0;
-}
-
-int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
-{
- int len = RTA_LENGTH(4);
- struct rtattr *subrta;
-
- if (RTA_ALIGN(rta->rta_len) + len > maxlen)
- return -1;
- subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
- subrta->rta_type = type;
- subrta->rta_len = len;
- memcpy(RTA_DATA(subrta), &data, 4);
- rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
- return 0;
-}
-
-int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
-{
- struct rtattr *subrta;
- int len = RTA_LENGTH(alen);
-
- if (RTA_ALIGN(rta->rta_len) + len > maxlen)
- return -1;
- subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
- subrta->rta_type = type;
- subrta->rta_len = len;
- memcpy(RTA_DATA(subrta), data, alen);
- rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
- return 0;
-}
-
-
-int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
-{
- while (RTA_OK(rta, len)) {
- if (rta->rta_type <= max)
- tb[rta->rta_type] = rta;
- rta = RTA_NEXT(rta,len);
- }
- if (len)
- fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
- return 0;
-}
-
-/****************************************************************
- NAME : rtnl_close 00/06/02 23:43:45
- AIM :
- REMARK :
-****************************************************************/
-int rtnl_close(struct rtnl_handle *rth)
-{
- /* close the fd */
- close( rth->fd );
- return(0);
-}
-
+++ /dev/null
-#ifndef __LIBNETLINK_H__
-#define __LIBNETLINK_H__ 1
-
-#include <asm/types.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-struct rtnl_handle
-{
- int fd;
- struct sockaddr_nl local;
- struct sockaddr_nl peer;
- __u32 seq;
- __u32 dump;
-};
-
-extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions);
-extern int rtnl_close(struct rtnl_handle *rth);
-extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
-extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
-extern int rtnl_dump_filter(struct rtnl_handle *rth,
- int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
- void *arg1,
- int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *arg2);
-extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
- unsigned groups, struct nlmsghdr *answer,
- int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *jarg);
-extern int rtnl_send(struct rtnl_handle *rth, char *buf, int);
-
-
-extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data);
-extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen);
-extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data);
-extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen);
-
-extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
-
-extern int rtnl_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *jarg);
-extern int rtnl_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
- void *jarg);
-
-#endif /* __LIBNETLINK_H__ */
-
+++ /dev/null
-/*
- * ll_map.c
- *
- * 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.
- *
- * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <string.h>
-
-#include "libnetlink.h"
-#include "ll_map.h"
-
-struct idxmap
-{
- struct idxmap * next;
- int index;
- int type;
- int alen;
- unsigned flags;
- unsigned char addr[8];
- char name[16];
-};
-
-static struct idxmap *idxmap[16];
-
-int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
-{
- int h;
- struct ifinfomsg *ifi = NLMSG_DATA(n);
- struct idxmap *im, **imp;
- struct rtattr *tb[IFLA_MAX+1];
-
- if (n->nlmsg_type != RTM_NEWLINK)
- return 0;
-
- if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
- return -1;
-
-
- memset(tb, 0, sizeof(tb));
- parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
- if (tb[IFLA_IFNAME] == NULL)
- return 0;
-
- h = ifi->ifi_index&0xF;
-
- for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next)
- if (im->index == ifi->ifi_index)
- break;
-
- if (im == NULL) {
- im = malloc(sizeof(*im));
- if (im == NULL)
- return 0;
- im->next = *imp;
- im->index = ifi->ifi_index;
- *imp = im;
- }
-
- im->type = ifi->ifi_type;
- im->flags = ifi->ifi_flags;
- if (tb[IFLA_ADDRESS]) {
- int alen;
- im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
- if (alen > sizeof(im->addr))
- alen = sizeof(im->addr);
- memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
- } else {
- im->alen = 0;
- memset(im->addr, 0, sizeof(im->addr));
- }
- strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]));
- return 0;
-}
-
-const char *ll_idx_n2a(int idx, char *buf)
-{
- struct idxmap *im;
-
- if (idx == 0)
- return "*";
- for (im = idxmap[idx&0xF]; im; im = im->next)
- if (im->index == idx)
- return im->name;
- snprintf(buf, 16, "if%d", idx);
- return buf;
-}
-
-
-const char *ll_index_to_name(int idx)
-{
- static char nbuf[16];
-
- return ll_idx_n2a(idx, nbuf);
-}
-
-int ll_index_to_type(int idx)
-{
- struct idxmap *im;
-
- if (idx == 0)
- return -1;
- for (im = idxmap[idx&0xF]; im; im = im->next)
- if (im->index == idx)
- return im->type;
- return -1;
-}
-
-unsigned ll_index_to_flags(int idx)
-{
- struct idxmap *im;
-
- if (idx == 0)
- return 0;
-
- for (im = idxmap[idx&0xF]; im; im = im->next)
- if (im->index == idx)
- return im->flags;
- return 0;
-}
-
-int ll_name_to_index(char *name)
-{
- static char ncache[16];
- static int icache;
- struct idxmap *im;
- int i;
-
- if (name == NULL)
- return 0;
- if (icache && strcmp(name, ncache) == 0)
- return icache;
- for (i=0; i<16; i++) {
- for (im = idxmap[i]; im; im = im->next) {
- if (strcmp(im->name, name) == 0) {
- icache = im->index;
- strcpy(ncache, name);
- return im->index;
- }
- }
- }
- return 0;
-}
-
-int ll_init_map(struct rtnl_handle *rth)
-{
- if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) {
- perror("Cannot send dump request");
- exit(1);
- }
-
- if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) {
- fprintf(stderr, "Dump terminated\n");
- exit(1);
- }
- return 0;
-}
+++ /dev/null
-#ifndef __LL_MAP_H__
-#define __LL_MAP_H__ 1
-
-extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
-extern int ll_init_map(struct rtnl_handle *rth);
-extern int ll_name_to_index(char *name);
-extern const char *ll_index_to_name(int idx);
-extern const char *ll_idx_n2a(int idx, char *buf);
-extern int ll_index_to_type(int idx);
-extern unsigned ll_index_to_flags(int idx);
-
-#endif /* __LL_MAP_H__ */
*
* Part: Main program structure.
*
- * Version: $Id: main.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: main.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
closelog();
exit(0);
}
+
+ /* daemonize process */
+ daemon(0, 0);
+
/* write the pidfile */
if (!pidfile_write(getpid())) {
syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
/* Signal handling initialization */
signal_init();
- /* daemonize process */
- daemon(0, 0);
-
/* Create the master thread */
master = thread_make_master();
/* We then cleanup the room & closelog */
thread_destroy_master(master);
clear_services(conf_data->lvstopology);
+
/* Stop VRRP instances */
clear_vrrp_instance(conf_data->vrrp);
clear_conf(conf_data);
*
* Part: Main program include file.
*
- * Version: $Id: main.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: main.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* Build version */
#define PROG "keepalived"
-#define VERSION "0.4.1 (14/09, 2001)"
+#define VERSION "0.4.8 (20/11, 2001)"
#endif
*
* Part: pidfile utility.
*
- * Version: $Id: pidfile.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: pidfile.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: pidfile.c include file.
*
- * Version: $Id: pidfile.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: pidfile.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
--- /dev/null
+# Configuration File for keepalived
+
+global_defs {
+ notification_email {
+ acassen
+ }
+ notification_email_from Alexandre.Cassen@firewall.loc
+ smtp_server 192.168.200.1
+ smtp_connect_timeout 30
+ lvs_id LVS_DEVEL
+}
+
+virtual_server 10.10.10.2 1358 {
+ delay_loop 6
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ sorry_server 192.168.200.200 1358
+
+ real_server 192.168.200.2 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+
+ real_server 192.168.200.3 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334c
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334c
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+
+ real_server 192.168.200.6 1358 {
+ weight 1
+ MISC_CHECK {
+ misc_path /usr/local/bin/script.sh
+ }
+ }
+
+}
+
+virtual_server 10.10.10.3 1358 {
+ delay_loop 3
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.200.4 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+
+ real_server 192.168.200.5 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
lvs_id LVS_DEVEL
}
+
vrrp_instance VI_1 {
+ state MASTER
interface eth0
- virtual_router_id 50
+ virtual_router_id 51
+ priority 100
+ advert_int 1
authentication {
auth_type AH
- auth_pass k!4@lve1
+ auth_pass 1111
}
- priority 100
+ virtual_ipaddress {
+ 192.168.200.16
+ 192.168.200.17
+ 192.168.200.18
+ }
+}
+
+vrrp_instance VI_2 {
+ interface eth0
+ virtual_router_id 50
+ priority 50
advert_int 1
virtual_ipaddress {
- 192.168.200.11
- 192.168.200.12
192.168.200.13
+ 192.168.200.14
+ 192.168.200.15
}
- sync_instance VI_2
- preempt
}
-vrrp_instance VI_2 {
+vrrp_instance VI_3 {
+ state MASTER
interface eth1
- virtual_router_id 51
+ virtual_router_id 52
+ priority 100
+ advert_int 1
authentication {
auth_type AH
- auth_pass k!4@lve2
+ auth_pass 1111
}
- priority 100
- advert_int 1
virtual_ipaddress {
- 192.168.201.11
- 192.168.201.12
192.168.201.13
+ 192.168.201.14
+ 192.168.201.15
}
- sync_instance VI_1
}
+vrrp_instance VI_4 {
+ interface eth1
+ virtual_router_id 53
+ priority 50
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.201.16
+ 192.168.201.17
+ 192.168.201.18
+ }
+}
--- /dev/null
+# Configuration File for keepalived
+
+global_defs {
+ notification_email {
+ acassen@canal-plus.com
+ }
+ notification_email_from keepalived@canal-plus.com
+ smtp_server 172.31.47.6
+ smtp_connect_timeout 30
+ lvs_id LVS_DEVEL
+}
+
+vrrp_instance VI_1 {
+ state MASTER
+ interface eth0
+ virtual_router_id 51
+ priority 150
+ advert_int 1
+ authentication {
+ auth_type AH
+ auth_pass 1111
+ }
+ virtual_ipaddress {
+ 192.168.200.16
+ 192.168.200.17
+ 192.168.200.18
+ }
+}
+
+vrrp_instance VI_2 {
+ interface eth0
+ virtual_router_id 52
+ priority 100
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.200.19
+ 192.168.200.20
+ 192.168.200.21
+ }
+ sync_instance VI_3
+}
+
+vrrp_instance VI_3 {
+ interface eth1
+ virtual_router_id 53
+ priority 100
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.201.19
+ 192.168.201.20
+ 192.168.201.21
+ }
+ sync_instance VI_2
+}
+
+virtual_server 192.168.200.19 80 {
+ delay_loop 20
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.201.100 80 {
+ weight 1
+ TCP_CHECK {
+ connect_timeout 3
+ }
+ }
+}
--- /dev/null
+#!/bin/sh
+# remove it as smbcheck.sh and put it the location you want
+
+SAMBA_BIN=`which smbclient 2> /dev/null`
+
+if [ -z "$SAMBA_BIN" ] ; then
+ exit 2
+fi
+
+if [ -z "$1" ] ; then
+ echo "Usage: $0 <ip address>"
+ exit 2
+fi
+
+($SAMBA_BIN -N -L $1 -W CENTRALB -U nobody) \
+ | egrep '^Domain=\[[A-Za-z0-9_-]+\]' > /dev/null 2>&1
+
* the thread management routine (thread.c) present in the
* very nice zebra project (http://www.zebra.org).
*
- * Version: $Id: scheduler.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: scheduler.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
}
/* timer compare */
-static int
+int
thread_timer_cmp (struct timeval a, struct timeval b)
{
if (a.tv_sec > b.tv_sec)
retry: /* When thread can't fetch try to find next thread again. */
/* If there is event process it first. */
- while ((thread = thread_trim_head (&m->event))) {
+ while ((thread = thread_trim_head(&m->event))) {
*fetch = *thread;
free(timer_wait);
/* If daemon hanging event is received return NULL pointer */
if (thread->type == THREAD_TERMINATE) {
thread->type = THREAD_UNUSED;
- thread_add_unuse (m, thread);
+ thread_add_unuse(m, thread);
return NULL;
}
thread->type = THREAD_UNUSED;
- thread_add_unuse (m, thread);
+ thread_add_unuse(m, thread);
return fetch;
}
/* If there is ready threads process them */
- while ((thread = thread_trim_head (&m->ready))) {
+ while ((thread = thread_trim_head(&m->ready))) {
*fetch = *thread;
thread->type = THREAD_UNUSED;
- thread_add_unuse (m, thread);
+ thread_add_unuse(m, thread);
free(timer_wait);
return fetch;
}
break;
case LDAP_GET_ID:
break;
+ case MISC_CHECK_ID:
+ thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
+ thread_add_timer(master, misc_check_thread, thread_arg,
+ thread_arg->vs->delay_loop);
default:
break;
}
register_worker_thread(struct thread_master *master, configuration_data *lstptr)
{
virtualserver *pointervs;
- vrrp_instance *pointervrrp;
- /* register VRRP specifics threads */
- pointervrrp = lstptr->vrrp;
- while (lstptr->vrrp) {
- thread_add_event(master, vrrp_state_init_thread, lstptr->vrrp, VRRP_STATE_INIT);
-
- lstptr->vrrp = (vrrp_instance *)lstptr->vrrp->next;
- }
- lstptr->vrrp = pointervrrp;
+ /* register VRRP instances dispatcher */
+ if (lstptr->vrrp)
+ thread_add_event(master, vrrp_dispatcher_init_thread,
+ lstptr->vrrp, VRRP_DISPATCHER);
/* register VS specifics threads */
pointervs = lstptr->lvstopology;
*
* Part: scheduler.c include file.
*
- * Version: $Id: scheduler.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: scheduler.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* MICRO SEC def */
#define TIMER_SEC_MICRO 1000000
-#define TIMER_MAX_SEC 10
+#define TIMER_MAX_SEC 1000
/* Macros. */
#define THREAD_ARG(X) ((X)->arg)
void
thread_call (struct thread *thread);
+int
+thread_timer_cmp (struct timeval a, struct timeval b);
+
struct timeval
thread_timer_sub (struct timeval a, struct timeval b);
http_connect_thread(struct thread *thread);
extern int
-vrrp_state_init_thread(struct thread *thread);
+misc_check_thread(struct thread *thread);
+
+extern int
+vrrp_dispatcher_init_thread(struct thread *thread);
#endif
* using the smtp protocol according to the RFC 821. A non blocking
* timeouted connection is used to handle smtp protocol.
*
- * Version: $Id: smtp.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: smtp.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
struct thread_arg *thread_arg;
struct smtp_thread_arg *smtp_arg;
- /* allocate a new thread_arg */
- thread_arg = thread_arg_new(root, NULL, NULL);
+ /* Only send mail if email specified */
+ if (root->email) {
+ /* allocate a new thread_arg */
+ thread_arg = thread_arg_new(root, NULL, NULL);
- /* allocate & initialize smtp argument data structure */
- smtp_arg = (struct smtp_thread_arg *)malloc(sizeof(struct smtp_thread_arg));
- memset(smtp_arg, 0, sizeof(struct smtp_thread_arg));
+ /* allocate & initialize smtp argument data structure */
+ smtp_arg = (struct smtp_thread_arg *)malloc(sizeof(struct smtp_thread_arg));
+ memset(smtp_arg, 0, sizeof(struct smtp_thread_arg));
- smtp_arg->subject = (char *)malloc(MAX_SUBJECT_LENGTH);
- smtp_arg->body = (char *)malloc(MAX_BODY_LENGTH);
- memset(smtp_arg->subject, 0, MAX_SUBJECT_LENGTH);
- memset(smtp_arg->body, 0, MAX_BODY_LENGTH);
+ smtp_arg->subject = (char *)malloc(MAX_SUBJECT_LENGTH);
+ smtp_arg->body = (char *)malloc(MAX_BODY_LENGTH);
+ memset(smtp_arg->subject, 0, MAX_SUBJECT_LENGTH);
+ memset(smtp_arg->body, 0, MAX_BODY_LENGTH);
- smtp_arg->stage = connection; /* first smtp command set to HELO */
+ smtp_arg->stage = connection; /* first smtp command set to HELO */
- /* format subject if rserver is specified */
- if (rserver)
- snprintf(smtp_arg->subject, MAX_SUBJECT_LENGTH, "[%s] %s:%d - %s",
- root->lvs_id, inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port), subject);
- else
- snprintf(smtp_arg->subject, MAX_SUBJECT_LENGTH, "[%s] %s", root->lvs_id, subject);
+ /* format subject if rserver is specified */
+ if (rserver)
+ snprintf(smtp_arg->subject, MAX_SUBJECT_LENGTH, "[%s] %s:%d - %s",
+ root->lvs_id, inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port), subject);
+ else
+ snprintf(smtp_arg->subject, MAX_SUBJECT_LENGTH, "[%s] %s", root->lvs_id, subject);
- strncpy(smtp_arg->body, body, MAX_BODY_LENGTH);
+ strncpy(smtp_arg->body, body, MAX_BODY_LENGTH);
- thread_arg->checker_arg = smtp_arg;
+ thread_arg->checker_arg = smtp_arg;
- thread_add_event(master, smtp_connect_thread, thread_arg, 0);
+ thread_add_event(master, smtp_connect_thread, thread_arg, 0);
+ }
}
*
* Part: smtp.c include file.
*
- * Version: $Id: smtp.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: smtp.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: General program utils.
*
- * Version: $Id: utils.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: utils.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* master fails, a backup server takes over.
* The original implementation has been made by jerome etienne.
*
- * Version: $Id: vrrp.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
- * Based on the Jerome Etienne, <jetienne@arobas.net> code.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
*/
/* local include */
-#include "scheduler.h"
-#include "cfreader.h"
-#include "utils.h"
+#include "vrrp_scheduler.h"
#include "vrrp.h"
-/* local prototypes */
-static int vrrp_state_goto_master_thread(struct thread *thread);
-static int vrrp_state_master_thread(struct thread *thread);
-int vrrp_state_backup_thread(struct thread *thread);
-
/* compute checksum */
static u_short in_csum( u_short *addr, int len, u_short csum)
{
return (answer);
}
+/* retrieve MAC address from interface name */
+static int hwaddr_get(char *ifname, char *addr, int addrlen)
+{
+ struct ifreq ifr;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ int ret;
+
+ if (fd < 0) return (-1);
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ret = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
+ memcpy(addr, ifr.ifr_hwaddr.sa_data, addrlen);
+ close(fd);
+ return ret;
+}
+
/* resolve ipaddress from interface name */
-static uint32_t ifname_to_ip(char *ifname)
+static uint32_t ifname_to_ip(const char *ifname)
{
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
}
/* resolve interface index from interface name */
-static int ifname_to_idx(char *ifname)
+int ifname_to_idx(const char *ifname)
{
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
return ifindex;
}
-/* retrieve MAC options */
-static int rcvhwaddr_op(char *ifname, char *addr, int addrlen, int addF)
+/* resolve ifname from index */
+static void index_to_ifname(const int ifindex, char *ifname)
{
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
- int ret;
- if (fd < 0) return (-1);
+ if (fd < 0) return;
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- memcpy( ifr.ifr_hwaddr.sa_data, addr, addrlen );
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
-
- ret = ioctl(fd, addF ? SIOCADDMULTI : SIOCDELMULTI, (char *)&ifr);
- if (ret) {
- syslog(LOG_INFO, "Can't %s on %s. errno=%d"
- , addF ? "SIOCADDMULTI" : "SIOCDELMULTI"
- , ifname, errno );
- }
+ /* get interface name */
+ ifr.ifr_ifindex = ifindex;
+ if (ioctl(fd, SIOCGIFNAME, (char *)&ifr) == 0)
+ strncpy(ifname, ifr.ifr_name, sizeof(ifr.ifr_name));
close(fd);
- return ret;
}
-/* Set MAC address - need to shutdown the interface before */
-static int hwaddr_set(char *ifname, char *addr, int addrlen)
+/* resolve ipaddress from interface index */
+static uint32_t index_to_ip(const int ifindex)
{
- struct ifreq ifr;
- int fd = socket(AF_INET, SOCK_DGRAM, 0);
- int ret;
- unsigned long flags;
-
- if (fd < 0) return (-1);
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-
- /* get the flags */
- ret = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
- if (ret) goto end;
- flags = ifr.ifr_flags;
+ char ifname[IFNAMSIZ];
- /* set the interface down */
- ifr.ifr_flags &= ~IFF_UP;
- ret = ioctl(fd, SIOCSIFFLAGS, (char *)&ifr);
- if(ret) goto end;
+ memset(&ifname, 0, IFNAMSIZ);
+ index_to_ifname(ifindex, ifname);
- /* change the hwaddr */
- memcpy(ifr.ifr_hwaddr.sa_data, addr, addrlen);
- ifr.ifr_hwaddr.sa_family = AF_UNIX;
- ret = ioctl(fd, SIOCSIFHWADDR, (char *)&ifr);
- if(ret) goto end;
-
- /* set the interface up */
- ifr.ifr_flags = flags;
- ret = ioctl(fd, SIOCSIFFLAGS, (char *)&ifr);
- if(ret) goto end;
-
-end:;
- if (ret) syslog(LOG_INFO, "MAC set : error errno=%d", errno);
-
- close(fd);
- return ret;
-}
-
-/* retrieve MAC address from interface name */
-static int hwaddr_get(char *ifname, char *addr, int addrlen)
-{
- struct ifreq ifr;
- int fd = socket(AF_INET, SOCK_DGRAM, 0);
- int ret;
-
- if (fd < 0) return (-1);
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- ret = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
- memcpy(addr, ifr.ifr_hwaddr.sa_data, addrlen);
- close(fd);
- return ret;
+ return(ifname_to_ip(ifname));
}
/* add/remove VIP */
-static int ipaddr_ops(vrrp_rt *vsrv, int addF)
+static int vrrp_handle_ipaddress(vrrp_rt *vsrv, int cmd)
{
int i, err = 0;
+ int retry = 0;
int ifidx = ifname_to_idx(vsrv->vif->ifname);
struct in_addr in;
for(i = 0; i < vsrv->naddr; i++ ) {
vip_addr *vadd = &vsrv->vaddr[i];
- if(!addF && !vadd->deletable) continue;
-
- if (ipaddr_op(ifidx , vadd->addr, addF)) {
+ if(!cmd && !vadd->deletable) continue;
+retry:
+ if (netlink_address_ipv4(ifidx , vadd->addr, cmd) < 0) {
err = 1;
vadd->deletable = 0;
in.s_addr = htonl(vadd->addr);
syslog(LOG_INFO, "cant %s the address %s to %s\n"
- , addF ? "set" : "remove"
+ , cmd ? "set" : "remove"
, inet_ntoa(in)
, vsrv->vif->ifname);
+ if (cmd == VRRP_IPADDRESS_ADD) {
+ syslog(LOG_INFO, "try to delete eventual stalled ip");
+ netlink_address_ipv4(ifidx, vadd->addr, VRRP_IPADDRESS_DEL);
+ if (!retry) {
+ retry++;
+ goto retry;
+ }
+ }
} else {
vadd->deletable = 1;
}
}
/* IPSEC AH header length */
-static int vrrp_ipsecah_len(vrrp_rt *vsrv)
+int vrrp_ipsecah_len()
{
return sizeof(ipsec_ah);
}
* IPSEC AH incoming packet check.
* return 0 for a valid pkt, != 0 otherwise.
*/
-static int vrrp_in_chk_ipsecah( vrrp_rt *vsrv, char *buffer)
+static int vrrp_in_chk_ipsecah(vrrp_rt *vsrv, char *buffer)
{
struct iphdr *ip = (struct iphdr*)(buffer);
ipsec_ah *ah = (ipsec_ah *)((char *)ip + (ip->ihl<<2));
vsrv->ipsecah_counter->seq_number++;
if (ah->seq_number >= vsrv->ipsecah_counter->seq_number) {
#ifdef DEBUG
- syslog(LOG_DEBUG, "IPSEC AH : SEQUENCE NUMBER : %d\n", ah->seq_number);
+// syslog(LOG_DEBUG, "IPSEC AH : SEQUENCE NUMBER : %d\n", ah->seq_number);
#endif
vsrv->ipsecah_counter->seq_number = ah->seq_number;
} else {
memset(ah->auth_data, 0, sizeof(ah->auth_data));
/* Compute the ICV */
- hmac_md5(buffer, vrrp_iphdr_len(vsrv)+vrrp_ipsecah_len(vsrv)+vrrp_hd_len(vsrv),
+ hmac_md5(buffer, vrrp_iphdr_len(vsrv)+vrrp_ipsecah_len()+vrrp_hd_len(vsrv),
vsrv->vif->auth_data, sizeof(vsrv->vif->auth_data), digest);
- if (memcmp(backup_auth_data,digest,HMAC_MD5_TRUNC) != 0) {
+ if (memcmp(backup_auth_data, digest, HMAC_MD5_TRUNC) != 0) {
syslog(LOG_INFO, "IPSEC AH : invalid IPSEC HMAC-MD5 value."
" Due to fields mutation or bad password !");
return 1;
uint32_t ipbuf;
for (i=0; i < vsrv->naddr; i++) {
- bcopy(buffer+i*sizeof(uint32_t),&ipbuf,sizeof(uint32_t));
+ bcopy(buffer+i*sizeof(uint32_t), &ipbuf, sizeof(uint32_t));
if (ipaddr == ntohl(ipbuf)) return 1;
}
if (vif->auth_type == VRRP_AUTH_AH) {
ah = (ipsec_ah *)(buffer + sizeof(struct iphdr));
- hd = (vrrp_pkt *)(buffer + ihl + vrrp_ipsecah_len(vsrv));
+ hd = (vrrp_pkt *)(buffer + ihl + vrrp_ipsecah_len());
} else {
hd = (vrrp_pkt *)(buffer + ihl);
}
}
/* MUST verify that the VRID is valid on the receiving interface */
- if (vsrv->vrid != hd->vrid)
- return VRRP_PACKET_KO;
+ if (vsrv->vrid != hd->vrid) {
+ syslog(LOG_INFO, "received VRID mismatch. Received %d, Expected %d",
+ hd->vrid, vsrv->vrid);
+ return VRRP_PACKET_DROP;
+ }
/*
* MAY verify that the IP address(es) associated with the
, vsrv->vaddr[i].addr);
syslog(LOG_INFO, "one or more VIP associated with"
" VRID mismatch actual MASTER advert");
- return VRRP_PACKET_DROP;
+ return VRRP_PACKET_KO;
}
/*
/* check the authenicaion if it is ipsec ah */
if(hd->auth_type == VRRP_AUTH_AH)
- return(vrrp_in_chk_ipsecah(vsrv,buffer));
+ return(vrrp_in_chk_ipsecah(vsrv, buffer));
return VRRP_PACKET_OK;
}
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
- ip->tot_len = ip->ihl*4 + vrrp_hd_len( vsrv );
+ ip->tot_len = ip->ihl*4 + vrrp_hd_len(vsrv);
ip->tot_len = htons(ip->tot_len);
ip->id = ++vsrv->vif->ip_id;
ip->frag_off = 0;
ip->daddr = htonl(INADDR_VRRP_GROUP);
/* checksum must be done last */
- ip->check = in_csum( (u_short*)ip, ip->ihl*4, 0 );
+ ip->check = in_csum((u_short*)ip, ip->ihl*4, 0);
}
/* build IPSEC AH header */
ICV_mutable_fields *ip_mutable_fields;
unsigned char *digest;
struct iphdr *ip = (struct iphdr *)(buffer);
- ipsec_ah *ah = (ipsec_ah *)(buffer+sizeof(struct iphdr));
+ ipsec_ah *ah = (ipsec_ah *)(buffer + sizeof(struct iphdr));
/* alloc a temp memory space to stock the ip mutable fields */
- ip_mutable_fields=calloc(sizeof(ICV_mutable_fields),1);
- memset(ip_mutable_fields,0,sizeof(ICV_mutable_fields));
+ ip_mutable_fields=calloc(sizeof(ICV_mutable_fields), 1);
+ memset(ip_mutable_fields, 0, sizeof(ICV_mutable_fields));
/* fill in next header filed --rfc2402.2.1 */
ah->next_header = IPPROTO_VRRP;
/* update IP header total length value */
- ip->tot_len = ip->ihl*4 + vrrp_ipsecah_len( vsrv ) + vrrp_hd_len( vsrv );
+ ip->tot_len = ip->ihl*4 + vrrp_ipsecah_len() + vrrp_hd_len(vsrv);
ip->tot_len = htons(ip->tot_len);
/* update ip checksum */
/* copy the ip addresses */
for( i = 0; i < vsrv->naddr; i++ ){
- iparr[i] = htonl( vsrv->vaddr[i].addr );
+ iparr[i] = htonl(vsrv->vaddr[i].addr);
}
hd->chksum = in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0);
/* copy the passwd if the authentication is VRRP_AH_PASS */
if( vif->auth_type == VRRP_AUTH_PASS ){
- char *pw = (char *)hd+sizeof(*hd)+vsrv->naddr*4;
- memcpy( pw, vif->auth_data, sizeof(vif->auth_data));
+ char *pw = (char *)hd + sizeof(*hd) + vsrv->naddr*4;
+ memcpy(pw, vif->auth_data, sizeof(vif->auth_data));
}
return(0);
}
/* build VRRP packet */
-static void vrrp_build_pkt( vrrp_rt *vsrv, int prio, char *buffer, int buflen )
+static void vrrp_build_pkt(vrrp_rt *vsrv, int prio, char *buffer, int buflen)
{
char *bufptr;
/* build the ip header */
buffer += vrrp_dlt_len(vsrv);
buflen -= vrrp_dlt_len(vsrv);
- vrrp_build_ip( vsrv, buffer, buflen );
+ vrrp_build_ip(vsrv, buffer, buflen);
/* build the vrrp header */
buffer += vrrp_iphdr_len(vsrv);
if (vsrv->vif->auth_type == VRRP_AUTH_AH)
- buffer += vrrp_ipsecah_len(vsrv);
+ buffer += vrrp_ipsecah_len();
buflen -= vrrp_iphdr_len(vsrv);
if (vsrv->vif->auth_type == VRRP_AUTH_AH)
- buflen -= vrrp_ipsecah_len(vsrv);
+ buflen -= vrrp_ipsecah_len();
vrrp_build_vrrp(vsrv, prio, buffer, buflen);
/* build the IPSEC AH header */
if (vsrv->vif->auth_type == VRRP_AUTH_AH) {
bufptr += vrrp_dlt_len(vsrv);
- buflen += vrrp_ipsecah_len(vsrv) + vrrp_iphdr_len(vsrv);;
+ buflen += vrrp_ipsecah_len() + vrrp_iphdr_len(vsrv);;
vrrp_build_ipsecah(vsrv, bufptr, buflen);
}
}
int fd = socket(PF_PACKET, SOCK_PACKET, 0x300); /* 0x300 is magic */
if( fd < 0 ){
- syslog(LOG_DEBUG, "VRRP Error : socket creation");
+ syslog(LOG_INFO, "VRRP Error : socket creation");
return -1;
}
/* build the address */
memset(&from, 0 , sizeof(from));
- strcpy( from.sa_data, vsrv->vif->ifname );
+ strcpy(from.sa_data, vsrv->vif->ifname);
/* send the data */
len = sendto(fd, buffer, buflen, 0, &from, sizeof(from));
- close( fd );
+ close(fd);
return len;
}
/* alloc the memory */
buflen = vrrp_dlt_len(vsrv) + vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv);
if (vsrv->vif->auth_type == VRRP_AUTH_AH)
- buflen += vrrp_ipsecah_len(vsrv);
+ buflen += vrrp_ipsecah_len();
buffer = calloc(buflen, 1);
memset(buffer,0,buflen);
/* send it */
ret = vrrp_send_pkt(vsrv, buffer, buflen);
-#ifdef DEBUG
- syslog(LOG_DEBUG, "Sending VRRP Advert on %s", vsrv->vif->ifname);
-// printf("Sending on : %s : fd :%d\n", vsrv->vif->ifname,vsrv->sockfd);
-// print_buffer(buflen,buffer);
-#endif
/* free the memory */
free(buffer);
return ret;
}
-
/* Received packet processing */
-static int vrrp_read(vrrp_rt *vsrv, char *buf, int buflen)
+int vrrp_check_packet(vrrp_rt *vsrv, char *buf, int buflen)
{
- int len = 0;
int ret;
- len = read(vsrv->sockfd, buf, buflen);
-
-#ifdef DEBUG
- syslog(LOG_DEBUG, "VRRP packet received (%d bytes)", len);
-// print_buffer(buflen,buf);
-#endif
-
- if (len > 0) {
+ if (buflen > 0) {
ret = vrrp_in_chk(vsrv, buf);
- if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_DROP)
- syslog(LOG_INFO, "bogus VRRP packet received !!!");
+ if (ret == VRRP_PACKET_DROP) {
+ syslog(LOG_INFO, "Sync instance needed on %s !!!",
+ vsrv->vif->ifname);
+ }
+ if (ret == VRRP_PACKET_KO)
+ syslog(LOG_INFO, "bogus VRRP packet received on %s !!!",
+ vsrv->vif->ifname);
+// else
+// syslog(LOG_INFO, "Success receiving VRRP packet on %s.",
+// vsrv->vif->ifname);
return ret;
}
}
/* send a gratuitous ARP packet */
-static int send_gratuitous_arp(vrrp_rt *vsrv, int addr, int vAddrF)
+static int send_gratuitous_arp(vrrp_rt *vsrv, int addr)
{
struct m_arphdr {
unsigned short int ar_hrd; /* Format of hardware address. */
unsigned char __ar_tip[4]; /* Target IP address. */
};
- char buf[sizeof(struct m_arphdr)+ETHER_HDR_LEN];
- char buflen = sizeof(struct m_arphdr)+ETHER_HDR_LEN;
+ char buf[sizeof(struct m_arphdr) + ETHER_HDR_LEN];
+ char buflen = sizeof(struct m_arphdr) + ETHER_HDR_LEN;
struct ether_header *eth = (struct ether_header *)buf;
- struct m_arphdr *arph = (struct m_arphdr *)(buf+vrrp_dlt_len(vsrv));
- char *hwaddr = vAddrF ? vsrv->hwaddr : vsrv->vif->hwaddr;
+ struct m_arphdr *arph = (struct m_arphdr *)(buf + vrrp_dlt_len(vsrv));
+ char *hwaddr = vsrv->vif->hwaddr;
int hwlen = ETH_ALEN;
/* hardcoded for ethernet */
eth->ether_type = htons(ETHERTYPE_ARP);
/* build the arp payload */
- memset(arph, 0, sizeof( *arph ));
+ memset(arph, 0, sizeof(*arph));
arph->ar_hrd = htons(ARPHRD_ETHER);
arph->ar_pro = htons(ETHERTYPE_IP);
arph->ar_hln = 6;
return vrrp_send_pkt(vsrv, buf, buflen);
}
-/* becoming master */
-static int vrrp_state_goto_master_thread(struct thread *thread)
+/* Gratuitous ARP on each VIP */
+void vrrp_send_gratuitous_arp(vrrp_instance *vrrp_instance)
{
- int i;
- vrrp_instance *vrrp_instance = THREAD_ARG(thread);
+ int i, j;
vrrp_rt *vsrv = vrrp_instance->vsrv;
- vrrp_if *vif = vsrv->vif;
- struct rt_entry *rt_table;
-
- /* set the VRRP MAC address -- rfc2338.7.3 */
- if(!vsrv->no_vmac) {
- /* backup the routing table */
- rt_table = iproute_list(vif->ifname);
- hwaddr_set(vif->ifname, vsrv->hwaddr, sizeof(vsrv->hwaddr));
- rcvhwaddr_op(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 1);
+ /* send gratuitous arp for each virtual ip */
+ for (j = 0; j < 5; j++)
+ for (i = 0; i < vsrv->naddr; i++)
+ send_gratuitous_arp(vsrv, vsrv->vaddr[i].addr);
+}
- /* restore routing table */
- iproute_restore(rt_table, vif->ifname);
- iproute_clear(rt_table);
- }
+/* becoming master */
+void vrrp_state_goto_master(vrrp_instance *vrrp_instance)
+{
+ vrrp_rt *vsrv = vrrp_instance->vsrv;
/* add the ip addresses */
- ipaddr_ops(vsrv, 1);
+ vrrp_handle_ipaddress(vsrv, VRRP_IPADDRESS_ADD);
/* send an advertisement */
vrrp_send_adv(vsrv, vsrv->priority);
- /* send gratuitous arp for each virtual ip */
- for (i = 0; i < vsrv->naddr; i++)
- send_gratuitous_arp(vsrv, vsrv->vaddr[i].addr, 1);
+ /* remotes arp tables update */
+ vrrp_send_gratuitous_arp(vrrp_instance);
- syslog(LOG_INFO, "VRRP_Instance(%s) entering MASTER STATE"
+ syslog(LOG_INFO, "VRRP_Instance(%s) Entering MASTER STATE"
, vrrp_instance->iname);
- /* register master state thread */
vsrv->state = VRRP_STATE_MAST;
- thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
- vsrv->sockfd, vsrv->adver_int);
-
- return 0;
}
/* leaving master state */
static void vrrp_restore_interface(vrrp_rt *vsrv, int advF)
{
- uint32_t addr[1024];
- vrrp_if *vif = vsrv->vif;
- struct rt_entry *rt_table;
-
- /* restore the original MAC addresses */
- if (!vsrv->no_vmac) {
- /* backup the routing table */
- rt_table = iproute_list(vif->ifname);
-
- hwaddr_set(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr));
- rcvhwaddr_op(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 0);
-
- /* restore routing table */
- iproute_restore(rt_table, vif->ifname);
- iproute_clear(rt_table);
- }
-
/* remove the ip addresses */
- ipaddr_ops(vsrv, 0);
+ vrrp_handle_ipaddress(vsrv, VRRP_IPADDRESS_DEL);
- /* if we stop vrrpd, warn the other routers to speed up the recovery */
- if (advF) {
+ /* if we stop vrrp, warn the other routers to speed up the recovery */
+ if (advF)
vrrp_send_adv(vsrv, VRRP_PRIO_STOP);
- }
-
- /*
- * Send gratuitous ARP for all the non-vrrp ip addresses to update
- * the cache of remote hosts using these addresses
- */
- if (!vsrv->no_vmac) {
- int i, naddr;
- naddr = ipaddr_list(ifname_to_idx(vif->ifname), addr
- , sizeof(addr)/sizeof(addr[0]));
- for (i = 0; i < naddr; i++)
- send_gratuitous_arp(vsrv, addr[i], 0);
- }
}
-static int vrrp_state_leave_master_thread(struct thread *thread)
+void vrrp_state_leave_master(vrrp_instance *instance)
{
- vrrp_instance *vrrp_instance = THREAD_ARG(thread);
- vrrp_rt *vsrv = vrrp_instance->vsrv;
+ vrrp_rt *vsrv = instance->vsrv;
- /* restore the routing table & remove VIPs */
+ /* Remove VIPs */
vrrp_restore_interface(vsrv, 0);
syslog(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE"
- , vrrp_instance->iname);
+ , instance->iname);
/* register the vrrp backup handler */
vsrv->state = VRRP_STATE_BACK;
- thread_add_read(thread->master, vrrp_state_backup_thread, vrrp_instance,
- vsrv->sockfd, vsrv->ms_down_timer);
- return 0;
}
/* BACKUP state processing */
-int vrrp_state_backup_thread(struct thread *thread)
+void vrrp_state_backup(vrrp_instance *instance, char *buf, int buflen)
{
- char *buf;
int ret = 0;
- int buflen = 0;
- struct iphdr *iph;
+ vrrp_rt *vsrv = instance->vsrv;
+ struct iphdr *iph = (struct iphdr *)buf;
vrrp_pkt *hd;
- vrrp_instance *vrrp_instance = THREAD_ARG(thread);
- vrrp_rt *vsrv = vrrp_instance->vsrv;
-//printf("-----[ %s ]------\nBACKUP STATE fd : %d\n", vrrp_instance->iname, thread->u.fd);
-
- if (thread->type == THREAD_READ_TIMEOUT) {
-
- /* If becoming MASTER in IPSEC AH AUTH, we reset the anti-replay */
- if (vsrv->ipsecah_counter->cycle) {
- vsrv->ipsecah_counter->cycle = 0;
- vsrv->ipsecah_counter->seq_number = 0;
- }
-
- /* register the vrrp transit backup state */
- vsrv->state = VRRP_STATE_BACK;
- thread_add_event(thread->master, vrrp_state_goto_master_thread,
- vrrp_instance, VRRP_STATE_MAST);
-
- syslog(LOG_INFO, "VRRP_Instance(%s) becoming MASTER"
- , vrrp_instance->iname);
- } else {
- /* buffer allocation */
- if(vsrv->vif->auth_type == VRRP_AUTH_AH) {
- buflen = vrrp_iphdr_len(vsrv) + vrrp_ipsecah_len(vsrv) + vrrp_hd_len(vsrv);
- buf = calloc(buflen,1);
- memset(buf,0,buflen);
-
- /* fill the header structure */
- ret = vrrp_read(vsrv, buf, buflen);
- iph = (struct iphdr *)buf;
- hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len(vsrv));
- } else {
- buflen = vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv);
- buf = calloc(buflen, 1);
- memset(buf,0,buflen);
-
- /* fill the header structure */
- ret = vrrp_read( vsrv, buf, buflen );
- iph = (struct iphdr *)buf;
- hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
- }
-
- if (ret == VRRP_PACKET_KO ||
- ret == VRRP_PACKET_NULL ||
- ret == VRRP_PACKET_DROP) {
- syslog(LOG_INFO, "Dropping received advertisment...\n");
- vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
- } else if (hd->priority == 0) {
- vsrv->ms_down_timer = VRRP_TIMER_SKEW(vsrv);
- } else if( !vsrv->preempt || hd->priority >= vsrv->priority ) {
- vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
- }
+ /* Fill the VRRP header */
+ switch (iph->protocol) {
+ case IPPROTO_IPSEC_AH:
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len());
+ break;
+ case IPPROTO_VRRP:
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
+ break;
+ }
- /* register next vrrp master thread */
- thread_add_read(thread->master, vrrp_state_backup_thread, vrrp_instance,
- thread->u.fd, vsrv->ms_down_timer);
+ /* Process the incoming packet */
+ ret = vrrp_check_packet(vsrv, buf, buflen);
- free(buf);
+ if (ret == VRRP_PACKET_KO ||
+ ret == VRRP_PACKET_NULL) {
+ syslog(LOG_INFO, "VRRP_Instance(%s) ignoring received advertisment..."
+ , instance->iname);
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+ } else if (hd->priority == 0) {
+ vsrv->ms_down_timer = VRRP_TIMER_SKEW(vsrv);
+ } else if( !vsrv->preempt || hd->priority >= vsrv->priority ) {
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
}
-
- return 0;
}
/* MASTER state processing */
-static int vrrp_state_master_thread(struct thread *thread)
+void vrrp_state_master_tx(vrrp_instance *instance, const int prio)
{
- char *buf;
- int ret = 0;
- int buflen = 0;
- struct iphdr *iph;
- vrrp_pkt *hd;
- vrrp_instance *vrrp_instance = THREAD_ARG(thread);
- vrrp_rt *vsrv = vrrp_instance->vsrv;
-
-//printf("-----[ %s ]------\nMASTER STATE fd : %d\n", vrrp_instance->iname, thread->u.fd);
-
- if (thread->type == THREAD_READ_TIMEOUT) {
-
- if (vsrv->wantstate == VRRP_STATE_BACK ||
- vsrv->ipsecah_counter->cycle) {
- vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
-
- /* register the vrrp transit backup state */
- vsrv->state = VRRP_STATE_BACK;
- thread_add_event(thread->master, vrrp_state_leave_master_thread,
- vrrp_instance, VRRP_STATE_BACK);
-
- syslog(LOG_INFO, "VRRP_Instance(%s) becoming BACKUP"
- , vrrp_instance->iname);
- }
+ vrrp_rt *vsrv = instance->vsrv;
+ if (prio == VRRP_PRIO_OWNER)
+ vrrp_send_adv(vsrv, VRRP_PRIO_OWNER);
+ else
vrrp_send_adv(vsrv, vsrv->priority);
+}
- /* register next vrrp master thread */
- thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
- thread->u.fd, vsrv->adver_int);
- } else {
- /* buffer allocation */
- if (vsrv->vif->auth_type == VRRP_AUTH_AH) {
- buflen = vrrp_iphdr_len(vsrv) + vrrp_ipsecah_len(vsrv) + vrrp_hd_len(vsrv);
- buf = calloc(buflen,1);
- memset(buf,0,buflen);
-
- /* fill the header structure */
- ret = vrrp_read(vsrv, buf, buflen);
- iph = (struct iphdr *)buf;
- hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len(vsrv));
- } else {
- buflen = vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv);
- buf = calloc(buflen, 1);
- memset(buf,0,buflen);
-
- /* fill the header structure */
- ret = vrrp_read(vsrv, buf, buflen);
- iph = (struct iphdr *)buf;
- hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
- }
-
- if (ret == VRRP_PACKET_KO ||
- ret == VRRP_PACKET_NULL ||
- ret == VRRP_PACKET_DROP) {
- syslog(LOG_INFO, "Dropping received VRRP packet...\n");
- vrrp_send_adv(vsrv, vsrv->priority);
-
- /* register next vrrp master thread */
- thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
- thread->u.fd, vsrv->adver_int);
-
- } else if (hd->priority == 0) {
- vrrp_send_adv(vsrv, vsrv->priority);
-
- /* register next vrrp master thread */
- thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
- thread->u.fd, vsrv->adver_int);
+int vrrp_state_master_rx(vrrp_instance *instance, char *buf, int buflen)
+{
+ int ret = 0;
+ vrrp_rt *vsrv = instance->vsrv;
+ struct iphdr *iph = (struct iphdr *)buf;
+ vrrp_pkt *hd;
- } else if( hd->priority > vsrv->priority ||
- (hd->priority == vsrv->priority &&
- ntohl(iph->saddr) > vsrv->vif->ipaddr)) {
+ /* Fill the VRRP header */
+ switch (iph->protocol) {
+ case IPPROTO_IPSEC_AH:
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len());
+ break;
+ case IPPROTO_VRRP:
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
+ break;
+ }
- vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+ /* Process the incoming packet */
+ ret = vrrp_check_packet(vsrv, buf, buflen);
- /* register the vrrp transit backup state */
- vsrv->state = VRRP_STATE_BACK;
- thread_add_event(thread->master, vrrp_state_leave_master_thread,
- vrrp_instance, VRRP_STATE_BACK);
- }
- free(buf);
+ if (ret == VRRP_PACKET_KO ||
+ ret == VRRP_PACKET_NULL ||
+ ret == VRRP_PACKET_DROP) {
+ syslog(LOG_INFO, "VRRP_Instance(%s) Dropping received VRRP packet..."
+ , instance->iname);
+ vrrp_send_adv(vsrv, vsrv->priority);
+ return 0;
+ } else if (hd->priority == 0) {
+ vrrp_send_adv(vsrv, vsrv->priority);
+ return 0;
+ } else if( hd->priority > vsrv->priority ||
+ (hd->priority == vsrv->priority &&
+ ntohl(iph->saddr) > vsrv->vif->ipaddr)) {
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+ vsrv->state = VRRP_STATE_BACK;
+ return 1;
}
return 0;
return 0;
}
- /* vrrp structure is completed */
- vsrv->initF = 1;
-
return 1;
}
}
/* open the socket and join the multicast group. */
-static int open_vrrp_socket(vrrp_rt *vsrv)
+int open_vrrp_socket(const int proto, const int index)
{
- struct ip_mreq req;
- struct ip_mreqn interface;
- u_char loop;
+ struct ip_mreqn req_add;
+ char ifname[IFNAMSIZ];
int fd;
int ret;
/* open the socket */
- if (vsrv->vif->auth_type == VRRP_AUTH_AH)
- fd = socket(AF_INET, SOCK_RAW, IPPROTO_IPSEC_AH);
- else
- fd = socket(AF_INET, SOCK_RAW, IPPROTO_VRRP);
+ fd = socket(AF_INET, SOCK_RAW, proto);
- if(fd < 0){
+ if (fd < 0) {
int err = errno;
syslog(LOG_INFO, "cant open raw socket. errno=%d. (try to run it as root)"
, err);
return -1;
}
- /* join the multicast group */
- memset(&req, 0, sizeof (req));
- req.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
- req.imr_interface.s_addr = htonl(vsrv->vif->ipaddr);
- ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- (char *)&req, sizeof(struct ip_mreq));
-
- /* disable loop back to local socket */
- loop = 0;
-// setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
-
+ /* -> inbound processing option
+ * Specify the bound_dev_if.
+ * why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set
+ * sk->bound_dev_if themself ??? !!!
+ * Needed for filter multicasted advert per interface.
+ *
+ * -- If you read this !!! and know the answer to the question
+ * please feal free to answer me ! :)
+ */
+ memset(ifname, 0, IFNAMSIZ);
+ index_to_ifname(index, ifname);
+ ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
+ ifname, strlen(ifname)+1);
if (ret < 0) {
int err = errno;
- syslog(LOG_INFO, "cant do IP_ADD_MEMBERSHIP errno=%d", err);
+ syslog(LOG_INFO, "cant bind to device %s. errno=%d. (try to run it as root)",
+ ifname, err);
+ close(fd); /* sd leak handle */
return -1;
}
-#ifdef DEBUG
- else {
- syslog(LOG_DEBUG, "VRRP socket successfully created...");
- }
-#endif
-
- /* binding the socket to the local interface */
- memset(&interface, 0, sizeof(interface));
- interface.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
- interface.imr_address.s_addr = htonl(vsrv->vif->ipaddr);
- interface.imr_ifindex = ifname_to_idx(vsrv->vif->ifname);
- ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
- &interface, sizeof(struct ip_mreqn));
+ /* -> outbound processing option
+ * join the multicast group.
+ * binding the socket to the interface for outbound multicast
+ * traffic.
+ */
+ memset(&req_add, 0, sizeof (req_add));
+ req_add.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
+ req_add.imr_address.s_addr = htonl(index_to_ip(index));
+ req_add.imr_ifindex = index;
+ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&req_add, sizeof(struct ip_mreqn));
if (ret < 0) {
int err = errno;
- syslog(LOG_INFO, "cant bind socket to interface errno=%d", err);
+ syslog(LOG_INFO, "cant do IP_ADD_MEMBERSHIP errno=%d", err);
return -1;
}
return fd;
}
-/*
- * Initialize state handling
- * --rfc2338.6.4.1
- */
-int vrrp_state_init_thread(struct thread *thread)
-{
- vrrp_instance *vrrp_instance = THREAD_ARG(thread);
- vrrp_rt *vsrv = vrrp_instance->vsrv;
- int fd;
-
- /* create the socket */
- fd = open_vrrp_socket(vsrv);
- if (fd < 0) return -1;
-
- vsrv->sockfd = fd;
-
- if (vsrv->priority == VRRP_PRIO_OWNER ||
- vsrv->wantstate == VRRP_STATE_MAST){
- thread_add_event(thread->master, vrrp_state_goto_master_thread,
- vrrp_instance, VRRP_STATE_MAST);
- } else {
- vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
-
- syslog(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE"
- , vrrp_instance->iname);
-
- /* register the vrrp backup handler */
- vsrv->state = VRRP_STATE_BACK;
- thread_add_read(thread->master, vrrp_state_backup_thread,
- vrrp_instance, fd, vsrv->ms_down_timer);
- }
-
- return 0;
-}
-
/* handle terminate state */
void vrrp_state_stop_instance(vrrp_rt *vsrv)
{
/* restore MAC, routing table & remove VIPs */
- vrrp_restore_interface(vsrv, 1);
+ if (vsrv->state == VRRP_STATE_MAST)
+ vrrp_restore_interface(vsrv, 1);
}
* master fails, a backup server takes over.
* The original implementation has been made by jerome etienne.
*
- * Version: $Id: vrrp.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
* Based on the Jerome Etienne, <jetienne@arobas.net> code.
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <unistd.h>
/* local include */
-#include "vrrp_iproute.h"
+#include "cfreader.h"
#include "vrrp_ipaddress.h"
#include "vrrp_ipsecah.h"
+#include "utils.h"
typedef struct { /* rfc2338.5.1 */
uint8_t vers_type; /* 0-3=type, 4-7=version */
#define VRRP_ADVER_DFL 1 /* advert. interval (in sec) -- rfc2338.5.3.7 */
#define VRRP_PREEMPT_DFL 1 /* rfc2338.6.1.2.Preempt_Mode */
-typedef struct { /* parameters per interface -- rfc2338.6.1.1 */
+/* parameters per interface -- rfc2338.6.1.1 */
+typedef struct {
int auth_type; /* authentification type. VRRP_AUTH_* */
uint8_t auth_data[8]; /* authentification data */
* to warn the user only if the outoing mtu is too small
*/
int ip_id;
-
} vrrp_if;
typedef struct {
int deletable; /* TRUE if one of my primary addr */
} vip_addr;
-typedef struct { /* parameters per virtual router -- rfc2338.6.1.2 */
+/* parameters per virtual router -- rfc2338.6.1.2 */
+typedef struct {
int vrid; /* virtual id. from 1(!) to 255 */
int priority; /* priority value */
int naddr; /* number of ip addresses */
vip_addr *vaddr; /* point on the ip address array */
int adver_int; /* delay between advertisements(in sec) */
char hwaddr[6]; /* VMAC -- rfc2338.7.3 */
-
-#if 0 /* dynamically calculated */
- double skew_time; /* skew Master_Down_Interval. (256-Prio)/256 */
- int mast_down_int; /* interval for backup to declare master down*/
-#endif
int preempt; /* true if a higher prio preempt a lower one */
int state; /* internal state (init/backup/master) */
+ int init_state; /* the initial state of the instance */
int wantstate; /* user explicitly wants a state (back/mast) */
- int sockfd; /* the socket descriptor */
- int initF; /* true if the struct is init */
- int no_vmac; /* dont handle the virtual MAC --rfc2338.7.3 */
+ int fd; /* the socket descriptor */
/* rfc2336.6.2 */
uint32_t ms_down_timer;
- uint32_t adver_timer;
+ struct timeval sands;
/* IPSEC AH counter def --rfc2402.3.3.2 */
seq_counter *ipsecah_counter;
} vrrp_rt;
/* VRRP state machine -- rfc2338.6.4 */
-#define VRRP_STATE_INIT 1 /* rfc2338.6.4.1 */
-#define VRRP_STATE_BACK 2 /* rfc2338.6.4.2 */
-#define VRRP_STATE_MAST 3 /* rfc2338.6.4.3 */
-#define VRRP_STATE_NONE 99 /* internal */
+#define VRRP_DISPATCHER 0 /* internal */
+#define VRRP_STATE_INIT 1 /* rfc2338.6.4.1 */
+#define VRRP_STATE_BACK 2 /* rfc2338.6.4.2 */
+#define VRRP_STATE_MAST 3 /* rfc2338.6.4.3 */
+#define VRRP_STATE_GOTO_MASTER 4 /* internal */
+#define VRRP_STATE_LEAVE_MASTER 5 /* internal */
+#define VRRP_STATE_FAULT 99 /* internal */
/* VRRP packet handling */
-#define VRRP_PACKET_OK 0
-#define VRRP_PACKET_KO 1
-#define VRRP_PACKET_DROP 2
-#define VRRP_PACKET_NULL 3
+#define VRRP_PACKET_OK 0
+#define VRRP_PACKET_KO 1
+#define VRRP_PACKET_DROP 2
+#define VRRP_PACKET_NULL 3
+#define VRRP_PACKET_TEMP_LEN 256
#define VRRP_AUTH_LEN 8
-#define VRRP_IS_BAD_VID(id) ((id)<1 || (id)>255) /* rfc2338.6.1.vrid */
-#define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */
-#define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1)
+#define VRRP_IS_BAD_VID(id) ((id)<1 || (id)>255) /* rfc2338.6.1.vrid */
+#define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */
+#define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1)
-#define VRRP_TIMER_HZ 1000000
-#define VRRP_TIMER_SKEW( srv ) ((256-(srv)->priority)*VRRP_TIMER_HZ/256)
+#define VRRP_TIMER_HZ 1000000
+#define VRRP_TIMER_SKEW(srv) ((256-(srv)->priority)*VRRP_TIMER_HZ/256)
-#define VRRP_MIN( a , b ) ( (a) < (b) ? (a) : (b) )
-#define VRRP_MAX( a , b ) ( (a) > (b) ? (a) : (b) )
+#define VRRP_MIN(a, b) ((a) < (b)?(a):(b))
+#define VRRP_MAX(a, b) ((a) > (b)?(a):(b))
/* prototypes */
+extern int vrrp_ipsecah_len();
extern int complete_vrrp_init(vrrp_rt *vsrv);
extern void vrrp_state_stop_instance(vrrp_rt *vsrv);
* master fails, a backup server takes over.
* The original implementation has been made by jerome etienne.
*
- * Version: $Id: vrrp_ipaddress.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp_ipaddress.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* local include */
#include "vrrp_ipaddress.h"
-#include "libnetlink/libnetlink.h"
+#include "vrrp_netlink.h"
-static int get_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+int netlink_address_ipv4(int ifindex, uint32_t addr, int cmd)
{
- struct ifaddrmsg *ifa = NLMSG_DATA(n);
- int len = n->nlmsg_len;
- iplist_ctx *ctx = (iplist_ctx *)arg;
- struct rtattr *rta_tb[IFA_MAX+1];
-
- /* sanity check */
- len -= NLMSG_LENGTH(sizeof(*ifa));
- if (len < 0) {
- syslog(LOG_INFO, "IPADDRESS : BUG: wrong nlmsg len %d", len);
- return -1;
- }
-
- /* check the message type */
- if (n->nlmsg_type != RTM_NEWADDR)
- return 0;
- /* check it is ipv4 */
- if( ifa->ifa_family != AF_INET)
- return 0;
-
- /* check it is the good interface */
- if(ifa->ifa_index != ctx->ifindex)
- return 0;
-
- /* parse the attribute */
- memset(rta_tb, 0, sizeof(rta_tb));
- parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), len);
-
- if (!rta_tb[IFA_LOCAL])
- rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
-
- if (rta_tb[IFA_LOCAL]) {
- u_char *src = RTA_DATA(rta_tb[IFA_LOCAL]);
- if( ctx->nb_elem >= ctx->max_elem )
- return 0;
- ctx->addr[ctx->nb_elem++] = (src[0]<<24) + (src[1]<<16) +
- (src[2]<<8) + src[3];
- }
- return 0;
-}
-
-int ipaddr_list( int ifindex, uint32_t *array, int max_elem )
-{
- struct rtnl_handle rth;
- iplist_ctx ctx;
-
- /* init the struct */
- ctx.ifindex = ifindex;
- ctx.addr = array;
- ctx.max_elem = max_elem;
- ctx.nb_elem = 0;
-
- /* open the rtnetlink socket */
- if( rtnl_open( &rth, 0) )
- return -1;
-
- /* send the request */
- if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETADDR) < 0) {
- syslog(LOG_INFO, "IPADDRESS : Cannot send dump request");
- return -1;
- }
-
- /* parse the answer */
- if (rtnl_dump_filter(&rth, get_addrinfo, &ctx, NULL, NULL) < 0) {
- syslog(LOG_INFO, "IPADDRESS : Flush terminated");
- exit(1);
- }
-
- /* to close the clocket */
- rtnl_close(&rth);
-
- return ctx.nb_elem;
-}
-
-int ipaddr_op(int ifindex, uint32_t addr, int addF)
-{
- struct rtnl_handle rth;
+ struct nl_handle nlh;
struct {
- struct nlmsghdr n;
- struct ifaddrmsg ifa;
- char buf[256];
+ struct nlmsghdr n;
+ struct ifaddrmsg ifa;
+ char buf[256];
} req;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_type = addF ? RTM_NEWADDR : RTM_DELADDR;
+ req.n.nlmsg_type = cmd ? RTM_NEWADDR:RTM_DELADDR;
req.ifa.ifa_family = AF_INET;
req.ifa.ifa_index = ifindex;
req.ifa.ifa_prefixlen = 32;
addr = htonl(addr);
addattr_l(&req.n, sizeof(req), IFA_LOCAL, &addr, sizeof(addr));
- if (rtnl_open(&rth, 0) < 0)
+ if (netlink_socket(&nlh, 0) < 0)
return -1;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+
+ if (netlink_talk(&nlh, &req.n) < 0)
return -1;
/* to close the clocket */
- rtnl_close( &rth );
+ netlink_close(&nlh);
return(0);
}
-
*
* Part: vrrp_ipaddress.c include file.
*
- * Version: $Id: vrrp_ipaddress.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp_ipaddress.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include <string.h>
#include <syslog.h>
-/* types definitions */
-typedef struct {
- int ifindex;
- uint32_t *addr;
- int max_elem;
- int nb_elem;
-} iplist_ctx;
+/* types definition */
+#define VRRP_IPADDRESS_DEL 0
+#define VRRP_IPADDRESS_ADD 1
/* prototypes */
-int ipaddr_list(int ifindex, uint32_t *array, int max_elem);
-int ipaddr_op(int ifindex, uint32_t addr, int addF);
-
+extern int netlink_address_ipv4(int ifindex, uint32_t addr, int cmd);
+
#endif
+++ /dev/null
-/*
- * 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: Routing utilities using the NETLINK kernel interface.
- *
- * Version: $Id: vrrp_iproute.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
- *
- * 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.
- */
-
-/* local includes */
-#include "vrrp_iproute.h"
-#include "libnetlink/libnetlink.h"
-#include "libnetlink/ll_map.h"
-#include "utils.h"
-
-/* Allocation function */
-struct rt_entry * iproute_new()
-{
- struct rt_entry *entry;
-
- entry = (struct rt_entry *)malloc(sizeof(struct rt_entry));
- memset(entry, 0, sizeof(struct rt_entry));
-
- entry->rtm = (struct rtmsg *)malloc(sizeof(struct rtmsg));
- memset(entry->rtm, 0, sizeof(struct rtmsg));
-
- return entry;
-}
-
-/* free memory */
-void iproute_del(struct rt_entry *entry)
-{
- free(entry->rtm);
- free(entry);
-}
-
-/* destroy functions */
-struct rt_entry * clear_entry(struct rt_entry *entry)
-{
- struct rt_entry *t;
-
- t = (struct rt_entry *)entry->next;
- iproute_del(entry);
- return t;
-}
-
-void iproute_clear(struct rt_entry *lstentry)
-{
- while (lstentry)
- lstentry = clear_entry(lstentry);
-}
-
-/* Append rt entry function */
-struct rt_entry * iproute_append(struct rt_entry *lstentry, struct rt_entry *entry)
-{
- struct rt_entry *ptr = lstentry;
-
- if (lstentry) {
- while (lstentry->next) lstentry = (struct rt_entry *)lstentry->next;
- lstentry->next = (struct rt_entry *)entry;
- return ptr;
- } else {
- lstentry = entry;
- return lstentry;
- }
-}
-
-/* Our rt netlink filter */
-int iproute_filter(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
-{
- struct rt_entry *rtarg;
- struct rtmsg *r = NLMSG_DATA(n);
- int len = n->nlmsg_len;
- struct rtattr *tb[RTA_MAX+1];
- struct rt_entry *entry;
-
- rtarg = (struct rt_entry *)arg;
-
- /* Just lookup the Main routing table */
- if (r->rtm_table != RT_TABLE_MAIN)
- return 0;
-
- /* init len value */
- len -= NLMSG_LENGTH(sizeof(*r));
- if (len <0) {
- syslog(LOG_INFO, "IPROUTE : BUG: wrong nlmsg len %d", len);
- return -1;
- }
-
- /* init the parse attribute space */
- memset(tb, 0, sizeof(tb));
- parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
-
- /*
- * we return from filter when route is
- * cloned from another route, learn by an
- * ICMP redirect or set by kernel.
- * Return too when rt type != gateway or direct route.
- */
- if (r->rtm_flags & RTM_F_CLONED)
- return 0;
- if (r->rtm_protocol == RTPROT_REDIRECT)
- return 0;
- if (r->rtm_protocol == RTPROT_KERNEL)
- return 0;
- if (r->rtm_type != RTN_UNICAST)
- return 0;
-
- if (tb[RTA_OIF]) {
- /* alloc new memory entry */
- entry = iproute_new();
-
- /* copy the rtmsg infos */
- memcpy(entry->rtm, r, sizeof(struct rtmsg));
-
- /*
- * can use RTA_PAYLOAD(tb[RTA_SRC])
- * but ipv4 addr are 4 bytes coded
- */
- entry->oif = *(int *) RTA_DATA(tb[RTA_OIF]);
- if (tb[RTA_SRC]) memcpy(&entry->src, RTA_DATA(tb[RTA_SRC]), 4);
- if (tb[RTA_PREFSRC]) memcpy(&entry->psrc, RTA_DATA(tb[RTA_PREFSRC]), 4);
- if (tb[RTA_DST]) memcpy(&entry->dest, RTA_DATA(tb[RTA_DST]), 4);
- if (tb[RTA_GATEWAY]) memcpy(&entry->gate, RTA_DATA(tb[RTA_GATEWAY]), 4);
- if (tb[RTA_FLOW]) memcpy(&entry->flow, RTA_DATA(tb[RTA_FLOW]), 4);
- if (tb[RTA_IIF]) entry->iif = *(int *) RTA_DATA(tb[RTA_IIF]);
- if (tb[RTA_PRIORITY]) entry->prio = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
- if (tb[RTA_METRICS]) entry->metrics = *(int *) RTA_DATA(tb[RTA_METRICS]);
-
- /* save this entry */
- rtarg = iproute_append(rtarg, entry);
- }
-
- return 0;
-}
-
-struct rt_entry * iproute_fetch(struct rt_entry *r)
-{
- struct rtnl_handle rth;
-
- if (rtnl_open(&rth, 0) < 0) {
- syslog(LOG_INFO, "IPROUTE : Can not initialize netlink interface...");
- return NULL;
- }
-
- ll_init_map(&rth);
-
- if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETROUTE) < 0) {
- syslog(LOG_INFO, "IPROUTE : Cannot send dump request.");
- close(rth.fd);
- return NULL;
- }
-
- if (rtnl_dump_filter(&rth, iproute_filter, r, NULL, NULL) < 0) {
- syslog(LOG_INFO, "IPROUTE : Dump terminated.");
- close(rth.fd);
- return NULL;
- }
-
- close(rth.fd);
- return r;
-}
-
-int iproute_restore_entry(struct rt_entry *r)
-{
- struct rtnl_handle rth;
-
- struct {
- struct nlmsghdr n;
- struct rtmsg r;
- char buf[1024];
- } req;
-
- memset(&req, 0, sizeof(req));
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
- req.n.nlmsg_type = RTM_NEWROUTE;
-
- memcpy(&req.r, r->rtm, sizeof(struct rtmsg));
-
- if (r->src)
- addattr_l(&req.n, sizeof(req), RTA_SRC, &r->src, 4);
- if (r->psrc)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &r->psrc, 4);
- if (r->dest)
- addattr_l(&req.n, sizeof(req), RTA_DST, &r->dest, 4);
- if (r->gate)
- addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &r->gate, 4);
- if (r->flow)
- addattr_l(&req.n, sizeof(req), RTA_FLOW, &r->flow, 4);
-
- if (r->oif)
- addattr32(&req.n, sizeof(req), RTA_OIF, r->oif);
- if (r->iif)
- addattr32(&req.n, sizeof(req), RTA_IIF, r->iif);
- if (r->prio)
- addattr32(&req.n, sizeof(req), RTA_PRIORITY, r->prio);
- if (r->metrics)
- addattr32(&req.n, sizeof(req), RTA_METRICS, r->metrics);
-
- if (rtnl_open(&rth, 0) < 0) {
- syslog(LOG_INFO, "IPROUTE : Can not initialize netlink interface...");
- return -1;
- }
-
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
- syslog(LOG_INFO, "IPROUTE : Can not talk with netlink interface...");
- return -1;
- }
-
- return 0;
-}
-
-/* rt netlink dump function */
-void iproute_dump(struct rt_entry *r)
-{
- while (r) {
- if (r->src) syslog(LOG_DEBUG, "src %s ", ip_ntoa(r->src));
- if (r->psrc) syslog(LOG_DEBUG, "prefsrc %s ", ip_ntoa(r->psrc));
- if (r->iif) syslog(LOG_DEBUG, "idev %s", ll_index_to_name(r->iif));
-
- if (r->dest) syslog(LOG_DEBUG, "dest %s ", ip_ntoa(r->dest));
- if (r->gate) syslog(LOG_DEBUG, "gateway %s ", ip_ntoa(r->gate));
-
- if (r->prio) syslog(LOG_DEBUG, "priority %d ", r->prio);
- if (r->metrics) syslog(LOG_DEBUG, "metrics %d ", r->metrics);
-
- if (r->oif) syslog(LOG_DEBUG, "odev %s ", ll_index_to_name(r->oif));
-
- /* rtmsg specifics */
- if (r->rtm->rtm_dst_len) syslog(LOG_DEBUG, "mask %d ", r->rtm->rtm_dst_len);
- if (r->rtm->rtm_scope == RT_SCOPE_LINK) syslog(LOG_DEBUG, "scope link");
-
- printf("\n");
-
- r = (struct rt_entry *)r->next;
- }
-}
-
-struct rt_entry *iproute_list(char *dev)
-{
- struct rt_entry rt_table;
-
- /* Fetch the main routing table */
- memset(&rt_table, 0, sizeof(struct rt_entry));
- if (!iproute_fetch(&rt_table)) return NULL;
-
- return rt_table.next;
-}
-
-int iproute_restore(struct rt_entry *lstentry, char *dev)
-{
- int idx = ll_name_to_index(dev);
- int ret = 0;
-
- while (lstentry) {
- if (lstentry->oif == idx) {
- ret = iproute_restore_entry(lstentry);
- if (ret < 0) return ret;
- }
-
- lstentry = (struct rt_entry *)lstentry->next;
- }
-
- return 0;
-}
* authentication data encryption using HMAC MD5 according to
* RFCs 2085 & 2104.
*
- * Version: $Id: vrrp_ipsecah.c,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp_ipsecah.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: vrrp_ipsecah.c include file.
*
- * Version: $Id: vrrp_ipsecah.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp_ipsecah.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
--- /dev/null
+/*
+ * 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: NETLINK kernel command channel.
+ *
+ * Version: $Id: vrrp_netlink.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ *
+ * 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.
+ */
+
+/* local include */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <net/if_arp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/uio.h>
+
+#include "vrrp_netlink.h"
+
+/* Create a socket to netlink interface */
+int netlink_socket(struct nl_handle *nl, unsigned long groups)
+{
+ int addr_len;
+ int ret;
+
+ memset(nl, 0, sizeof(nl));
+
+ nl->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (nl->fd < 0) {
+ syslog(LOG_INFO, "Netlink: Cannot open netlink socket : (%s)"
+ , strerror(errno));
+ return -1;
+ }
+
+ ret = fcntl(nl->fd, F_SETFL, O_NONBLOCK);
+ if (ret < 0) {
+ syslog(LOG_INFO, "Netlink: Cannot set netlink socket flags : (%s)"
+ , strerror(errno));
+ close(nl->fd);
+ return -1;
+ }
+
+ memset(&nl->snl, 0, sizeof(nl->snl));
+ nl->snl.nl_family = AF_NETLINK;
+ nl->snl.nl_groups = groups;
+
+ ret = bind(nl->fd, (struct sockaddr*)&nl->snl, sizeof(nl->snl));
+ if (ret < 0) {
+ syslog(LOG_INFO, "Netlink: Cannot bind netlink socket : (%s)"
+ , strerror(errno));
+ close(nl->fd);
+ return -1;
+ }
+
+ addr_len = sizeof(nl->snl);
+ ret = getsockname(nl->fd, (struct sockaddr *)&nl->snl, &addr_len);
+ if (ret < 0 || addr_len != sizeof(nl->snl)) {
+ syslog(LOG_INFO, "Netlink: Cannot getsockname : (%s)"
+ , strerror(errno));
+ close(nl->fd);
+ return -1;
+ }
+
+ if (nl->snl.nl_family != AF_NETLINK) {
+ syslog(LOG_INFO, "Netlink: Wrong address family %d", nl->snl.nl_family);
+ close(nl->fd);
+ return -1;
+ }
+
+ nl->seq = time(NULL);
+
+ return ret;
+}
+
+/* Close a netlink socket */
+int netlink_close(struct nl_handle *nl)
+{
+ close(nl->fd);
+ return 0;
+}
+
+/* iproute2 utility function */
+int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
+{
+ int len = RTA_LENGTH(alen);
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
+ return -1;
+
+ rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy(RTA_DATA(rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+
+ return 0;
+}
+
+/* Our netlink parser */
+static int netlink_parse_info(int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
+ struct nl_handle *nl)
+{
+ int status;
+ int ret = 0;
+ int error;
+
+ while (1) {
+ char buf[4096];
+ struct iovec iov = { buf, sizeof buf };
+ struct sockaddr_nl snl;
+ struct msghdr msg = {(void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};
+ struct nlmsghdr *h;
+
+ status = recvmsg (nl->fd, &msg, 0);
+
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK)
+ break;
+ syslog(LOG_INFO, "Netlink: Received message overrun");
+ continue;
+ }
+
+ if (status == 0) {
+ syslog(LOG_INFO, "Netlink: EOF");
+ return -1;
+ }
+
+ if (msg.msg_namelen != sizeof snl) {
+ syslog(LOG_INFO, "Netlink: Sender address length error: length %d"
+ , msg.msg_namelen);
+ return -1;
+ }
+
+ for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
+ h = NLMSG_NEXT (h, status)) {
+ /* Finish of reading. */
+ if (h->nlmsg_type == NLMSG_DONE)
+ return ret;
+
+ /* Error handling. */
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
+ if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
+ syslog(LOG_INFO, "Netlink: error: message truncated");
+ return -1;
+ }
+ syslog (LOG_INFO, "Netlink: error: %s, type=(%u), seq=%u, pid=%d"
+ , strerror (-err->error)
+ , err->msg.nlmsg_type, err->msg.nlmsg_seq
+ , err->msg.nlmsg_pid);
+
+ return -1;
+ }
+
+ error = (*filter) (&snl, h);
+ if (error < 0) {
+ syslog(LOG_INFO, "Netlink: filter function error");
+ ret = error;
+ }
+ }
+
+ /* After error care. */
+ if (msg.msg_flags & MSG_TRUNC) {
+ syslog(LOG_INFO, "Netlink: error: message truncated");
+ continue;
+ }
+ if (status) {
+ syslog(LOG_INFO, "Netlink: error: data remnant size %d", status);
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+/* Out talk filter */
+static int netlink_talk_filter(struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+ syslog(LOG_INFO, "Netlink: ignoring message type 0x%04x"
+ , h->nlmsg_type);
+ return 0;
+}
+
+/* send message to netlink kernel socket, then receive response */
+int netlink_talk(struct nl_handle *nl, struct nlmsghdr *n)
+{
+ int status;
+ struct sockaddr_nl snl;
+ struct iovec iov = { (void*) n, n->nlmsg_len };
+ struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
+
+ memset(&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+
+ n->nlmsg_seq = ++nl->seq;
+
+ /* Send message to netlink interface. */
+ status = sendmsg(nl->fd, &msg, 0);
+ if (status < 0) {
+ syslog(LOG_INFO, "Netlink: sendmsg() error: %s"
+ , strerror (errno));
+ return -1;
+ }
+
+ status = netlink_parse_info(netlink_talk_filter, nl);
+ return status;
+}
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
*
- * Part: vrrp_iproute.c include file.
+ * Part: vrrp_netlink.c include file.
*
- * Version: $Id: vrrp_iproute.h,v 0.4.1 2001/09/14 00:37:56 acassen Exp $
+ * Version: $Id: vrrp_netlink.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* 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.
*/
-#ifndef _VRRP_IPROUTE_H
-#define _VRRP_IPROUTE_H
-
-/* global includes */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <syslog.h>
-
-/* specify a routing entry */
-struct rt_entry {
- struct rtmsg *rtm;
+#ifndef _VRRP_NETLINK_H
+#define _VRRP_NETLINK_H 1
- uint32_t psrc;
- uint32_t src;
- uint32_t dest;
- uint32_t gate;
- uint32_t flow;
- int iif;
- int oif;
- int prio;
- int metrics;
+/* Hack for GNU libc version 2. */
+#ifndef MSG_TRUNC
+#define MSG_TRUNC 0x20
+#endif /* MSG_TRUNC */
- struct rt_entry *next;
+/* global includes */
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+/* types definitions */
+struct nl_handle {
+ int fd;
+ struct sockaddr_nl snl;
+ __u32 seq;
};
/* prototypes */
-
-extern struct rt_entry *iproute_fetch(struct rt_entry *r);
-extern void iproute_dump(struct rt_entry *r);
-extern void iproute_clear(struct rt_entry *lstentry);
-extern int iproute_restore(struct rt_entry *lstentry, char *dev);
-extern struct rt_entry *iproute_list(char *dev);
+extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen);
+extern int netlink_socket(struct nl_handle *nl, unsigned long groups);
+extern int netlink_close(struct nl_handle *nl);
+extern int netlink_talk (struct nl_handle *nl, struct nlmsghdr *n);
#endif
--- /dev/null
+/*
+ * 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: Sheduling framework for vrrp code.
+ *
+ * Version: $Id: vrrp_scheduler.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ *
+ * 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.
+ */
+
+#include "vrrp_scheduler.h"
+#include "vrrp_ipsecah.h"
+#include "vrrp.h"
+
+/*
+ * Initialize state handling
+ * --rfc2338.6.4.1
+ */
+static void vrrp_init_state(vrrp_instance *instance)
+{
+ vrrp_instance *vrrpptr = instance;
+
+ while (instance) {
+ if (instance->vsrv->priority == VRRP_PRIO_OWNER ||
+ instance->vsrv->wantstate == VRRP_STATE_MAST) {
+ instance->vsrv->state = VRRP_STATE_GOTO_MASTER;
+ } else {
+ instance->vsrv->ms_down_timer = 3 * instance->vsrv->adver_int
+ + VRRP_TIMER_SKEW(instance->vsrv);
+ instance->vsrv->state = VRRP_STATE_BACK;
+ }
+
+ instance = (vrrp_instance *)instance->next;
+ }
+ instance = vrrpptr;
+}
+
+static void vrrp_init_instance_sands(vrrp_instance *instance)
+{
+ struct timeval timer_now;
+
+ gettimeofday(&timer_now, NULL);
+
+ if (instance->vsrv->state == VRRP_STATE_BACK) {
+ instance->vsrv->sands.tv_sec = timer_now.tv_sec +
+ instance->vsrv->ms_down_timer / VRRP_TIMER_HZ;
+ instance->vsrv->sands.tv_usec = timer_now.tv_usec +
+ instance->vsrv->ms_down_timer % VRRP_TIMER_HZ;
+ }
+ if (instance->vsrv->state == VRRP_STATE_GOTO_MASTER ||
+ instance->vsrv->state == VRRP_STATE_MAST) {
+ instance->vsrv->sands.tv_sec = timer_now.tv_sec +
+ instance->vsrv->adver_int / VRRP_TIMER_HZ;
+ instance->vsrv->sands.tv_usec = timer_now.tv_usec;
+ }
+}
+
+static void vrrp_init_sands(vrrp_instance *instance)
+{
+ vrrp_instance *vrrpptr = instance;
+
+ while (instance) {
+ vrrp_init_instance_sands(instance);
+
+ instance = (vrrp_instance *)instance->next;
+ }
+ instance = vrrpptr;
+}
+
+/* Timer functions */
+static struct timeval vrrp_compute_timer(const int fd, vrrp_instance *vrrp)
+{
+ vrrp_instance *ptr = vrrp;
+ struct timeval timer;
+
+ /* clean the memory */
+ memset(&timer, 0, sizeof(struct timeval));
+
+ while (vrrp) {
+ if (vrrp->vsrv->fd == fd) {
+ if (thread_timer_cmp(vrrp->vsrv->sands, timer) < 0 ||
+ (timer.tv_sec == 0 && timer.tv_usec == 0)) {
+ timer.tv_sec = vrrp->vsrv->sands.tv_sec;
+ timer.tv_usec = vrrp->vsrv->sands.tv_usec;
+ }
+ }
+
+ vrrp = (vrrp_instance *)vrrp->next;
+ }
+ vrrp = ptr;
+
+ return timer;
+}
+
+static struct timeval vrrp_timer_delta(struct timeval timer)
+{
+ struct timeval timer_now;
+
+ /* init timer */
+ memset(&timer_now, 0, sizeof(struct timeval));
+ gettimeofday(&timer_now, NULL);
+
+ return(thread_timer_sub(timer, timer_now));
+}
+
+static long vrrp_timer_fd(const int fd, vrrp_instance *instance)
+{
+ struct timeval timer;
+ long vrrp_timer = 0;
+
+ timer = vrrp_compute_timer(fd, instance);
+ timer = vrrp_timer_delta(timer);
+ vrrp_timer = timer.tv_sec * VRRP_TIMER_HZ + timer.tv_usec;
+
+ return vrrp_timer;
+}
+
+static int vrrp_timer_vrid_timeout(const int fd, vrrp_instance *vrrp)
+{
+ vrrp_instance *ptr = vrrp;
+ struct timeval vrrp_timer;
+ int vrid = 0;
+
+ /* clean the memory */
+ memset(&vrrp_timer, 0, sizeof(struct timeval));
+ vrrp_timer = vrrp_compute_timer(fd, vrrp);
+
+ while (vrrp) {
+ if (thread_timer_cmp(vrrp->vsrv->sands, vrrp_timer) == 0)
+ vrid = vrrp->vsrv->vrid;
+
+ vrrp = (vrrp_instance *)vrrp->next;
+ }
+ vrrp = ptr;
+
+ return vrid;
+}
+
+/* Simple dump function
+static void vrrp_timer_dump(vrrp_instance *vrrp)
+{
+ vrrp_instance *ptr = vrrp;
+ struct timeval timer_now;
+ struct timeval timer;
+ long vrrp_timer = 0;
+
+ memset(&timer, 0, sizeof(struct timeval));
+ memset(&timer_now, 0, sizeof(struct timeval));
+ gettimeofday(&timer_now, NULL);
+
+ while (vrrp) {
+ timer = thread_timer_sub(vrrp->vsrv->sands, timer_now);
+ vrrp_timer = timer.tv_sec * VRRP_TIMER_HZ + timer.tv_usec;
+ syslog(LOG_DEBUG, "Timer(vrid,value) : (%d,%d)", vrrp->vsrv->vrid, vrrp_timer);
+
+ vrrp = (vrrp_instance *)vrrp->next;
+ }
+ vrrp = ptr;
+}
+*/
+
+/* Thread functions */
+static void vrrp_register_workers(struct thread_master *master,
+ vrrp_instance *instance,
+ sockpool *pool)
+{
+ sockpool *poolptr = pool;
+ struct timeval timer;
+ long vrrp_timer = 0;
+
+ /* init compute timer */
+ memset(&timer, 0, sizeof(struct timeval));
+
+ /* Init the VRRP instances state */
+ vrrp_init_state(instance);
+
+ /* Init VRRP instances sands */
+ vrrp_init_sands(instance);
+
+ while (pool) {
+ /* jump to asynchronous handling */
+ vrrp_timer = vrrp_timer_fd(pool->fd, instance);
+ thread_add_read(master, vrrp_read_dispatcher_thread,
+ instance, pool->fd, vrrp_timer);
+
+ pool = (sockpool *)pool->next;
+ }
+ pool = poolptr;
+}
+
+/* VRRP dispatcher functions */
+static int already_exist_sock(sockpool *lstptr, int ifindex, int proto)
+{
+ sockpool *ptrpool = lstptr;
+
+ while (lstptr) {
+ if ((lstptr->ifindex == ifindex) && (lstptr->proto == proto)) {
+ lstptr = ptrpool;
+ return 1;
+ }
+ lstptr = (sockpool *)lstptr->next;
+ }
+ lstptr = ptrpool;
+ return 0;
+}
+
+static sockpool *add_sock(sockpool *lstsock, sockpool *sock)
+{
+ sockpool *ptrpool = lstsock;
+
+ if (lstsock) {
+ while (lstsock->next) lstsock = (sockpool *)lstsock->next;
+ lstsock->next = (struct sockpool *)sock;
+ return ptrpool;
+ } else {
+ lstsock = sock;
+ return lstsock;
+ }
+}
+
+static sockpool *remove_sock(sockpool *pool)
+{
+ sockpool *t;
+
+ t = (sockpool *)pool->next;
+ free(pool);
+ return t;
+}
+
+static void clear_sockpool(sockpool *pool)
+{
+ while (pool)
+ pool = remove_sock(pool);
+}
+
+static sockpool *vrrp_create_sockpool(vrrp_instance *instance, sockpool *pool)
+{
+ vrrp_instance *ptr = instance;
+ sockpool *sock;
+ int ifindex;
+ int proto;
+
+ while (instance) {
+ ifindex = ifname_to_idx(instance->vsrv->vif->ifname);
+ if (instance->vsrv->vif->auth_type == VRRP_AUTH_AH)
+ proto = IPPROTO_IPSEC_AH;
+ else
+ proto = IPPROTO_VRRP;
+
+ if (!already_exist_sock(pool, ifindex, proto)) {
+ /* allocate & clean the new struct */
+ sock = (sockpool *)malloc(sizeof(sockpool));
+ memset(sock, 0, sizeof(sockpool));
+
+ /* fill in the new sock structure */
+ sock->ifindex = ifindex;
+ sock->proto = proto;
+ pool = add_sock(pool, sock);
+ }
+
+ instance = (vrrp_instance *)instance->next;
+ }
+
+ instance = ptr;
+ return pool;
+}
+
+static void vrrp_open_sockpool(sockpool *pool)
+{
+ sockpool *ptr = pool;
+
+ while (pool) {
+ pool->fd = open_vrrp_socket(pool->proto, pool->ifindex);
+ syslog(LOG_DEBUG, "sockpool -> ifindex %d, proto %d, fd %d",
+ pool->ifindex, pool->proto, pool->fd);
+ pool = (sockpool *)pool->next;
+ }
+ pool = ptr;
+}
+
+static void vrrp_set_fds(vrrp_instance *instance, sockpool *pool)
+{
+ sockpool *ptr = pool;
+ vrrp_instance *ptrvrrp = instance;
+ int proto;
+
+ while (pool) {
+ while (instance) {
+ if (instance->vsrv->vif->auth_type == VRRP_AUTH_AH)
+ proto = IPPROTO_IPSEC_AH;
+ else
+ proto = IPPROTO_VRRP;
+
+ if ((pool->ifindex == ifname_to_idx(instance->vsrv->vif->ifname)) &&
+ (pool->proto == proto))
+ instance->vsrv->fd = pool->fd;
+
+ instance = (vrrp_instance *)instance->next;
+ }
+ instance = ptrvrrp;
+
+ pool = (sockpool *)pool->next;
+ }
+ pool = ptr;
+}
+
+/*
+ * We create & allocate a socket pool here. The soft design
+ * can be sum up by the following sketch :
+ *
+ * fd1 fd2 fd3 fd4 fdi fdi+1
+ * -----\__/--------\__/---........---\__/---
+ * | ETH0 | | ETH1 | | ETHn |
+ * +------+ +------+ +------+
+ *
+ * Here we have n physical NIC. Each NIC own a maximum of 2 fds.
+ * (one for VRRP the other for IPSEC_AH). All our VRRP instances
+ * are multiplexed through this fds. So our design can handle 2*n
+ * multiplexing points.
+ */
+int vrrp_dispatcher_init_thread(struct thread *thread)
+{
+ vrrp_instance *instance = THREAD_ARG(thread);
+ sockpool *pool;
+
+ /* init */
+ pool = NULL;
+
+ /* create the VRRP socket pool list */
+ pool = vrrp_create_sockpool(instance, pool);
+
+ /* open the VRRP socket pool */
+ vrrp_open_sockpool(pool);
+
+ /* set VRRP instance fds to sockpool */
+ vrrp_set_fds(instance, pool);
+
+ /* register read dispatcher worker thread */
+ vrrp_register_workers(thread->master, instance, pool);
+
+ /* cleanup the temp socket pool */
+ clear_sockpool(pool);
+
+ return 0;
+}
+
+static vrrp_instance *vrrp_search_instance_isync(char *isync, vrrp_instance *instance)
+{
+ while (instance) {
+ if (strcmp(instance->iname, isync) == 0) /* FIXME: handle buffer overflow */
+ return instance;
+ instance = (vrrp_instance *)instance->next;
+ }
+
+ return NULL;
+}
+
+static vrrp_instance *vrrp_search_instance(const int vrid, vrrp_instance *instance)
+{
+ while (instance) {
+ if (instance->vsrv->vrid == vrid)
+ return instance;
+ instance = (vrrp_instance *)instance->next;
+ }
+
+ return NULL;
+}
+
+static void vrrp_handle_backup(vrrp_instance *instance,
+ char *vrrp_buffer,
+ int len)
+{
+ vrrp_state_backup(instance, vrrp_buffer, len);
+}
+
+static void vrrp_handle_become_master(vrrp_instance *instance,
+ char *vrrp_buffer,
+ int len)
+{
+ vrrp_rt *vsrv = instance->vsrv;
+ struct iphdr *iph = (struct iphdr *)vrrp_buffer;
+ ipsec_ah *ah;
+
+ /*
+ * If we are in IPSEC AH mode, we must be sync
+ * with the remote IPSEC AH VRRP instance counter.
+ */
+ if (iph->protocol == IPPROTO_IPSEC_AH) {
+ ah = (ipsec_ah *)(vrrp_buffer + sizeof(struct iphdr));
+ vsrv->ipsecah_counter->seq_number = ah->seq_number + 1;
+ vsrv->ipsecah_counter->cycle = 0;
+ }
+}
+
+static void vrrp_handle_leave_master(vrrp_instance *instance,
+ char *vrrp_buffer,
+ int len)
+{
+ if (vrrp_state_master_rx(instance, vrrp_buffer, len)) {
+ syslog(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert"
+ , instance->iname);
+ vrrp_state_leave_master(instance);
+ }
+}
+
+static int vrrp_handle_state(vrrp_instance *instance,
+ char *vrrp_buffer,
+ int len)
+{
+ int previous_state;
+
+ previous_state = instance->vsrv->state;
+
+ switch (instance->vsrv->state) {
+ case VRRP_STATE_BACK:
+ vrrp_handle_backup(instance, vrrp_buffer, len);
+ break;
+ case VRRP_STATE_GOTO_MASTER:
+ vrrp_handle_become_master(instance, vrrp_buffer, len);
+ break;
+ case VRRP_STATE_MAST:
+ vrrp_handle_leave_master(instance, vrrp_buffer, len);
+ break;
+ }
+
+ return previous_state;
+}
+
+static void vrrp_handle_goto_master(vrrp_instance *instance)
+{
+ vrrp_rt *vsrv = instance->vsrv;
+
+ /* If becoming MASTER in IPSEC AH AUTH, we reset the anti-replay */
+ if (vsrv->ipsecah_counter->cycle) {
+ vsrv->ipsecah_counter->cycle = 0;
+ vsrv->ipsecah_counter->seq_number = 0;
+ }
+
+ vsrv->state = VRRP_STATE_BACK;
+ vsrv->wantstate = VRRP_STATE_MAST;
+
+ /* handle master state transition */
+ vrrp_state_goto_master(instance);
+}
+
+static void vrrp_handle_master(vrrp_instance *instance)
+{
+ vrrp_rt *vsrv = instance->vsrv;
+
+ if (vsrv->wantstate == VRRP_STATE_BACK ||
+ vsrv->ipsecah_counter->cycle) {
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+
+ /* handle backup state transition */
+ vsrv->state = VRRP_STATE_BACK;
+ vrrp_state_leave_master(instance);
+
+ syslog(LOG_INFO, "VRRP_Instance(%s) Becoming BACKUP"
+ , instance->iname);
+ } else {
+ /* send the VRRP advert */
+ vrrp_state_master_tx(instance, 0);
+ }
+}
+
+static int vrrp_handle_state_timeout(vrrp_instance *instance)
+{
+ int previous_state;
+
+ previous_state = instance->vsrv->state;
+
+ switch (instance->vsrv->state) {
+ case VRRP_STATE_BACK:
+ vrrp_handle_goto_master(instance);
+ break;
+ case VRRP_STATE_GOTO_MASTER:
+ vrrp_handle_goto_master(instance);
+ break;
+ case VRRP_STATE_MAST:
+ vrrp_handle_master(instance);
+ break;
+ case VRRP_STATE_FAULT:
+ vrrp_handle_master(instance);
+ break;
+ }
+
+ return previous_state;
+}
+
+/* Our read packet dispatcher */
+int vrrp_read_dispatcher_thread(struct thread *thread)
+{
+ vrrp_instance *instance = THREAD_ARG(thread);
+ vrrp_instance *ptr = instance;
+ vrrp_instance *vrrp_isync;
+ vrrp_instance *vrrp_instance;
+ long vrrp_timer = 0;
+ char *vrrp_buffer;
+ struct iphdr *iph;
+ vrrp_pkt *hd;
+ int len = 0;
+ int vrid = 0;
+ int previous_state = 0;
+
+ if (thread->type == THREAD_READ_TIMEOUT) {
+
+ /* Searching for matching instance */
+ vrid = vrrp_timer_vrid_timeout(thread->u.fd, instance);
+ vrrp_instance = vrrp_search_instance(vrid, instance);
+ instance = ptr;
+
+// syslog(LOG_DEBUG, "Dispatcher timeout on (fd,vrid) : (%d,%d)", thread->u.fd, vrid);
+
+ previous_state = vrrp_handle_state_timeout(vrrp_instance);
+
+ /* handle master instance synchronization */
+ if (previous_state == VRRP_STATE_BACK &&
+ strlen(vrrp_instance->isync) > 0) {
+ vrrp_isync = vrrp_search_instance_isync(vrrp_instance->isync, instance);
+ instance = ptr;
+
+ if (vrrp_isync->vsrv->state == VRRP_STATE_BACK) {
+ syslog(LOG_INFO, "VRRP_Instance(%s) must be sync with %s"
+ , vrrp_instance->iname
+ , vrrp_isync->iname);
+
+ /* Send the higher priority advert */
+ syslog(LOG_INFO, "VRRP_Instance(%s) sending OWNER advert"
+ , vrrp_isync->iname);
+ vrrp_state_master_tx(vrrp_isync, VRRP_PRIO_OWNER);
+ } else {
+ /* Otherwise, we simply update remotes arp tables */
+ syslog(LOG_INFO, "VRRP_Instance(%s) gratuitous arp on %s"
+ , vrrp_isync->iname
+ , vrrp_isync->vsrv->vif->ifname);
+ vrrp_isync->vsrv->state = VRRP_STATE_MAST;
+ vrrp_send_gratuitous_arp(vrrp_isync);
+ }
+ }
+
+ /*
+ * We are sure the instance exist. So we can
+ * compute new sands timer safely.
+ */
+ vrrp_init_instance_sands(vrrp_instance);
+
+ } else {
+
+ /* allocate & clean the read buffer */
+ vrrp_buffer = (char *)malloc(VRRP_PACKET_TEMP_LEN);
+ memset(vrrp_buffer, 0, VRRP_PACKET_TEMP_LEN);
+
+ /* read & affect received buffer */
+ len = read(thread->u.fd, vrrp_buffer, VRRP_PACKET_TEMP_LEN);
+ iph = (struct iphdr *)vrrp_buffer;
+
+ switch (iph->protocol) {
+ case IPPROTO_IPSEC_AH:
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len());
+ break;
+ case IPPROTO_VRRP:
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
+ break;
+ }
+
+ /* Searching for matching instance */
+ vrrp_instance = vrrp_search_instance(hd->vrid, instance);
+ instance = ptr;
+
+ if (vrrp_instance) {
+
+//syslog(LOG_DEBUG, "VRRP packet received: on fd:%d", thread->u.fd);
+
+ previous_state = vrrp_handle_state(vrrp_instance, vrrp_buffer, len);
+
+ /* handle backup instance synchronization */
+ if (previous_state == VRRP_STATE_MAST &&
+ vrrp_instance->vsrv->state == VRRP_STATE_BACK &&
+ strlen(vrrp_instance->isync) > 0) {
+ vrrp_isync = vrrp_search_instance_isync(vrrp_instance->isync, instance);
+ instance = ptr;
+
+ /* synchronized instance probably failed */
+ if (vrrp_isync->vsrv->state == VRRP_STATE_MAST &&
+ vrrp_isync->vsrv->init_state == VRRP_STATE_MAST) {
+ syslog(LOG_INFO, "VRRP_Instance(%s) transition to FAULT state"
+ , vrrp_instance->iname);
+ vrrp_isync->vsrv->state = VRRP_STATE_FAULT;
+ } else if (vrrp_isync->vsrv->state == VRRP_STATE_MAST) {
+ syslog(LOG_INFO, "VRRP_Instance(%s) must be sync with %s"
+ , vrrp_instance->iname
+ , vrrp_isync->iname);
+
+ /* Transition to BACKUP state */
+ vrrp_isync->vsrv->wantstate = VRRP_STATE_BACK;
+ }
+ }
+
+ /*
+ * Refresh sands only if found matching instance.
+ * Otherwize the packet is simply ignored...
+ *
+ * FIXME: Add a dropping packet framework to not
+ * degrade the instance timer during dropping.
+ */
+ vrrp_init_instance_sands(vrrp_instance);
+ }
+
+ /* cleanup the room */
+ free(vrrp_buffer);
+
+ }
+
+ /* register next dispatcher thread */
+ vrrp_timer = vrrp_timer_fd(thread->u.fd, instance);
+ thread_add_read(thread->master, vrrp_read_dispatcher_thread,
+ instance, thread->u.fd, vrrp_timer);
+
+//syslog(LOG_DEBUG, "VRRP new timer: %lu on fd:%d", vrrp_timer, thread->u.fd);
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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_scheduler.c include file.
+ *
+ * Version: $Id: vrrp_scheduler.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ *
+ * 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.
+ */
+
+#ifndef _VRRP_SCHEDULER_H
+#define _VRRP_SCHEDULER_H
+
+/* system include */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdint.h>
+
+/* local include */
+#include "scheduler.h"
+
+/*
+ * Our instance dispatcher use a socket pool.
+ * That way we handle VRRP protocole type per
+ * physical interface.
+ */
+typedef struct {
+ int ifindex;
+ int proto;
+ int fd;
+
+ struct sockpool *next;
+} sockpool;
+
+/* extern prototypes */
+extern int open_vrrp_socket(const int proto, const int index);
+extern int ifname_to_idx(const char *ifname);
+extern void vrrp_send_gratuitous_arp(vrrp_instance *vrrp_instance);
+extern int vrrp_read_dispatcher_thread(struct thread *thread);
+extern int vrrp_state_master_rx(vrrp_instance *instance, char *buf, int buflen);
+extern void vrrp_state_master_tx(vrrp_instance *instance, const int prio);
+extern void vrrp_state_backup(vrrp_instance *instance, char *buf, int buflen);
+extern void vrrp_state_goto_master(vrrp_instance *vrrp_instance);
+extern void vrrp_state_leave_master(vrrp_instance *instance);
+
+#endif