mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
Create new AF_UNIX based network simulator
This commit is contained in:
parent
33bbd7b52e
commit
7420f46653
1
.gitignore
vendored
1
.gitignore
vendored
@ -23,6 +23,7 @@ serval.c
|
||||
/tfw_createfile
|
||||
/fakeradio
|
||||
/config_test
|
||||
/simulator
|
||||
*.so
|
||||
test.*.log
|
||||
testlog
|
||||
|
@ -29,6 +29,7 @@ SERVALD_OBJS= $(SERVALD_SRCS:.c=.o)
|
||||
SERVAL_DAEMON_OBJS= $(SERVAL_DAEMON_SOURCES:.c=.o)
|
||||
MONITOR_CLIENT_OBJS= $(MONITOR_CLIENT_SRCS:.c=.o)
|
||||
MDP_CLIENT_OBJS= $(MDP_CLIENT_SRCS:.c=.o)
|
||||
SIMULATOR_OBJS= $(SIMULATOR_SOURCES:.c=.o)
|
||||
|
||||
LDFLAGS=@LDFLAGS@ @LIBS@ @PTHREAD_LIBS@
|
||||
|
||||
@ -58,7 +59,7 @@ DEFS= @DEFS@
|
||||
|
||||
all: servald libmonitorclient.so libmonitorclient.a test
|
||||
|
||||
test: tfw_createfile directory_service fakeradio config_test
|
||||
test: tfw_createfile directory_service fakeradio config_test simulator
|
||||
|
||||
sqlite-amalgamation-3070900/sqlite3.o: sqlite-amalgamation-3070900/sqlite3.c
|
||||
@echo CC $<
|
||||
@ -83,6 +84,7 @@ configure: $(wildcard configure.in)
|
||||
$(SERVAL_DAEMON_OBJS): $(HDRS)
|
||||
$(MONITOR_CLIENT_OBJS): $(HDRS)
|
||||
$(MDP_CLIENT_OBJS): $(HDRS)
|
||||
$(SIMULATOR_OBJS): $(HDRS)
|
||||
|
||||
servald: $(SERVALD_OBJS) version.o
|
||||
@echo LINK $@
|
||||
@ -100,6 +102,10 @@ fakeradio: fakeradio.o
|
||||
@echo LINK $@
|
||||
@$(CC) $(CFLAGS) -Wall -o $@ fakeradio.o
|
||||
|
||||
simulator: $(SIMULATOR_OBJS)
|
||||
@echo LINK $@
|
||||
@$(CC) $(CFLAGS) -Wall -o $@ $(SIMULATOR_OBJS) $(LDFLAGS)
|
||||
|
||||
config_test: config_test.o conf_om.o conf_schema.o conf_parse.o str.o strbuf.o strbuf_helpers.o mem.o dataformats.o net.o log_util.o
|
||||
@echo LINK $@
|
||||
@$(CC) $(CFLAGS) -Wall -o $@ config_test.o conf_om.o conf_schema.o conf_parse.o str.o strbuf.o strbuf_helpers.o mem.o dataformats.o net.o log_util.o $(LDFLAGS)
|
||||
|
18
main.c
18
main.c
@ -68,21 +68,3 @@ static void crash_handler(int signal)
|
||||
exit(-signal);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <execinfo.h>
|
||||
#define MAX_DEPTH 64
|
||||
int printBackTrace()
|
||||
{
|
||||
int i,depth=0;
|
||||
void *functions[MAX_DEPTH];
|
||||
char **function_names;
|
||||
|
||||
depth = backtrace (functions, MAX_DEPTH);
|
||||
function_names = backtrace_symbols (functions, depth);
|
||||
|
||||
for(i=0;i<depth;i++)
|
||||
fprintf(stderr,"%s\n", function_names[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -789,39 +789,44 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
}
|
||||
}
|
||||
|
||||
static int send_local_broadcast(int fd, const uint8_t *bytes, size_t len, struct socket_address *address)
|
||||
static int send_local_packet(int fd, const uint8_t *bytes, size_t len, const char *folder, const char *file)
|
||||
{
|
||||
struct socket_address addr;
|
||||
|
||||
strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
|
||||
strbuf_path_join(d, folder, file, NULL);
|
||||
if (strbuf_overrun(d))
|
||||
return WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
|
||||
|
||||
struct stat st;
|
||||
if (lstat(addr.local.sun_path, &st))
|
||||
return 1;
|
||||
if (!S_ISSOCK(st.st_mode))
|
||||
return 1;
|
||||
|
||||
addr.local.sun_family = AF_UNIX;
|
||||
addr.addrlen = sizeof(addr.local.sun_family) + strlen(addr.local.sun_path)+1;
|
||||
|
||||
ssize_t sent = sendto(fd, bytes, len, 0,
|
||||
&addr.addr, addr.addrlen);
|
||||
if (sent == -1)
|
||||
return WHYF_perror("sendto(%d, %zu, %s)", fd, len, alloca_socket_address(&addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_local_broadcast(int fd, const uint8_t *bytes, size_t len, const char *folder)
|
||||
{
|
||||
if (send_local_packet(fd, bytes, len, folder, "broadcast")==0)
|
||||
return 0;
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *dp;
|
||||
if ((dir = opendir(address->local.sun_path)) == NULL) {
|
||||
WARNF_perror("opendir(%s)", alloca_str_toprint(address->local.sun_path));
|
||||
if ((dir = opendir(folder)) == NULL) {
|
||||
WARNF_perror("opendir(%s)", alloca_str_toprint(folder));
|
||||
return -1;
|
||||
}
|
||||
while ((dp = readdir(dir)) != NULL) {
|
||||
struct socket_address addr;
|
||||
|
||||
strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
|
||||
strbuf_path_join(d, address->local.sun_path, dp->d_name, NULL);
|
||||
if (strbuf_overrun(d)){
|
||||
WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
|
||||
continue;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (lstat(addr.local.sun_path, &st)) {
|
||||
WARNF_perror("stat(%s)", alloca_str_toprint(addr.local.sun_path));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISSOCK(st.st_mode)){
|
||||
addr.local.sun_family = AF_UNIX;
|
||||
addr.addrlen = sizeof(addr.local.sun_family) + strlen(addr.local.sun_path)+1;
|
||||
|
||||
ssize_t sent = sendto(fd, bytes, len, 0,
|
||||
&addr.addr, addr.addrlen);
|
||||
if (sent == -1)
|
||||
WHYF_perror("sendto(%d, %zu, %s)", fd, len, alloca_socket_address(&addr));
|
||||
}
|
||||
send_local_packet(fd, bytes, len, folder, dp->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
@ -915,7 +920,7 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
|
||||
&& !destination->unicast){
|
||||
// find all sockets in this folder and send to them
|
||||
send_local_broadcast(interface->alarm.poll.fd,
|
||||
bytes, (size_t)len, &destination->address);
|
||||
bytes, (size_t)len, destination->address.local.sun_path);
|
||||
}else{
|
||||
ssize_t sent = sendto(interface->alarm.poll.fd,
|
||||
bytes, (size_t)len, 0,
|
||||
|
689
simulator.c
Normal file
689
simulator.c
Normal file
@ -0,0 +1,689 @@
|
||||
/*
|
||||
Copyright (C) 2014 Serval Project Inc.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
Network simulator
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mem.h"
|
||||
#include "socket.h"
|
||||
#include "fdqueue.h"
|
||||
#include "str.h"
|
||||
#include "strbuf.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "conf.h"
|
||||
#include "net.h"
|
||||
#include "console.h"
|
||||
#include "limit.h"
|
||||
|
||||
#define MTU 1600
|
||||
struct peer;
|
||||
|
||||
/*
|
||||
* we want to support simulating common wired, wireless & UHF network topologies
|
||||
* eg layer 2 adhoc mesh, switched ethernet, AP's, openWRT's
|
||||
* With topology changes over time
|
||||
*
|
||||
* Some kind of DSL will probably be required
|
||||
*
|
||||
* Node{
|
||||
* name "foo"
|
||||
* type servald / switch ...
|
||||
* Adapter{
|
||||
* socket "path"
|
||||
* type adhoc / ap / client / ethernet / uhf
|
||||
* queue_length 10
|
||||
* drop broadcast %
|
||||
* drop unicast %
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
struct packet {
|
||||
struct packet *_next;
|
||||
time_ms_t recv_time;
|
||||
struct peer *destination;
|
||||
size_t len;
|
||||
uint8_t tdma_order;
|
||||
unsigned char buff[MTU];
|
||||
};
|
||||
|
||||
struct peer {
|
||||
struct sched_ent alarm;
|
||||
struct peer *_next;
|
||||
struct network *network;
|
||||
struct socket_address addr;
|
||||
int packet_count;
|
||||
int max_packets;
|
||||
struct packet *_head, **_tail;
|
||||
uint32_t rx_count;
|
||||
uint32_t tx_count;
|
||||
};
|
||||
|
||||
struct network {
|
||||
struct sched_ent alarm;
|
||||
char name[16];
|
||||
char path[256];
|
||||
struct limit_state limit;
|
||||
long latency;
|
||||
char drop_packets;
|
||||
char drop_broadcast;
|
||||
char drop_unicast;
|
||||
uint8_t up;
|
||||
uint8_t echo;
|
||||
uint8_t drop_broadcast_collisions; // on wifi collisions cause dropped packets
|
||||
uint32_t rx_count;
|
||||
uint32_t tx_count;
|
||||
struct peer *peer_list;
|
||||
struct network *_next;
|
||||
};
|
||||
|
||||
struct profile_total broadcast_stats= {
|
||||
.name="sock_alarm"
|
||||
};
|
||||
struct profile_total unicast_stats= {
|
||||
.name="unicast_alarm"
|
||||
};
|
||||
|
||||
struct command_state *stdin_state;
|
||||
|
||||
struct network *networks=NULL;
|
||||
static void unicast_alarm(struct sched_ent *alarm);
|
||||
|
||||
const struct __sourceloc __whence = __NOWHERE__;
|
||||
|
||||
static const char *_trimbuildpath(const char *path)
|
||||
{
|
||||
/* Remove common path prefix */
|
||||
int lastsep = 0;
|
||||
int i;
|
||||
for (i = 0; __FILE__[i] && path[i]; ++i) {
|
||||
if (i && path[i - 1] == '/')
|
||||
lastsep = i;
|
||||
if (__FILE__[i] != path[i])
|
||||
break;
|
||||
}
|
||||
return &path[lastsep];
|
||||
}
|
||||
|
||||
void cf_on_config_change()
|
||||
{
|
||||
}
|
||||
|
||||
void logMessage(int level, struct __sourceloc whence, const char *fmt, ...)
|
||||
{
|
||||
const char *levelstr = "UNKWN:";
|
||||
switch (level) {
|
||||
case LOG_LEVEL_FATAL:
|
||||
levelstr = "FATAL:";
|
||||
break;
|
||||
case LOG_LEVEL_ERROR:
|
||||
levelstr = "ERROR:";
|
||||
break;
|
||||
case LOG_LEVEL_INFO:
|
||||
levelstr = "INFO:";
|
||||
break;
|
||||
case LOG_LEVEL_WARN:
|
||||
levelstr = "WARN:";
|
||||
break;
|
||||
case LOG_LEVEL_DEBUG:
|
||||
levelstr = "DEBUG:";
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
gettimeofday(&tv, NULL);
|
||||
localtime_r(&tv.tv_sec, &tm);
|
||||
char buf[50];
|
||||
strftime(buf, sizeof buf, "%T", &tm);
|
||||
fprintf(stderr, "%s.%03u ", buf, (unsigned int)tv.tv_usec / 1000);
|
||||
|
||||
fprintf(stderr, "%s ", levelstr);
|
||||
if (whence.file) {
|
||||
fprintf(stderr, "%s", _trimbuildpath(whence.file));
|
||||
if (whence.line)
|
||||
fprintf(stderr, ":%u", whence.line);
|
||||
if (whence.function)
|
||||
fprintf(stderr, ":%s()", whence.function);
|
||||
fputc(' ', stderr);
|
||||
} else if (whence.function) {
|
||||
fprintf(stderr, "%s() ", whence.function);
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
void logFlush()
|
||||
{
|
||||
}
|
||||
void logConfigChanged()
|
||||
{
|
||||
}
|
||||
|
||||
int serverMode=0;
|
||||
|
||||
static void recv_packet(int fd, struct network *network, struct peer *destination)
|
||||
{
|
||||
struct socket_address addr;
|
||||
struct packet *packet=emalloc_zero(sizeof(struct packet));
|
||||
if (!packet)
|
||||
return;
|
||||
network->rx_count++;
|
||||
packet->recv_time = gettime_ms();
|
||||
packet->destination = destination;
|
||||
struct iovec iov[]= {
|
||||
{
|
||||
.iov_base = (void*)&packet->buff,
|
||||
.iov_len = sizeof(packet->buff)
|
||||
}
|
||||
};
|
||||
struct msghdr hdr= {
|
||||
.msg_name=(void *)&addr.addr,
|
||||
.msg_namelen=sizeof(addr.store),
|
||||
.msg_iov=iov,
|
||||
.msg_iovlen=1,
|
||||
};
|
||||
ssize_t ret = recvmsg(fd, &hdr, 0);
|
||||
if (ret==-1) {
|
||||
free(packet);
|
||||
WHYF_perror("recvmsg(%d,...)", fd);
|
||||
return;
|
||||
}
|
||||
|
||||
addr.addrlen = hdr.msg_namelen;
|
||||
packet->len = ret;
|
||||
packet->tdma_order = rand()&31;
|
||||
|
||||
struct peer *peer = network->peer_list;
|
||||
while(peer) {
|
||||
if (cmp_sockaddr(&addr, &peer->addr)==0)
|
||||
break;
|
||||
peer=peer->_next;
|
||||
}
|
||||
if (!peer) {
|
||||
DEBUGF("New peer %s", alloca_socket_address(&addr));
|
||||
struct socket_address unicast_addr;
|
||||
unicast_addr.local.sun_family=AF_UNIX;
|
||||
strbuf d = strbuf_local(unicast_addr.local.sun_path, sizeof unicast_addr.local.sun_path);
|
||||
static unsigned peerid=0;
|
||||
strbuf_sprintf(d, "%s/peer%d", network->path, peerid++);
|
||||
if (strbuf_overrun(d)) {
|
||||
WHY("Path too long");
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
unicast_addr.addrlen=sizeof unicast_addr.local.sun_family + strlen(unicast_addr.local.sun_path) + 1;
|
||||
|
||||
peer = emalloc_zero(sizeof(struct peer));
|
||||
if (!peer) {
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
peer->alarm.poll.fd=esocket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (peer->alarm.poll.fd==-1) {
|
||||
free(packet);
|
||||
free(peer);
|
||||
return;
|
||||
}
|
||||
if (socket_bind(peer->alarm.poll.fd, &unicast_addr)==-1) {
|
||||
free(packet);
|
||||
free(peer);
|
||||
return;
|
||||
}
|
||||
set_nonblock(peer->alarm.poll.fd);
|
||||
peer->alarm.function=unicast_alarm;
|
||||
peer->alarm.poll.events=POLLIN;
|
||||
peer->alarm.context = peer;
|
||||
peer->network = network;
|
||||
peer->addr = addr;
|
||||
peer->_next = network->peer_list;
|
||||
peer->_tail = &peer->_head;
|
||||
peer->max_packets = 100;
|
||||
peer->alarm.stats=&unicast_stats;
|
||||
watch(&peer->alarm);
|
||||
network->peer_list = peer;
|
||||
}
|
||||
|
||||
peer->tx_count++;
|
||||
|
||||
// drop packets if the network is "down" or the peer queue is full
|
||||
if (!network->up || peer->packet_count >= peer->max_packets) {
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
*peer->_tail = packet;
|
||||
peer->_tail = &packet->_next;
|
||||
peer->packet_count++;
|
||||
time_ms_t allowed = limit_next_allowed(&network->limit);
|
||||
if (allowed < packet->recv_time + network->latency)
|
||||
allowed = packet->recv_time + network->latency;
|
||||
if (!is_scheduled(&network->alarm) || allowed < network->alarm.alarm){
|
||||
unschedule(&network->alarm);
|
||||
network->alarm.alarm = allowed;
|
||||
network->alarm.deadline = network->alarm.alarm;
|
||||
schedule(&network->alarm);
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_alarm(struct sched_ent *alarm)
|
||||
{
|
||||
struct peer *peer = (struct peer*)alarm->context;
|
||||
|
||||
if (alarm->poll.revents & POLLIN) {
|
||||
recv_packet(alarm->poll.fd, peer->network, peer);
|
||||
}
|
||||
}
|
||||
|
||||
static int should_drop(struct network *network, struct packet *packet){
|
||||
if (network->drop_packets>=100)
|
||||
return 1;
|
||||
if (packet->destination){
|
||||
if (network->drop_unicast)
|
||||
return 1;
|
||||
}else{
|
||||
if (network->drop_broadcast)
|
||||
return 1;
|
||||
}
|
||||
if (network->drop_packets <= 0)
|
||||
return 0;
|
||||
if (rand()%100 >= network->drop_packets)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sock_alarm(struct sched_ent *alarm)
|
||||
{
|
||||
struct network *network = (struct network*)alarm->context;
|
||||
|
||||
if (alarm->poll.revents & POLLIN) {
|
||||
recv_packet(alarm->poll.fd, network, NULL);
|
||||
}
|
||||
|
||||
if (alarm->poll.revents == 0) {
|
||||
time_ms_t allowed = limit_next_allowed(&network->limit);
|
||||
time_ms_t now = gettime_ms();
|
||||
if (allowed > now){
|
||||
alarm->deadline = alarm->alarm = allowed;
|
||||
schedule(alarm);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t tdma_order=127;
|
||||
unsigned tdma_count=0;
|
||||
struct packet *packet=NULL;
|
||||
struct peer *sender=NULL;
|
||||
|
||||
// what's the best TDMA value?
|
||||
{
|
||||
struct peer *peer = network->peer_list;
|
||||
while(peer){
|
||||
struct packet *p = peer->_head;
|
||||
if (p && p->recv_time + network->latency <= now){
|
||||
if (tdma_order > p->tdma_order){
|
||||
tdma_order=p->tdma_order;
|
||||
tdma_count=1;
|
||||
packet = p;
|
||||
sender = peer;
|
||||
}else if(tdma_order==p->tdma_order){
|
||||
tdma_count++;
|
||||
packet = NULL;
|
||||
sender = NULL;
|
||||
}
|
||||
}
|
||||
peer = peer->_next;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdma_count!=0){
|
||||
limit_is_allowed(&network->limit);
|
||||
|
||||
if (packet && tdma_count==1 && should_drop(network, packet)==0){
|
||||
// deliver the packet
|
||||
struct iovec iov[]= {
|
||||
{
|
||||
.iov_base = (void*)&packet->buff,
|
||||
.iov_len = packet->len
|
||||
}
|
||||
};
|
||||
struct msghdr hdr= {
|
||||
.msg_iov=iov,
|
||||
.msg_iovlen=1,
|
||||
};
|
||||
|
||||
network->tx_count++;
|
||||
struct peer *peer = network->peer_list;
|
||||
while(peer) {
|
||||
if ((packet->destination == peer || !packet->destination)
|
||||
&& (network->echo || peer !=sender)) {
|
||||
hdr.msg_name=(void *)&peer->addr.addr;
|
||||
hdr.msg_namelen=peer->addr.addrlen;
|
||||
// failure isn't fatal...
|
||||
if (sendmsg(sender->alarm.poll.fd, &hdr, 0)==-1)
|
||||
WARN_perror("sendmsg()");
|
||||
peer->rx_count++;
|
||||
}
|
||||
peer = peer->_next;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdma_count>1){
|
||||
// collision!
|
||||
struct peer *peer = network->peer_list;
|
||||
while(peer){
|
||||
struct packet *p = peer->_head;
|
||||
if (p
|
||||
&& p->recv_time + network->latency <= now
|
||||
&& tdma_order==p->tdma_order){
|
||||
if (!p->destination && network->drop_broadcast_collisions){
|
||||
if (p==packet) // NOOP?
|
||||
packet = NULL;
|
||||
peer->_head = p->_next;
|
||||
if (!peer->_head)
|
||||
peer->_tail = &peer->_head;
|
||||
peer->packet_count --;
|
||||
free(p);
|
||||
}else{
|
||||
p->tdma_order = rand()&31;
|
||||
}
|
||||
}
|
||||
peer = peer->_next;
|
||||
}
|
||||
}
|
||||
|
||||
// free the sent packet
|
||||
if (sender && packet){
|
||||
sender->_head = packet->_next;
|
||||
if (!sender->_head)
|
||||
sender->_tail = &sender->_head;
|
||||
sender->packet_count --;
|
||||
free(packet);
|
||||
}
|
||||
}
|
||||
|
||||
// when is the next packet allowed?
|
||||
{
|
||||
time_ms_t next = TIME_MS_NEVER_WILL;
|
||||
struct peer *peer = network->peer_list;
|
||||
while(peer){
|
||||
struct packet *p = peer->_head;
|
||||
if (p && next > p->recv_time + network->latency){
|
||||
next = p->recv_time + network->latency;
|
||||
}
|
||||
peer = peer->_next;
|
||||
}
|
||||
time_ms_t allowed = limit_next_allowed(&network->limit);
|
||||
if (next < allowed)
|
||||
next = allowed;
|
||||
alarm->deadline = alarm->alarm = next;
|
||||
schedule(alarm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void signal_handler(int UNUSED(signal))
|
||||
{
|
||||
command_close(stdin_state);
|
||||
}
|
||||
|
||||
static void crash_handler(int signal)
|
||||
{
|
||||
LOGF(LOG_LEVEL_FATAL, "Caught signal %s", alloca_signal_name(signal));
|
||||
dump_stack(LOG_LEVEL_FATAL);
|
||||
// TODO Move logBackTrace to log utils?
|
||||
// BACKTRACE;
|
||||
// Now die of the same signal, so that our exit status reflects the cause.
|
||||
INFOF("Re-sending signal %d to self", signal);
|
||||
kill(getpid(), signal);
|
||||
// If that didn't work, then die normally.
|
||||
INFOF("exit(%d)", -signal);
|
||||
exit(-signal);
|
||||
}
|
||||
|
||||
static struct network *find_network(const char *name)
|
||||
{
|
||||
struct network *n = networks;
|
||||
while(n) {
|
||||
if (strcasecmp(name, n->name)==0)
|
||||
return n;
|
||||
n=n->_next;
|
||||
}
|
||||
WHYF("Network %s not found\n", n->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int console_create(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
||||
{
|
||||
const char *name, *path;
|
||||
if ( cli_arg(parsed, "name", &name, NULL, NULL) == -1
|
||||
|| cli_arg(parsed, "path", &path, NULL, NULL) == -1)
|
||||
return -1;
|
||||
|
||||
struct socket_address addr;
|
||||
addr.local.sun_family=AF_UNIX;
|
||||
|
||||
strbuf b = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
|
||||
strbuf_path_join(b, path, "broadcast", NULL);
|
||||
if (strbuf_overrun(b))
|
||||
return WHY("Path too long");
|
||||
|
||||
addr.addrlen=sizeof addr.local.sun_family + strlen(addr.local.sun_path) + 1;
|
||||
int fd = esocket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (fd==-1)
|
||||
return -1;
|
||||
if (socket_bind(fd, &addr)==-1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
set_nonblock(fd);
|
||||
|
||||
struct network *n = emalloc_zero(sizeof(struct network));
|
||||
if (!n)
|
||||
return -1;
|
||||
|
||||
strbuf_init(b, n->name, sizeof n->name);
|
||||
strbuf_puts(b, name);
|
||||
if (strbuf_overrun(b)) {
|
||||
socket_unlink_close(fd);
|
||||
free(n);
|
||||
return WHY("Name is too long");
|
||||
}
|
||||
strbuf_init(b, n->path, sizeof n->path);
|
||||
strbuf_puts(b, path);
|
||||
if (strbuf_overrun(b)) {
|
||||
socket_unlink_close(fd);
|
||||
free(n);
|
||||
return WHY("Path is too long");
|
||||
}
|
||||
|
||||
n->_next = networks;
|
||||
networks = n;
|
||||
|
||||
limit_init(&n->limit, 0);
|
||||
n->alarm.poll.fd = fd;
|
||||
n->alarm.function=sock_alarm;
|
||||
n->alarm.poll.events=POLLIN;
|
||||
n->alarm.stats=&broadcast_stats;
|
||||
n->alarm.context=n;
|
||||
watch(&n->alarm);
|
||||
|
||||
INFOF("Created socket %s for network %s", alloca_socket_address(&addr), name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_variable(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
||||
{
|
||||
const char *name;
|
||||
if (cli_arg(parsed, "name", &name, NULL, NULL) == -1)
|
||||
return -1;
|
||||
struct network *n = find_network(name);
|
||||
if (!n)
|
||||
return -1;
|
||||
|
||||
unsigned i;
|
||||
for (i = 2; i+1 < parsed->argc; i+=2) {
|
||||
const char *arg = parsed->args[i];
|
||||
const char *value = parsed->args[i+1];
|
||||
|
||||
if (strcmp(arg, "latency") == 0) {
|
||||
n->latency = atol(value);
|
||||
}else if (strcmp(arg, "echo") == 0) {
|
||||
n->echo = atoi(value) != 0;
|
||||
}else if (strcmp(arg, "rate") == 0) {
|
||||
uint32_t rate = atoi(value);
|
||||
limit_init(&n->limit, rate);
|
||||
}else if (strcmp(arg, "drop_packets") == 0){
|
||||
n->drop_packets= atol(value);
|
||||
}else if (strcmp(arg, "drop_broadcast") == 0){
|
||||
n->drop_broadcast=atol(value)!=0;
|
||||
}else if (strcmp(arg, "drop_unicast") == 0){
|
||||
n->drop_unicast=atol(value)!=0;
|
||||
}else
|
||||
return WHYF("Unknown variable %s", arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_up(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 1; i < parsed->argc; i++) {
|
||||
struct network *n = find_network(parsed->args[i]);
|
||||
if (!n)
|
||||
return -1;
|
||||
|
||||
n->up = 1;
|
||||
INFOF("Network %s is now up", n->name);
|
||||
DEBUGF("Minimum latency %dms", (int)n->latency);
|
||||
DEBUGF("Will drop %d%% of packets", n->drop_packets);
|
||||
DEBUGF("Will %s broadcast packets", n->drop_broadcast?"drop":"allow");
|
||||
DEBUGF("Will %s unicast packets", n->drop_unicast?"drop":"allow");
|
||||
DEBUGF("Allowing a maximum of %d packets every %"PRId64"ms",
|
||||
n->limit.burst_size,
|
||||
n->limit.burst_length);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_down(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 1; i < parsed->argc; i++) {
|
||||
struct network *n = find_network(parsed->args[i]);
|
||||
if (!n)
|
||||
return -1;
|
||||
|
||||
// free any pending packets
|
||||
struct peer *peer = n->peer_list;
|
||||
while(peer) {
|
||||
struct packet *p = peer->_head;
|
||||
while(p) {
|
||||
struct packet *f = p;
|
||||
p = p->_next;
|
||||
free(f);
|
||||
}
|
||||
peer->_head=NULL;
|
||||
peer=peer->_next;
|
||||
}
|
||||
|
||||
n->up = 0;
|
||||
unschedule(&n->alarm);
|
||||
|
||||
INFOF("Network %s is now down", n->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_quit(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context))
|
||||
{
|
||||
command_close(stdin_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cli_schema console_commands[]= {
|
||||
{console_create,{"create","<name>","<path>",NULL},0,"Create a named network"},
|
||||
{console_variable,{"set", "<name>", "<variable>","<value>","...",NULL},0,"Set a property of the network"},
|
||||
{console_up,{"up", "<name>", "...", NULL},0,"Bring a network up"},
|
||||
{console_down,{"down","<name>","...",NULL},0,"Bring a network down"},
|
||||
{console_quit,{"quit",NULL},0,"Exit the simulator"},
|
||||
{NULL, {NULL, NULL, NULL}, 0, NULL},
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
cf_init();
|
||||
|
||||
/* Catch crash signals so that we can log a backtrace before expiring. */
|
||||
struct sigaction sig;
|
||||
sig.sa_handler = crash_handler;
|
||||
sigemptyset(&sig.sa_mask); // Don't block any signals during handler
|
||||
sig.sa_flags = SA_NODEFER | SA_RESETHAND; // So the signal handler can kill the process by re-sending the same signal to itself
|
||||
sigaction(SIGSEGV, &sig, NULL);
|
||||
sigaction(SIGFPE, &sig, NULL);
|
||||
sigaction(SIGILL, &sig, NULL);
|
||||
sigaction(SIGBUS, &sig, NULL);
|
||||
sigaction(SIGABRT, &sig, NULL);
|
||||
|
||||
/* Catch SIGHUP, SIGINT so we can shutdown gracefully */
|
||||
sig.sa_handler = signal_handler;
|
||||
sigemptyset(&sig.sa_mask);
|
||||
sigaddset(&sig.sa_mask, SIGHUP);
|
||||
sigaddset(&sig.sa_mask, SIGINT);
|
||||
sig.sa_flags = 0;
|
||||
sigaction(SIGHUP, &sig, NULL);
|
||||
sigaction(SIGINT, &sig, NULL);
|
||||
|
||||
stdin_state = command_register(console_commands, STDIN_FILENO);
|
||||
|
||||
while(!is_command_closed(stdin_state) && fd_poll())
|
||||
;
|
||||
|
||||
INFO("Shutting down");
|
||||
command_free(stdin_state);
|
||||
|
||||
{
|
||||
struct network *n = networks;
|
||||
while(n) {
|
||||
DEBUGF("Closing network %s, TX %d RX %d", n->name, n->tx_count, n->rx_count);
|
||||
unwatch(&n->alarm);
|
||||
socket_unlink_close(n->alarm.poll.fd);
|
||||
struct peer *p = n->peer_list;
|
||||
while(p) {
|
||||
DEBUGF("Closing peer proxy socket, TX %d RX %d", p->tx_count, p->rx_count);
|
||||
unwatch(&p->alarm);
|
||||
socket_unlink_close(p->alarm.poll.fd);
|
||||
struct peer *f = p;
|
||||
p=p->_next;
|
||||
free(f);
|
||||
}
|
||||
struct network *f=n;
|
||||
n=n->_next;
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
4
simulator.h
Normal file
4
simulator.h
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
struct {
|
||||
|
||||
}
|
@ -97,3 +97,9 @@ SERVAL_DAEMON_SOURCES = \
|
||||
fec-3.0.1/encode_rs_8.c \
|
||||
fec-3.0.1/init_rs_char.c \
|
||||
context1.c
|
||||
|
||||
SIMULATOR_SOURCES = cli.c conf.c conf_om.c conf_parse.c conf_schema.c \
|
||||
console.c simulator.c socket.c fdqueue.c performance_timing.c \
|
||||
str.c os.c mem.c net.c log_util.c strbuf.c strbuf_helpers.c \
|
||||
dataformats.c xprintf.c instance.c limit.c version.c
|
||||
|
||||
|
232
tests/routing
232
tests/routing
@ -308,29 +308,60 @@ teardown_simulate_extender() {
|
||||
tfw_cat "$SERVALD_VAR/radioerr"
|
||||
}
|
||||
|
||||
_simulator() {
|
||||
# TODO timeout & failure reporting?
|
||||
executeOk --error-on-fail $servald_build_root/simulator <$SIM_IN
|
||||
tfw_cat --stdout --stderr
|
||||
rm $SIM_IN
|
||||
}
|
||||
start_simulator() {
|
||||
SIM_IN="$PWD/SIM_IN"
|
||||
mkfifo "$SIM_IN"
|
||||
exec 8<>"$SIM_IN" # stop fifo from blocking
|
||||
fork %simulator _simulator
|
||||
}
|
||||
simulator_command() {
|
||||
tfw_log "$@"
|
||||
assert_fork_is_running %simulator
|
||||
echo "$@" >>"$SIM_IN"
|
||||
}
|
||||
simulator_quit() {
|
||||
simulator_command quit
|
||||
fork_wait %simulator
|
||||
}
|
||||
|
||||
doc_multiple_nodes="Multiple nodes on one link"
|
||||
setup_multiple_nodes() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B +C +D create_single_identity
|
||||
foreach_instance +A +B +C +D add_servald_interface 1
|
||||
start_simulator
|
||||
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||
foreach_instance +A +B +C +D start_servald_server
|
||||
}
|
||||
test_multiple_nodes() {
|
||||
wait_until path_exists +A +B
|
||||
wait_until path_exists +A +C
|
||||
wait_until path_exists +A +D
|
||||
wait_until path_exists +B +A
|
||||
wait_until path_exists +C +A
|
||||
wait_until path_exists +D +A
|
||||
simulator_command set "net" "latency" "100"
|
||||
simulator_command up "net"
|
||||
wait_until --timeout=10 path_exists +A +B
|
||||
wait_until --timeout=5 path_exists +A +C
|
||||
wait_until --timeout=5 path_exists +A +D
|
||||
wait_until --timeout=5 path_exists +B +A
|
||||
wait_until --timeout=5 path_exists +C +A
|
||||
wait_until --timeout=5 path_exists +D +A
|
||||
set_instance +A
|
||||
executeOk_servald mdp ping --timeout=3 $SIDB 1
|
||||
tfw_cat --stdout --stderr
|
||||
simulator_command set "net" "latency" "150"
|
||||
executeOk_servald mdp ping --timeout=3 $SIDC 1
|
||||
tfw_cat --stdout --stderr
|
||||
simulator_command set "net" "latency" "200"
|
||||
executeOk_servald mdp ping --timeout=3 $SIDD 1
|
||||
tfw_cat --stdout --stderr
|
||||
}
|
||||
finally_multiple_nodes() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_scan="Network scan with isolated clients"
|
||||
setup_scan() {
|
||||
@ -410,12 +441,14 @@ setup_broadcast_only() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --file 1
|
||||
foreach_instance +A +B \
|
||||
executeOk_servald config set interfaces.1.drop_unicasts 1
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
start_simulator
|
||||
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command set "net" "drop_unicast" "1"
|
||||
foreach_instance +A +B start_servald_server
|
||||
}
|
||||
test_broadcast_only() {
|
||||
simulator_command up "net"
|
||||
set_instance +A
|
||||
wait_until has_link --broadcast $SIDB
|
||||
set_instance +B
|
||||
@ -424,6 +457,9 @@ test_broadcast_only() {
|
||||
executeOk_servald mdp ping --timeout=3 $SIDB 1
|
||||
tfw_cat --stdout --stderr
|
||||
}
|
||||
finally_broadcast_only() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_prefer_unicast="Prefer unicast packets"
|
||||
setup_prefer_unicast() {
|
||||
@ -535,27 +571,37 @@ doc_lose_neighbours="Lose and regain neighbours"
|
||||
setup_lose_neighbours() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
start_simulator
|
||||
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||
foreach_instance +A +B +C create_single_identity
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
foreach_instance +B +C add_servald_interface 2
|
||||
foreach_instance +A +B +C start_servald_server
|
||||
}
|
||||
test_lose_neighbours() {
|
||||
simulator_command up "net1" "net2"
|
||||
wait_until path_exists +A +B +C
|
||||
wait_until path_exists +C +B +A
|
||||
stop_servald_server +B
|
||||
simulator_command down "net1" "net2"
|
||||
foreach_instance +A +C \
|
||||
wait_until --timeout=30 instance_offline +B
|
||||
set_instance +A
|
||||
wait_until --timeout=30 instance_offline +C
|
||||
start_servald_server +B
|
||||
simulator_command up "net1" "net2"
|
||||
wait_until --timeout=20 path_exists +A +B +C
|
||||
wait_until --timeout=20 path_exists +C +B +A
|
||||
}
|
||||
finally_lose_neighbours() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
setup_multi_interface() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
start_simulator
|
||||
simulator_command create "wlan0" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command create "eth0" "$SERVALD_VAR/dummy2/"
|
||||
foreach_instance +A +B create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --wifi 1
|
||||
foreach_instance +A +B add_servald_interface --ethernet 2
|
||||
@ -564,36 +610,41 @@ setup_multi_interface() {
|
||||
|
||||
doc_multi_interface="Multiple links of different types to the same neighbour"
|
||||
test_multi_interface() {
|
||||
simulator_command up "wlan0" "eth0"
|
||||
set_instance +A
|
||||
wait_until has_link --interface "dummy2.*" $SIDB
|
||||
set_instance +B
|
||||
wait_until has_link --interface "dummy2.*" $SIDA
|
||||
set_instance +A
|
||||
executeOk_servald config set interfaces.2.exclude 1
|
||||
simulator_command down "eth0"
|
||||
wait_until has_link --interface "dummy1.*" $SIDB
|
||||
set_instance +B
|
||||
wait_until has_link --interface "dummy1.*" $SIDA
|
||||
set_instance +A
|
||||
executeOk_servald config del interfaces.2.exclude
|
||||
simulator_command up "eth0"
|
||||
wait_until has_link --interface "dummy2.*" $SIDB
|
||||
set_instance +B
|
||||
wait_until has_link --interface "dummy2.*" $SIDA
|
||||
}
|
||||
finally_multi_interface() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_ping_unreliable_1hop="Ping over a 1-hop unreliable link"
|
||||
setup_ping_unreliable_1hop() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --file 1
|
||||
foreach_instance +A +B \
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 40
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
start_simulator
|
||||
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command set "net" "drop_packets" "40"
|
||||
foreach_instance +A +B start_servald_server
|
||||
}
|
||||
test_ping_unreliable_1hop() {
|
||||
wait_until path_exists +A +B
|
||||
wait_until path_exists +B +A
|
||||
simulator_command up "net"
|
||||
wait_until --timeout=10 path_exists +A +B
|
||||
wait_until --timeout=5 path_exists +B +A
|
||||
set_instance +A
|
||||
executeOk_servald mdp ping --interval=0.100 --timeout=3 --wait-for-duplicates $SIDB 100
|
||||
tfw_cat --stdout --stderr
|
||||
@ -602,23 +653,26 @@ test_ping_unreliable_1hop() {
|
||||
assert [ "$received" -ge 98 ]
|
||||
assert [ "$duplicates" -le 2 ]
|
||||
}
|
||||
finally_ping_unreliable_1hop() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_ping_unreliable_2hop="Ping over a 2-hop unreliable link"
|
||||
setup_ping_unreliable_2hop() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B +C create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --file 1
|
||||
foreach_instance +A +B \
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 40
|
||||
foreach_instance +B +C add_servald_interface --file 2
|
||||
foreach_instance +B +C \
|
||||
executeOk_servald config \
|
||||
set interfaces.2.drop_packets 40
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
foreach_instance +B +C add_servald_interface 2
|
||||
start_simulator
|
||||
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command set "net1" "drop_packets" "40"
|
||||
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||
simulator_command set "net2" "drop_packets" "40"
|
||||
foreach_instance +A +B +C start_servald_server
|
||||
}
|
||||
test_ping_unreliable_2hop() {
|
||||
simulator_command up "net1" "net2"
|
||||
wait_until path_exists +A +B +C
|
||||
wait_until path_exists +C +B +A
|
||||
set_instance +A
|
||||
@ -629,49 +683,79 @@ test_ping_unreliable_2hop() {
|
||||
assert [ "$received" -ge 98 ]
|
||||
assert [ "$duplicates" -le 5 ]
|
||||
}
|
||||
finally_ping_unreliable_2hop() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
# TODO implement congestion control, use this test as a basis for improving...
|
||||
doc_ping_congested="Ping flood over an unreliable and congested link"
|
||||
setup_ping_congested() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B create_single_identity
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
start_simulator
|
||||
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command set "net1" \
|
||||
"drop_packets" "20" \
|
||||
"latency" "20" \
|
||||
"rate" "20000"
|
||||
foreach_instance +A +B +C start_servald_server
|
||||
}
|
||||
test_ping_congested() {
|
||||
simulator_command up "net1"
|
||||
wait_until --timeout=10 path_exists +A +B
|
||||
wait_until --timeout=5 path_exists +B +A
|
||||
set_instance +A
|
||||
executeOk_servald mdp ping --interval=0.100 --timeout=3 $SIDB 100
|
||||
tfw_cat --stdout --stderr
|
||||
}
|
||||
finally_ping_congested() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_brping_unreliable_1hop="Broadcast ping over a 1-hop unreliable link"
|
||||
setup_brping_unreliable_1hop() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --file 1
|
||||
foreach_instance +A +B \
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 20
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
start_simulator
|
||||
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command set "net" "drop_packets" "20"
|
||||
foreach_instance +A +B start_servald_server
|
||||
}
|
||||
test_brping_unreliable_1hop() {
|
||||
simulator_command up "net"
|
||||
wait_until path_exists +A +B
|
||||
wait_until path_exists +B +A
|
||||
set_instance +A
|
||||
executeOk_servald mdp ping --interval=0.100 --timeout=2 --wait-for-duplicates broadcast 100
|
||||
tfw_cat --stdout --stderr
|
||||
}
|
||||
finally_brping_unreliable_1hop() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_unreliable_links="Prefer a longer, better path vs an unreliable link"
|
||||
setup_unreliable_links() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B +C create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --file 1
|
||||
foreach_instance +B +C add_servald_interface --file 2
|
||||
foreach_instance +A +C add_servald_interface --file 3
|
||||
set_instance +A
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 5 \
|
||||
set interfaces.3.drop_packets 70
|
||||
set_instance +B
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 5 \
|
||||
set interfaces.2.drop_packets 5
|
||||
set_instance +C
|
||||
executeOk_servald config \
|
||||
set interfaces.2.drop_packets 5 \
|
||||
set interfaces.3.drop_packets 70
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
foreach_instance +B +C add_servald_interface 2
|
||||
foreach_instance +A +C add_servald_interface 3
|
||||
start_simulator
|
||||
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||
simulator_command create "net3" "$SERVALD_VAR/dummy3/"
|
||||
simulator_command set "net1" "drop_packets" "5"
|
||||
simulator_command set "net2" "drop_packets" "5"
|
||||
simulator_command set "net3" "drop_packets" "70"
|
||||
foreach_instance +A +B +C start_servald_server
|
||||
}
|
||||
test_unreliable_links() {
|
||||
simulator_command up "net1" "net2" "net3"
|
||||
wait_until path_exists +A +B +C
|
||||
wait_until path_exists +C +B +A
|
||||
set_instance +A
|
||||
@ -685,43 +769,40 @@ test_unreliable_links() {
|
||||
wait_until path_exists +A +B +C
|
||||
wait_until path_exists +C +B +A
|
||||
}
|
||||
finally_unreliable_links() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
doc_unreliable_links2="Choose the best multihop path with some unreliable links"
|
||||
setup_unreliable_links2() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B +C +D create_single_identity
|
||||
foreach_instance +A +B add_servald_interface --file 1
|
||||
foreach_instance +A +C add_servald_interface --file 2
|
||||
foreach_instance +A +D add_servald_interface --file 3
|
||||
foreach_instance +B +C add_servald_interface --file 4
|
||||
foreach_instance +B +D add_servald_interface --file 5
|
||||
foreach_instance +C +D add_servald_interface --file 6
|
||||
set_instance +A
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 5 \
|
||||
set interfaces.2.drop_packets 40 \
|
||||
set interfaces.3.drop_packets 90
|
||||
set_instance +B
|
||||
executeOk_servald config \
|
||||
set interfaces.1.drop_packets 5 \
|
||||
set interfaces.4.drop_packets 5 \
|
||||
set interfaces.5.drop_packets 40
|
||||
set_instance +C
|
||||
executeOk_servald config \
|
||||
set interfaces.2.drop_packets 40 \
|
||||
set interfaces.4.drop_packets 5 \
|
||||
set interfaces.6.drop_packets 5
|
||||
set_instance +D
|
||||
executeOk_servald config \
|
||||
set interfaces.3.drop_packets 90 \
|
||||
set interfaces.5.drop_packets 40 \
|
||||
set interfaces.6.drop_packets 5
|
||||
foreach_instance +A +B add_servald_interface 1
|
||||
foreach_instance +A +C add_servald_interface 2
|
||||
foreach_instance +A +D add_servald_interface 3
|
||||
foreach_instance +B +C add_servald_interface 4
|
||||
foreach_instance +B +D add_servald_interface 5
|
||||
foreach_instance +C +D add_servald_interface 6
|
||||
start_simulator
|
||||
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||
simulator_command create "net3" "$SERVALD_VAR/dummy3/"
|
||||
simulator_command create "net4" "$SERVALD_VAR/dummy4/"
|
||||
simulator_command create "net5" "$SERVALD_VAR/dummy5/"
|
||||
simulator_command create "net6" "$SERVALD_VAR/dummy6/"
|
||||
simulator_command set "net1" "drop_packets" "5"
|
||||
simulator_command set "net2" "drop_packets" "60"
|
||||
simulator_command set "net3" "drop_packets" "90"
|
||||
simulator_command set "net4" "drop_packets" "5"
|
||||
simulator_command set "net5" "drop_packets" "60"
|
||||
simulator_command set "net6" "drop_packets" "5"
|
||||
foreach_instance +A +B +C +D start_servald_server
|
||||
}
|
||||
test_unreliable_links2() {
|
||||
wait_until path_exists +A +B +C +D
|
||||
wait_until path_exists +D +C +B +A
|
||||
simulator_command up "net1" "net2" "net3" "net4" "net5" "net6"
|
||||
wait_until --timeout=20 path_exists +A +B +C +D
|
||||
wait_until --timeout=20 path_exists +D +C +B +A
|
||||
set_instance +A
|
||||
executeOk_servald mdp ping --interval=0.100 --timeout=3 --wait-for-duplicates $SIDD 100
|
||||
tfw_cat --stdout --stderr
|
||||
@ -732,6 +813,9 @@ test_unreliable_links2() {
|
||||
wait_until --timeout=20 path_exists +A +B +C +D
|
||||
wait_until --timeout=20 path_exists +D +C +B +A
|
||||
}
|
||||
finally_unreliable_links2() {
|
||||
simulator_quit
|
||||
}
|
||||
|
||||
setup_circle() {
|
||||
setup_servald
|
||||
|
Loading…
Reference in New Issue
Block a user