NetBSD/tests/net/carp/t_basic.c
pooka 7c8855f1e2 Put some sleeps between forking the hosts. Otherwise a race may
be triggered which appears to cause one host to go berzerk with
sending carp advertisements and ignore ping requests.

I'll get to the bottom of this eventually, but this is a stopgap
to prevent the test from failing, hopefully -- the race doesn't
appear to trigger for me even with 0.1s on a loaded machine, so
0.5s should be better than fine.

(hi jmmv ;)
2010-08-11 13:10:03 +00:00

221 lines
5.0 KiB
C

/* $NetBSD: t_basic.c,v 1.2 2010/08/11 13:10:03 pooka Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: t_basic.c,v 1.2 2010/08/11 13:10:03 pooka Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip_carp.h>
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
#include <atf-c.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../config/netconfig.c"
#include "../../h_macros.h"
static bool oknow = false;
static void
sighnd(int sig)
{
ATF_REQUIRE_EQ(sig, SIGCHLD);
if (oknow)
return;
atf_tc_fail("child died unexpectedly");
}
ATF_TC(handover);
ATF_TC_HEAD(handover, tc)
{
atf_tc_set_md_var(tc, "descr", "check that carp handover works if "
"the master dies");
atf_tc_set_md_var(tc, "use.fs", "true");
}
#define THEBUS "buuuuuuus,etherbus"
static void
child(bool master)
{
char ifname[IFNAMSIZ];
struct carpreq cr;
struct ifreq ifr;
const char *carpif;
int s;
/* helps reading carp debug output */
if (master)
carpif = "carp0";
else
carpif = "carp1";
/*
* Should use sysctl, bug debug is dabug.
*/
{
//extern int rumpns_carp_opts[]; /* XXX */
//rumpns_carp_opts[CARPCTL_LOG] = 1;
}
rump_init();
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, carpif, sizeof(ifr.ifr_name));
RL(s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0));
RL(rump_sys_ioctl(s, SIOCIFCREATE, &ifr));
netcfg_rump_makeshmif(THEBUS, ifname);
if (master)
netcfg_rump_if(ifname, "10.1.1.1", "255.255.255.0");
else
netcfg_rump_if(ifname, "10.1.1.2", "255.255.255.0");
/* configure the carp interface */
ifr.ifr_data = &cr;
RL(rump_sys_ioctl(s, SIOCGVH, &ifr));
strlcpy(cr.carpr_carpdev, ifname, sizeof(cr.carpr_carpdev));
cr.carpr_vhid = 175;
if (master)
cr.carpr_advskew = 0;
else
cr.carpr_advskew = 200;
cr.carpr_advbase = 1;
strcpy(cr.carpr_key, "s3cret");
RL(rump_sys_ioctl(s, SIOCSVH, &ifr));
netcfg_rump_if(carpif, "10.1.1.100", "255.255.255.0");
/* tassa pause()en enka muuta voi */
pause();
}
ATF_TC_BODY(handover, tc)
{
char ifname[IFNAMSIZ];
pid_t mpid, cpid;
int i, status;
signal(SIGCHLD, sighnd);
/* fork master */
switch (mpid = fork()) {
case -1:
atf_tc_fail_errno("fork failed");
/*NOTREACHED*/
case 0:
child(true);
/*NOTREACHED*/
default:
break;
}
usleep(500000);
/* fork backup */
switch (cpid = fork()) {
case -1:
kill(mpid, SIGKILL);
atf_tc_fail_errno("fork failed");
/*NOTREACHED*/
case 0:
child(false);
/*NOTREACHED*/
default:
break;
}
usleep(500000);
rump_init();
netcfg_rump_makeshmif(THEBUS, ifname);
netcfg_rump_if(ifname, "10.1.1.240", "255.255.255.0");
/* check that the primary addresses are up */
ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.1", 1000), true);
ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.2", 1000), true);
/* give carp a while to croak */
sleep(4);
/* check that the shared IP works */
ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.100", 500), true);
/* KILLING SPREE */
oknow = true;
kill(mpid, SIGKILL);
wait(&status);
usleep(10000); /* just in case */
oknow = false;
/* check that primary is now dead */
ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.1", 100), false);
/* do it in installments. carp will cluck meanwhile */
for (i = 0; i < 5; i++) {
if (netcfg_rump_pingtest("10.1.1.100", 1000) == true)
break;
}
if (i == 5)
atf_tc_fail("failed to failover");
/* to kill the child */
oknow = true;
kill(cpid, SIGKILL);
/* clean & done */
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, handover);
return atf_no_error();
}