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
|
/tfw_createfile
|
||||||
/fakeradio
|
/fakeradio
|
||||||
/config_test
|
/config_test
|
||||||
|
/simulator
|
||||||
*.so
|
*.so
|
||||||
test.*.log
|
test.*.log
|
||||||
testlog
|
testlog
|
||||||
|
@ -29,6 +29,7 @@ SERVALD_OBJS= $(SERVALD_SRCS:.c=.o)
|
|||||||
SERVAL_DAEMON_OBJS= $(SERVAL_DAEMON_SOURCES:.c=.o)
|
SERVAL_DAEMON_OBJS= $(SERVAL_DAEMON_SOURCES:.c=.o)
|
||||||
MONITOR_CLIENT_OBJS= $(MONITOR_CLIENT_SRCS:.c=.o)
|
MONITOR_CLIENT_OBJS= $(MONITOR_CLIENT_SRCS:.c=.o)
|
||||||
MDP_CLIENT_OBJS= $(MDP_CLIENT_SRCS:.c=.o)
|
MDP_CLIENT_OBJS= $(MDP_CLIENT_SRCS:.c=.o)
|
||||||
|
SIMULATOR_OBJS= $(SIMULATOR_SOURCES:.c=.o)
|
||||||
|
|
||||||
LDFLAGS=@LDFLAGS@ @LIBS@ @PTHREAD_LIBS@
|
LDFLAGS=@LDFLAGS@ @LIBS@ @PTHREAD_LIBS@
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ DEFS= @DEFS@
|
|||||||
|
|
||||||
all: servald libmonitorclient.so libmonitorclient.a test
|
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
|
sqlite-amalgamation-3070900/sqlite3.o: sqlite-amalgamation-3070900/sqlite3.c
|
||||||
@echo CC $<
|
@echo CC $<
|
||||||
@ -83,6 +84,7 @@ configure: $(wildcard configure.in)
|
|||||||
$(SERVAL_DAEMON_OBJS): $(HDRS)
|
$(SERVAL_DAEMON_OBJS): $(HDRS)
|
||||||
$(MONITOR_CLIENT_OBJS): $(HDRS)
|
$(MONITOR_CLIENT_OBJS): $(HDRS)
|
||||||
$(MDP_CLIENT_OBJS): $(HDRS)
|
$(MDP_CLIENT_OBJS): $(HDRS)
|
||||||
|
$(SIMULATOR_OBJS): $(HDRS)
|
||||||
|
|
||||||
servald: $(SERVALD_OBJS) version.o
|
servald: $(SERVALD_OBJS) version.o
|
||||||
@echo LINK $@
|
@echo LINK $@
|
||||||
@ -100,6 +102,10 @@ fakeradio: fakeradio.o
|
|||||||
@echo LINK $@
|
@echo LINK $@
|
||||||
@$(CC) $(CFLAGS) -Wall -o $@ fakeradio.o
|
@$(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
|
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 $@
|
@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)
|
@$(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);
|
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)
|
||||||
{
|
{
|
||||||
DIR *dir;
|
|
||||||
struct dirent *dp;
|
|
||||||
if ((dir = opendir(address->local.sun_path)) == NULL) {
|
|
||||||
WARNF_perror("opendir(%s)", alloca_str_toprint(address->local.sun_path));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
while ((dp = readdir(dir)) != NULL) {
|
|
||||||
struct socket_address addr;
|
struct socket_address addr;
|
||||||
|
|
||||||
strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
|
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);
|
strbuf_path_join(d, folder, file, NULL);
|
||||||
if (strbuf_overrun(d)){
|
if (strbuf_overrun(d))
|
||||||
WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
|
return WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(addr.local.sun_path, &st)) {
|
if (lstat(addr.local.sun_path, &st))
|
||||||
WARNF_perror("stat(%s)", alloca_str_toprint(addr.local.sun_path));
|
return 1;
|
||||||
continue;
|
if (!S_ISSOCK(st.st_mode))
|
||||||
}
|
return 1;
|
||||||
|
|
||||||
if (S_ISSOCK(st.st_mode)){
|
|
||||||
addr.local.sun_family = AF_UNIX;
|
addr.local.sun_family = AF_UNIX;
|
||||||
addr.addrlen = sizeof(addr.local.sun_family) + strlen(addr.local.sun_path)+1;
|
addr.addrlen = sizeof(addr.local.sun_family) + strlen(addr.local.sun_path)+1;
|
||||||
|
|
||||||
ssize_t sent = sendto(fd, bytes, len, 0,
|
ssize_t sent = sendto(fd, bytes, len, 0,
|
||||||
&addr.addr, addr.addrlen);
|
&addr.addr, addr.addrlen);
|
||||||
if (sent == -1)
|
if (sent == -1)
|
||||||
WHYF_perror("sendto(%d, %zu, %s)", fd, len, alloca_socket_address(&addr));
|
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(folder)) == NULL) {
|
||||||
|
WARNF_perror("opendir(%s)", alloca_str_toprint(folder));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
while ((dp = readdir(dir)) != NULL) {
|
||||||
|
send_local_packet(fd, bytes, len, folder, dp->d_name);
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return 0;
|
return 0;
|
||||||
@ -915,7 +920,7 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
|
|||||||
&& !destination->unicast){
|
&& !destination->unicast){
|
||||||
// find all sockets in this folder and send to them
|
// find all sockets in this folder and send to them
|
||||||
send_local_broadcast(interface->alarm.poll.fd,
|
send_local_broadcast(interface->alarm.poll.fd,
|
||||||
bytes, (size_t)len, &destination->address);
|
bytes, (size_t)len, destination->address.local.sun_path);
|
||||||
}else{
|
}else{
|
||||||
ssize_t sent = sendto(interface->alarm.poll.fd,
|
ssize_t sent = sendto(interface->alarm.poll.fd,
|
||||||
bytes, (size_t)len, 0,
|
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/encode_rs_8.c \
|
||||||
fec-3.0.1/init_rs_char.c \
|
fec-3.0.1/init_rs_char.c \
|
||||||
context1.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"
|
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"
|
doc_multiple_nodes="Multiple nodes on one link"
|
||||||
setup_multiple_nodes() {
|
setup_multiple_nodes() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B +C +D create_single_identity
|
foreach_instance +A +B +C +D create_single_identity
|
||||||
foreach_instance +A +B +C +D add_servald_interface 1
|
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
|
foreach_instance +A +B +C +D start_servald_server
|
||||||
}
|
}
|
||||||
test_multiple_nodes() {
|
test_multiple_nodes() {
|
||||||
wait_until path_exists +A +B
|
simulator_command set "net" "latency" "100"
|
||||||
wait_until path_exists +A +C
|
simulator_command up "net"
|
||||||
wait_until path_exists +A +D
|
wait_until --timeout=10 path_exists +A +B
|
||||||
wait_until path_exists +B +A
|
wait_until --timeout=5 path_exists +A +C
|
||||||
wait_until path_exists +C +A
|
wait_until --timeout=5 path_exists +A +D
|
||||||
wait_until path_exists +D +A
|
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
|
set_instance +A
|
||||||
executeOk_servald mdp ping --timeout=3 $SIDB 1
|
executeOk_servald mdp ping --timeout=3 $SIDB 1
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
|
simulator_command set "net" "latency" "150"
|
||||||
executeOk_servald mdp ping --timeout=3 $SIDC 1
|
executeOk_servald mdp ping --timeout=3 $SIDC 1
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
|
simulator_command set "net" "latency" "200"
|
||||||
executeOk_servald mdp ping --timeout=3 $SIDD 1
|
executeOk_servald mdp ping --timeout=3 $SIDD 1
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
}
|
}
|
||||||
|
finally_multiple_nodes() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
doc_scan="Network scan with isolated clients"
|
doc_scan="Network scan with isolated clients"
|
||||||
setup_scan() {
|
setup_scan() {
|
||||||
@ -410,12 +441,14 @@ setup_broadcast_only() {
|
|||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B create_single_identity
|
foreach_instance +A +B create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --file 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +A +B \
|
start_simulator
|
||||||
executeOk_servald config set interfaces.1.drop_unicasts 1
|
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||||
|
simulator_command set "net" "drop_unicast" "1"
|
||||||
foreach_instance +A +B start_servald_server
|
foreach_instance +A +B start_servald_server
|
||||||
}
|
}
|
||||||
test_broadcast_only() {
|
test_broadcast_only() {
|
||||||
|
simulator_command up "net"
|
||||||
set_instance +A
|
set_instance +A
|
||||||
wait_until has_link --broadcast $SIDB
|
wait_until has_link --broadcast $SIDB
|
||||||
set_instance +B
|
set_instance +B
|
||||||
@ -424,6 +457,9 @@ test_broadcast_only() {
|
|||||||
executeOk_servald mdp ping --timeout=3 $SIDB 1
|
executeOk_servald mdp ping --timeout=3 $SIDB 1
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
}
|
}
|
||||||
|
finally_broadcast_only() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
doc_prefer_unicast="Prefer unicast packets"
|
doc_prefer_unicast="Prefer unicast packets"
|
||||||
setup_prefer_unicast() {
|
setup_prefer_unicast() {
|
||||||
@ -535,27 +571,37 @@ doc_lose_neighbours="Lose and regain neighbours"
|
|||||||
setup_lose_neighbours() {
|
setup_lose_neighbours() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
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 +C create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +B +C add_servald_interface 2
|
foreach_instance +B +C add_servald_interface 2
|
||||||
foreach_instance +A +B +C start_servald_server
|
foreach_instance +A +B +C start_servald_server
|
||||||
}
|
}
|
||||||
test_lose_neighbours() {
|
test_lose_neighbours() {
|
||||||
|
simulator_command up "net1" "net2"
|
||||||
wait_until path_exists +A +B +C
|
wait_until path_exists +A +B +C
|
||||||
wait_until path_exists +C +B +A
|
wait_until path_exists +C +B +A
|
||||||
stop_servald_server +B
|
simulator_command down "net1" "net2"
|
||||||
foreach_instance +A +C \
|
foreach_instance +A +C \
|
||||||
wait_until --timeout=30 instance_offline +B
|
wait_until --timeout=30 instance_offline +B
|
||||||
set_instance +A
|
set_instance +A
|
||||||
wait_until --timeout=30 instance_offline +C
|
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 +A +B +C
|
||||||
wait_until --timeout=20 path_exists +C +B +A
|
wait_until --timeout=20 path_exists +C +B +A
|
||||||
}
|
}
|
||||||
|
finally_lose_neighbours() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
setup_multi_interface() {
|
setup_multi_interface() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
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 create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --wifi 1
|
foreach_instance +A +B add_servald_interface --wifi 1
|
||||||
foreach_instance +A +B add_servald_interface --ethernet 2
|
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"
|
doc_multi_interface="Multiple links of different types to the same neighbour"
|
||||||
test_multi_interface() {
|
test_multi_interface() {
|
||||||
|
simulator_command up "wlan0" "eth0"
|
||||||
set_instance +A
|
set_instance +A
|
||||||
wait_until has_link --interface "dummy2.*" $SIDB
|
wait_until has_link --interface "dummy2.*" $SIDB
|
||||||
set_instance +B
|
set_instance +B
|
||||||
wait_until has_link --interface "dummy2.*" $SIDA
|
wait_until has_link --interface "dummy2.*" $SIDA
|
||||||
set_instance +A
|
set_instance +A
|
||||||
executeOk_servald config set interfaces.2.exclude 1
|
simulator_command down "eth0"
|
||||||
wait_until has_link --interface "dummy1.*" $SIDB
|
wait_until has_link --interface "dummy1.*" $SIDB
|
||||||
set_instance +B
|
set_instance +B
|
||||||
wait_until has_link --interface "dummy1.*" $SIDA
|
wait_until has_link --interface "dummy1.*" $SIDA
|
||||||
set_instance +A
|
set_instance +A
|
||||||
executeOk_servald config del interfaces.2.exclude
|
simulator_command up "eth0"
|
||||||
wait_until has_link --interface "dummy2.*" $SIDB
|
wait_until has_link --interface "dummy2.*" $SIDB
|
||||||
set_instance +B
|
set_instance +B
|
||||||
wait_until has_link --interface "dummy2.*" $SIDA
|
wait_until has_link --interface "dummy2.*" $SIDA
|
||||||
}
|
}
|
||||||
|
finally_multi_interface() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
doc_ping_unreliable_1hop="Ping over a 1-hop unreliable link"
|
doc_ping_unreliable_1hop="Ping over a 1-hop unreliable link"
|
||||||
setup_ping_unreliable_1hop() {
|
setup_ping_unreliable_1hop() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B create_single_identity
|
foreach_instance +A +B create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --file 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +A +B \
|
start_simulator
|
||||||
executeOk_servald config \
|
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||||
set interfaces.1.drop_packets 40
|
simulator_command set "net" "drop_packets" "40"
|
||||||
foreach_instance +A +B start_servald_server
|
foreach_instance +A +B start_servald_server
|
||||||
}
|
}
|
||||||
test_ping_unreliable_1hop() {
|
test_ping_unreliable_1hop() {
|
||||||
wait_until path_exists +A +B
|
simulator_command up "net"
|
||||||
wait_until path_exists +B +A
|
wait_until --timeout=10 path_exists +A +B
|
||||||
|
wait_until --timeout=5 path_exists +B +A
|
||||||
set_instance +A
|
set_instance +A
|
||||||
executeOk_servald mdp ping --interval=0.100 --timeout=3 --wait-for-duplicates $SIDB 100
|
executeOk_servald mdp ping --interval=0.100 --timeout=3 --wait-for-duplicates $SIDB 100
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
@ -602,23 +653,26 @@ test_ping_unreliable_1hop() {
|
|||||||
assert [ "$received" -ge 98 ]
|
assert [ "$received" -ge 98 ]
|
||||||
assert [ "$duplicates" -le 2 ]
|
assert [ "$duplicates" -le 2 ]
|
||||||
}
|
}
|
||||||
|
finally_ping_unreliable_1hop() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
doc_ping_unreliable_2hop="Ping over a 2-hop unreliable link"
|
doc_ping_unreliable_2hop="Ping over a 2-hop unreliable link"
|
||||||
setup_ping_unreliable_2hop() {
|
setup_ping_unreliable_2hop() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B +C create_single_identity
|
foreach_instance +A +B +C create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --file 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +A +B \
|
foreach_instance +B +C add_servald_interface 2
|
||||||
executeOk_servald config \
|
start_simulator
|
||||||
set interfaces.1.drop_packets 40
|
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||||
foreach_instance +B +C add_servald_interface --file 2
|
simulator_command set "net1" "drop_packets" "40"
|
||||||
foreach_instance +B +C \
|
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||||
executeOk_servald config \
|
simulator_command set "net2" "drop_packets" "40"
|
||||||
set interfaces.2.drop_packets 40
|
|
||||||
foreach_instance +A +B +C start_servald_server
|
foreach_instance +A +B +C start_servald_server
|
||||||
}
|
}
|
||||||
test_ping_unreliable_2hop() {
|
test_ping_unreliable_2hop() {
|
||||||
|
simulator_command up "net1" "net2"
|
||||||
wait_until path_exists +A +B +C
|
wait_until path_exists +A +B +C
|
||||||
wait_until path_exists +C +B +A
|
wait_until path_exists +C +B +A
|
||||||
set_instance +A
|
set_instance +A
|
||||||
@ -629,49 +683,79 @@ test_ping_unreliable_2hop() {
|
|||||||
assert [ "$received" -ge 98 ]
|
assert [ "$received" -ge 98 ]
|
||||||
assert [ "$duplicates" -le 5 ]
|
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"
|
doc_brping_unreliable_1hop="Broadcast ping over a 1-hop unreliable link"
|
||||||
setup_brping_unreliable_1hop() {
|
setup_brping_unreliable_1hop() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B create_single_identity
|
foreach_instance +A +B create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --file 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +A +B \
|
start_simulator
|
||||||
executeOk_servald config \
|
simulator_command create "net" "$SERVALD_VAR/dummy1/"
|
||||||
set interfaces.1.drop_packets 20
|
simulator_command set "net" "drop_packets" "20"
|
||||||
foreach_instance +A +B start_servald_server
|
foreach_instance +A +B start_servald_server
|
||||||
}
|
}
|
||||||
test_brping_unreliable_1hop() {
|
test_brping_unreliable_1hop() {
|
||||||
|
simulator_command up "net"
|
||||||
wait_until path_exists +A +B
|
wait_until path_exists +A +B
|
||||||
wait_until path_exists +B +A
|
wait_until path_exists +B +A
|
||||||
set_instance +A
|
set_instance +A
|
||||||
executeOk_servald mdp ping --interval=0.100 --timeout=2 --wait-for-duplicates broadcast 100
|
executeOk_servald mdp ping --interval=0.100 --timeout=2 --wait-for-duplicates broadcast 100
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
}
|
}
|
||||||
|
finally_brping_unreliable_1hop() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
doc_unreliable_links="Prefer a longer, better path vs an unreliable link"
|
doc_unreliable_links="Prefer a longer, better path vs an unreliable link"
|
||||||
setup_unreliable_links() {
|
setup_unreliable_links() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B +C create_single_identity
|
foreach_instance +A +B +C create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --file 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +B +C add_servald_interface --file 2
|
foreach_instance +B +C add_servald_interface 2
|
||||||
foreach_instance +A +C add_servald_interface --file 3
|
foreach_instance +A +C add_servald_interface 3
|
||||||
set_instance +A
|
start_simulator
|
||||||
executeOk_servald config \
|
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||||
set interfaces.1.drop_packets 5 \
|
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||||
set interfaces.3.drop_packets 70
|
simulator_command create "net3" "$SERVALD_VAR/dummy3/"
|
||||||
set_instance +B
|
simulator_command set "net1" "drop_packets" "5"
|
||||||
executeOk_servald config \
|
simulator_command set "net2" "drop_packets" "5"
|
||||||
set interfaces.1.drop_packets 5 \
|
simulator_command set "net3" "drop_packets" "70"
|
||||||
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 +C start_servald_server
|
foreach_instance +A +B +C start_servald_server
|
||||||
}
|
}
|
||||||
test_unreliable_links() {
|
test_unreliable_links() {
|
||||||
|
simulator_command up "net1" "net2" "net3"
|
||||||
wait_until path_exists +A +B +C
|
wait_until path_exists +A +B +C
|
||||||
wait_until path_exists +C +B +A
|
wait_until path_exists +C +B +A
|
||||||
set_instance +A
|
set_instance +A
|
||||||
@ -685,43 +769,40 @@ test_unreliable_links() {
|
|||||||
wait_until path_exists +A +B +C
|
wait_until path_exists +A +B +C
|
||||||
wait_until path_exists +C +B +A
|
wait_until path_exists +C +B +A
|
||||||
}
|
}
|
||||||
|
finally_unreliable_links() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
doc_unreliable_links2="Choose the best multihop path with some unreliable links"
|
doc_unreliable_links2="Choose the best multihop path with some unreliable links"
|
||||||
setup_unreliable_links2() {
|
setup_unreliable_links2() {
|
||||||
setup_servald
|
setup_servald
|
||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
foreach_instance +A +B +C +D create_single_identity
|
foreach_instance +A +B +C +D create_single_identity
|
||||||
foreach_instance +A +B add_servald_interface --file 1
|
foreach_instance +A +B add_servald_interface 1
|
||||||
foreach_instance +A +C add_servald_interface --file 2
|
foreach_instance +A +C add_servald_interface 2
|
||||||
foreach_instance +A +D add_servald_interface --file 3
|
foreach_instance +A +D add_servald_interface 3
|
||||||
foreach_instance +B +C add_servald_interface --file 4
|
foreach_instance +B +C add_servald_interface 4
|
||||||
foreach_instance +B +D add_servald_interface --file 5
|
foreach_instance +B +D add_servald_interface 5
|
||||||
foreach_instance +C +D add_servald_interface --file 6
|
foreach_instance +C +D add_servald_interface 6
|
||||||
set_instance +A
|
start_simulator
|
||||||
executeOk_servald config \
|
simulator_command create "net1" "$SERVALD_VAR/dummy1/"
|
||||||
set interfaces.1.drop_packets 5 \
|
simulator_command create "net2" "$SERVALD_VAR/dummy2/"
|
||||||
set interfaces.2.drop_packets 40 \
|
simulator_command create "net3" "$SERVALD_VAR/dummy3/"
|
||||||
set interfaces.3.drop_packets 90
|
simulator_command create "net4" "$SERVALD_VAR/dummy4/"
|
||||||
set_instance +B
|
simulator_command create "net5" "$SERVALD_VAR/dummy5/"
|
||||||
executeOk_servald config \
|
simulator_command create "net6" "$SERVALD_VAR/dummy6/"
|
||||||
set interfaces.1.drop_packets 5 \
|
simulator_command set "net1" "drop_packets" "5"
|
||||||
set interfaces.4.drop_packets 5 \
|
simulator_command set "net2" "drop_packets" "60"
|
||||||
set interfaces.5.drop_packets 40
|
simulator_command set "net3" "drop_packets" "90"
|
||||||
set_instance +C
|
simulator_command set "net4" "drop_packets" "5"
|
||||||
executeOk_servald config \
|
simulator_command set "net5" "drop_packets" "60"
|
||||||
set interfaces.2.drop_packets 40 \
|
simulator_command set "net6" "drop_packets" "5"
|
||||||
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 +C +D start_servald_server
|
foreach_instance +A +B +C +D start_servald_server
|
||||||
}
|
}
|
||||||
test_unreliable_links2() {
|
test_unreliable_links2() {
|
||||||
wait_until path_exists +A +B +C +D
|
simulator_command up "net1" "net2" "net3" "net4" "net5" "net6"
|
||||||
wait_until path_exists +D +C +B +A
|
wait_until --timeout=20 path_exists +A +B +C +D
|
||||||
|
wait_until --timeout=20 path_exists +D +C +B +A
|
||||||
set_instance +A
|
set_instance +A
|
||||||
executeOk_servald mdp ping --interval=0.100 --timeout=3 --wait-for-duplicates $SIDD 100
|
executeOk_servald mdp ping --interval=0.100 --timeout=3 --wait-for-duplicates $SIDD 100
|
||||||
tfw_cat --stdout --stderr
|
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 +A +B +C +D
|
||||||
wait_until --timeout=20 path_exists +D +C +B +A
|
wait_until --timeout=20 path_exists +D +C +B +A
|
||||||
}
|
}
|
||||||
|
finally_unreliable_links2() {
|
||||||
|
simulator_quit
|
||||||
|
}
|
||||||
|
|
||||||
setup_circle() {
|
setup_circle() {
|
||||||
setup_servald
|
setup_servald
|
||||||
|
Loading…
Reference in New Issue
Block a user