* [2/2] CARP implementation. HA master's failover.
[not found] <1089898339.6114.860.camel@uganda>
@ 2004-07-15 13:37 ` Evgeniy Polyakov
0 siblings, 0 replies; only message in thread
From: Evgeniy Polyakov @ 2004-07-15 13:37 UTC (permalink / raw)
To: netdev; +Cc: netfilter-failover
[-- Attachment #1.1: Type: text/plain, Size: 2093 bytes --]
On Thu, 2004-07-15 at 17:32, Evgeniy Polyakov wrote:
> Hello, network developers.
>
> I'm glad to introduce CARP failover mechanism implementation.
> It is based on OpenBSD's CARP protocol but is not compatible with it
> since OpenBSD's implementation does not contain protection against
> repeated message sending.
>
> The main goal of the project is to implement CARP + firewall sync, but
> second part already implemented by Harald Welte <laforge@gnumonks.org> and
> KOVACS Krisztian <hidden@sch.bme.hu> in ct_sync.
>
> By design each node has it's own advertisement base and skew, node with
> the least timeval constructed from them became a master.
> It begins to advertise it's base and skew until shutdown or other node
> lower it's base+skew pair.
> CARP uses currently only IPv4 multicast, but can be easily changed to
> use IPv6.
> Each CARP packet contains unique 64bit counter with it's SHA1 hmac
> digest with 20byte secret key. By design this counter is incremented in
> both master and backup before sending and while receiving accordingly.
> If master and backup counters do not coincide with each other while
> receiving backup node drops this packet and thus preventing repeated
> sending attack.
> When after predefined interval master didn't send any packet or it's
> base+skew is bigger than that in the remote node those node becomes a
> master and begins to advertise.
>
> CARP has 2 work queues for "became_master" and "became_backup" events.
> Such events may be easily registered in runtime by external modules.
> One of such event handlers may send netlink message to ct_sync and/or
> userspace daemon which will flush iptables rules, up/down interfaces and
> so on...
>
> Please review and comment.
>
> Code against 2.6 attached
> in next 2 e-mails since netfilter-failover@lists.netfilter.org doesn't accept
> e-mail greater than 40kb.
>
> Code also is available at
> http://www.2ka.mipt.ru/~johnpol/carp_latest.tar.gz
--
Evgeniy Polaykov ( s0mbre )
Crash is better than data corruption. -- Art Grabowski
[-- Attachment #1.2: carpctl.c --]
[-- Type: text/x-csrc, Size: 3849 bytes --]
/*
* carpctl.c
*
* 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
* All rights reserved.
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <linux/if.h>
#include "carp_ioctl.h"
#define CARP_KEY_LEN 20
#define CARP_HMAC_PAD_LEN 64
#define IPPROTO_CARP 112
static void usage(const char *pr)
{
fprintf(stderr, "Usage: %s: [-h] [-i iph] [-b advbase] [-s advskew] [-d device] [-v vhid] [-k key] [-p pad] [-S state] "
"[-m md_timeout] [-a adv_timout].\n",
pr);
}
static void carp_dump_params(struct carp_ioctl_params p)
{
printf("Attached to device %s.\n", p.devname);
printf("ADV: base=%d, skew=%d.\n", p.carp_advbase, p.carp_advskew);
printf("VHID=%d, STATE=%d.\n", p.carp_vhid, p.state);
}
int main(int argc, char *argv[])
{
int ch, err, s, need_change;
struct ifreq ifr;
char devname[IFNAMSIZ] = "carp0";
struct carp_ioctl_params p;
memset(&p, 0, sizeof(p));
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
ifr.ifr_ifru.ifru_data = (void *)&p;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
{
fprintf(stderr, "Failed to create CARP control socket: [%d] %s.\n",
errno, strerror(errno));
return -1;
}
err = ioctl(s, SIOC_GETCARPPARAMS, &ifr);
if (err == -1)
{
fprintf(stderr, "Failed to call ioctl: [%d] %s.\n",
errno, strerror(errno));
close(s);
return -1;
}
carp_dump_params(p);
need_change = 0;
while((ch = getopt(argc, argv, "hi:b:s:d:v:k:p:S:m:a:")) != -1)
{
need_change = 1;
switch (ch)
{
case 'm':
p.md_timeout = atoi(optarg);
break;
case 'a':
p.adv_timeout = atoi(optarg);
break;
case 'b':
p.carp_advbase = atoi(optarg);
break;
case 's':
p.carp_advskew = atoi(optarg);
break;
case 'd':
memcpy(p.devname, optarg, sizeof(p.devname));
p.devname[sizeof(p.devname) - 1] = '\0';
break;
case 'v':
p.carp_vhid = atoi(optarg);
break;
case 'k':
if (strlen(optarg) != sizeof(p.carp_key))
{
fprintf(stderr, "Wrong key length. Must be %d.\n", sizeof(p.carp_key));
return -1;
}
memcpy(p.carp_key, optarg, sizeof(p.carp_key));
break;
case 'p':
if (strlen(optarg) != sizeof(p.carp_pad))
{
fprintf(stderr, "Wrong pad length. Must be %d.\n", sizeof(p.carp_pad));
return -1;
}
memcpy(p.carp_pad, optarg, sizeof(p.carp_pad));
break;
case 'S':
p.state = atoi(optarg);
break;
case 'h':
default:
need_change = 0;
usage(argv[0]);
return -1;
}
}
if (!need_change)
{
usage(argv[0]);
return -1;
}
ifr.ifr_ifru.ifru_data = (void *)&p;
err = ioctl(s, SIOC_SETCARPPARAMS, &ifr);
if (err == -1)
{
fprintf(stderr, "Failed to call ioctl: [%d] %s.\n",
errno, strerror(errno));
close(s);
return -1;
}
close(s);
return 0;
}
[-- Attachment #1.3: carp_queue.c --]
[-- Type: text/x-csrc, Size: 4182 bytes --]
/*
* carp_queue.c
*
* 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
* All rights reserved.
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/workqueue.h>
#include <asm/spinlock.h>
#include "carp.h"
#include "carp_log.h"
#include "carp_queue.h"
static spinlock_t carp_queue_lock = SPIN_LOCK_UNLOCKED;
static struct workqueue_struct *carp_queue[2];
static struct list_head carp_works[2];
static int carp_work_counter;
static void carp_queue_wrapper(void *data)
{
struct carp_master_task *t = (struct carp_master_task *)data;
atomic_inc(&t->task->refcnt);
t->task->callback(t->task->data);
atomic_dec(&t->task->refcnt);
}
struct carp_master_task *carp_alloc_task(struct __carp_master_task *t)
{
struct carp_master_task *newt;
newt = kmalloc(sizeof(struct carp_master_task), GFP_KERNEL);
if (!newt)
{
log("Failed to create new CARP master task.\n");
return NULL;
}
memset(newt, 0, sizeof(struct carp_master_task));
atomic_set(&t->refcnt, 1);
newt->task = t;
newt->task->id = carp_work_counter++;
INIT_WORK(&newt->work, &carp_queue_wrapper, newt);
return newt;
}
static void carp_free_task(struct carp_master_task *t)
{
cancel_delayed_work(&t->work);
while(atomic_read(&t->task->refcnt))
schedule_timeout(10);
kfree(t);
}
int carp_add_task(struct __carp_master_task *mt, int num)
{
struct carp_master_task *newt;
if (num != MASTER_QUEUE && num != BACKUP_QUEUE)
return -EINVAL;
newt = carp_alloc_task(mt);
if (!newt)
return -ENOMEM;
spin_lock(&carp_queue_lock);
list_add_tail(&newt->entry, &carp_works[num]);
spin_unlock(&carp_queue_lock);
return 0;
}
void carp_del_task(struct __carp_master_task *mt, int num)
{
struct list_head *ent, *n;
struct carp_master_task *t = NULL;
int found = 0;
if (num != MASTER_QUEUE && num != BACKUP_QUEUE)
return;
spin_lock(&carp_queue_lock);
list_for_each_safe(ent, n, &carp_works[num])
{
t = list_entry(ent, struct carp_master_task, entry);
if (t->task->id == mt->id) {
list_del(&t->entry);
found = 1;
break;
}
}
spin_unlock(&carp_queue_lock);
if (found)
{
atomic_dec(&t->task->refcnt);
carp_free_task(t);
}
}
void carp_call_queue(int num)
{
struct list_head *ent, *n;
struct carp_master_task *t;
if (num != MASTER_QUEUE && num != BACKUP_QUEUE)
return;
spin_lock(&carp_queue_lock);
list_for_each_safe(ent, n, &carp_works[num])
{
t = list_entry(ent, struct carp_master_task, entry);
queue_work(carp_queue[num], &t->work);
}
spin_unlock(&carp_queue_lock);
}
int carp_init_queues(void)
{
int i;
for (i=0; i<2; ++i)
INIT_LIST_HEAD(&carp_works[i]);
carp_queue[MASTER_QUEUE] = create_workqueue("CARP_m");
if (!carp_queue[MASTER_QUEUE])
{
log("Failed to create master CARP queue.\n");
return -1;
}
carp_queue[BACKUP_QUEUE] = create_workqueue("CARP_b");
if (!carp_queue[BACKUP_QUEUE])
{
destroy_workqueue(carp_queue[MASTER_QUEUE]);
log("Failed to create backup CARP queue.\n");
return -1;
}
return 0;
}
void carp_flush_queue(int num)
{
if (num != MASTER_QUEUE && num != BACKUP_QUEUE)
return;
flush_workqueue(carp_queue[num]);
}
void carp_fini_queues(void)
{
carp_flush_queue(MASTER_QUEUE);
destroy_workqueue(carp_queue[MASTER_QUEUE]);
carp_flush_queue(BACKUP_QUEUE);
destroy_workqueue(carp_queue[BACKUP_QUEUE]);
}
[-- Attachment #1.4: carp_queue.h --]
[-- Type: text/x-chdr, Size: 1540 bytes --]
/*
* carp_queue.h
*
* 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
* All rights reserved.
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __CARP_QUEUE_H
#define __CARP_QUEUE_H
#include <linux/workqueue.h>
#include <asm/atomic.h>
enum carp_queue_number {MASTER_QUEUE = 0, BACKUP_QUEUE};
struct __carp_master_task
{
atomic_t refcnt;
u32 id;
void (* callback)(void *);
void *data;
void *priv;
};
struct carp_master_task
{
struct list_head entry;
struct __carp_master_task *task;
struct work_struct work;
};
int carp_init_queues(void);
void carp_flush_queue(int);
void carp_fini_queues(void);
void carp_call_queue(int);
int carp_add_task(struct __carp_master_task *, int);
void carp_del_task(struct __carp_master_task *, int);
#endif /* __CARP_QUEUE_H */
[-- Attachment #1.5: carp_log.c --]
[-- Type: text/x-csrc, Size: 2967 bytes --]
/*
* carp_log.c
*
* 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
* All rights reserved.
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/in.h>
#include <linux/random.h>
#include <linux/crypto.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/arp.h>
#include <asm/scatterlist.h>
#include <asm/delay.h>
#include "carp.h"
#include "carp_log.h"
void dump_addr_info(struct carp_priv *cp)
{
int i;
printk(KERN_INFO "CARP addr: hw=");
for (i=0; i<ETH_ALEN; ++i)
printk("%02x%c", (unsigned char)cp->odev->dev_addr[i], (i==ETH_ALEN-1)?' ':':');
printk(", sw=");
for (i=0; i<4; ++i)
printk("%d%c", (ntohl(cp->iph.saddr) >> (3-i)*8)&0xff, (i==3)?' ':'.');
printk(", dst=");
for (i=0; i<4; ++i)
printk("%d%c", (ntohl(cp->iph.daddr) >> (3-i)*8)&0xff, (i==3)?' ':'.');
printk("\n");
}
void dump_hmac_params(struct carp_priv *cp)
{
int i;
unsigned int keylen;
struct scatterlist sg;
u8 carp_md[CARP_SIG_LEN];
keylen = sizeof(cp->carp_key);
sg.page = virt_to_page(&cp->carp_adv_counter);
sg.offset = (unsigned long)(&cp->carp_adv_counter) % PAGE_SIZE;
sg.length = sizeof(cp->carp_adv_counter);
crypto_hmac(cp->tfm, cp->carp_key, &keylen, &sg, 1, carp_md);
printk(KERN_INFO "key: ");
for (i=0; i<CARP_KEY_LEN; ++i)
printk("%02x ", cp->carp_key[i]);
printk("\n");
printk("counter: %llx ", cp->carp_adv_counter);
printk("hmac: ");
for (i=0; i<CARP_SIG_LEN; ++i)
printk("%02x ", carp_md[i]);
printk("\n");
}
void dump_carp_header(struct carp_header *ch)
{
u64 counter;
int i;
counter = ntohl(ch->carp_counter[0]);
counter = counter<<32;
counter += ntohl(ch->carp_counter[1]);
log("type=%u, version=%u, vhid=%u, skew=%u, base=%u, counter=%llu, md={",
ch->carp_type,
ch->carp_version,
ch->carp_vhid,
ch->carp_advskew,
ch->carp_advbase,
counter);
for (i=0; i<sizeof(ch->carp_md); ++i)
{
printk("%02x ", ch->carp_md[i]);
}
printk("}\n");
}
[-- Attachment #1.6: carp_log.h --]
[-- Type: text/x-chdr, Size: 1131 bytes --]
/*
* carp_log.h
*
* 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
* All rights reserved.
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __CARP_LOG_H
#define __CARP_LOG_H
#include "carp.h"
#define log(f, a...) printk(KERN_INFO f, ##a)
void dump_addr_info(struct carp_priv *);
void dump_hmac_params(struct carp_priv *);
void dump_carp_header(struct carp_header *);
#endif /* __CARP_LOG_H */
[-- Attachment #1.7: Makefile --]
[-- Type: text/x-makefile, Size: 382 bytes --]
obj-m := ip_carp.o
ip_carp-objs := carp.o carp_log.o carp_queue.o
KDIR := /usr/local/src/linux-2.6
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
gcc -W -Wall carpctl.c -o carpctl
copy:
scp ip_carp.ko carpctl mtest:carp/
scp ip_carp.ko carpctl pcix:aWork/carp/
clean:
rm -f *.o *.ko *.mod.* .*.cmd *~ carpctl
rm -rf .tmp_versions
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2004-07-15 13:37 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1089898339.6114.860.camel@uganda>
2004-07-15 13:37 ` [2/2] CARP implementation. HA master's failover Evgeniy Polyakov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).