1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

Merge branch 'master' of github.com:RWTH-ACS/S2SS

Conflicts:
	server/Makefile
This commit is contained in:
Steffen Vogel 2015-03-31 13:29:57 +02:00
commit b657d795d6
56 changed files with 716 additions and 430 deletions

View file

@ -1030,7 +1030,7 @@ HTML_OUTPUT = html
# The default value is: .html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FILE_EXTENSION = .xhtml
HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
# each generated HTML page. If the tag is left blank doxygen will generate a

View file

@ -19,11 +19,6 @@ Date: Mid 2014 - End 2015
UDP protocol over the ML507 Ethernet interface.
This is working!
- ml507_ppc440_plbv46_pcie
An unsuccessful attempt to use the RTDS PLB interface used by "ml507_gtfpga_ppc440_udp"
with the Xilinx PLBv46_PCIe bridge to allow direct PCIe access to the RTDS registers.
This does NOT work!
- opal
Contains the implementation of an asynchronous process block for RT-LAB.
This block allows exchanging messages with an S2SS server over UDP/TCP.

View file

@ -0,0 +1,7 @@
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=1
GRUB_DISABLE_SUBMENU=false
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="isolcpus=6,7 selinux=0 audit=0"
GRUB_DISABLE_RECOVERY=true

View file

@ -0,0 +1 @@
unknown-s2ss

10
contrib/liveusb/etc/hosts Normal file
View file

@ -0,0 +1,10 @@
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
# Orchestrator
# ACS hosts
134.130.169.31 acs-s2ss
134.130.169.32 acs-gtfpga
137.226.160.69 acs-opal
137.226.160.115 acs-workstation

View file

@ -0,0 +1,15 @@
[Unit]
Description=The mongoose Web server
After=network.target
[Service]
Type=simple
User=nobody
Group=nobody
Restart=always
ExecStart=/usr/bin/mongoose -p 80 -r /var/www/
StandardOutput=syslog
SyslogIdentifier=mongoose
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1 @@
latency-performance

View file

@ -0,0 +1,9 @@
#!/bin/bash
rpm -Uvh http://ccrma.stanford.edu/planetccrma/mirror/fedora/linux/planetccrma/20/i386/planetccrma-repo-1.1-3.fc20.ccrma.noarch.rpm
yum update
yum install planetccrma-core
source update_boot.sh

View file

@ -2,15 +2,14 @@
set -e
RECEIPENTS="stvogel@eonerc.rwth-aachen.de,mstevic@eonerc.rwth-aachen.de"
FROM="Simulator2Simulator Server <acs@0l.de>"
RECIPIENTS="stvogel@eonerc.rwth-aachen.de,mstevic@eonerc.rwth-aachen.de"
SERVER=tux.0l.de
USER=acs
PORT=$(shuf -i 60000-65535 -n 1)
IP=$(curl -s http://ifconfig.me)
IP=$(curl -s http://canihazip.com/s)
# check if system has net connectivity. otherwise die...
ssh -q -o ConnectTimeout=2 $USER@$SERVER
@ -21,7 +20,11 @@ ssh -f -N -L 25:localhost:25 $USER@$SERVER
ssh -f -N -R $PORT:localhost:22 $USER@$SERVER
# send mail with notification about new node
mail -s "New S2SS node alive: $IP ($HOSTNAME)" -a "From: $FROM" "$RECEIPENTS" <<EOF
sendmail "$RECIPIENTS" <<EOF
Subject: New S2SS node alive: $IP ($HOSTNAME)
From: Simulator2Simulator Server <acs@0l.de>
To: $RECIPIENTS
There's a new host with the S2SS LiveUSB Image running:
Reverse SSH tunnel port: $PORT

24
contrib/liveusb/update_boot.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/sh
# author: Christian Berendt <mail@cberendt.net>
set -x
for kernel in $(find /boot/vmlinuz*); do
version=$(basename $kernel)
version=${version#*-}
if [ ! -e /boot/initramfs-$version.img ]; then
sudo /usr/bin/dracut /boot/initramfs-$version.img $version
fi
done
for image in $(find /boot/initramfs*); do
version=${image%.img}
version=${version#*initramfs-}
if [ ! -e /boot/vmlinuz-$version ]; then
sudo rm $image
fi
done
/usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg

12
contrib/update_docs.sh Executable file
View file

@ -0,0 +1,12 @@
#/bin/bash
cd $( cd "$( dirname "$0" )/.." && pwd )
LASTREV=$(git rev-parse HEAD)
git pull --all
NEWREV=$(git rev-parse HEAD)
if [ "$LASTREV" != "$NEWREV" ]; then
echo "There's a new version. Running doxygen"
doxygen
fi

View file

@ -1,7 +1,7 @@
TARGETS = server send random receive test
# Common dependencies for all binaries
OBJS = if.o utils.o msg.o node.o cfg.o tc.o hooks.o list.o path.o hist.o socket.o file.o
OBJS = socket.o if.o utils.o msg.o node.o cfg.o tc.o hooks.o list.o path.o hist.o log.o socket.o file.o
VPATH = src
@ -10,11 +10,15 @@ V ?= 2
# Compiler and linker flags
LDLIBS = -pthread -lrt -lm -lconfig
CFLAGS = -std=c99 -Iinclude/ -MMD -Wall
CFLAGS = -std=gnu99 -Iinclude/ -MMD -Wall
CFLAGS += -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -DV=$(V)
CFLAGS += -D__GIT_REV__='"-$(shell git rev-parse --short HEAD)"'
# Conditional flags
# Add git commit hash
ifneq (,$(shell which git))
CFLAGS += -D_GIT_REV='"$(shell git rev-parse --short HEAD)"'
endif
# Conditional debug flags
ifdef DEBUG
CFLAGS += -O0 -g
else
@ -22,13 +26,13 @@ else
endif
# Enable OPAL-RT Asynchronous Process support
#OPALDIR = /usr/opalrt/common
OPALDIR = ../opal
OPALDIR = /usr/opalrt/common
#OPALDIR = ../opal
ifneq (,$(wildcard $(OPALDIR)/include_target/AsyncApi.h))
CFLAGS += -m32 -DENABLE_OPAL_ASYNC -I$(OPALDIR)/include_target
LDFLAGS += -m32
LDLIBS += $(addprefix $(OPALDIR)/lib/redhawk/, libOpalAsyncApiCore.a libOpalCore.a libOpalUtils.a libirc.a)
COMMON += opal.o
OBJS += opal.o
endif
.PHONY: all clean

View file

@ -0,0 +1,28 @@
# Example configuration file for the s2ss server
affinity = 0x01; # Mask of cores the server should run on
priority = 99; # Scheduler priority for the server
debug = 5; # The level of verbosity for debug messages
stats = 1; # The interval in seconds for path statistics
nodes = {
opal = {
type = "opal";
send_id = 1;
recv_id = 1;
},
acs-s2ss = {
type = "udp";
local = "*:12000";
remote = "134.130.169.31:12000";
}
};
paths = (
{
in = "opal";
out = "acs-s2ss";
reverse = true;
hook = "print";
}
);

View file

@ -51,7 +51,7 @@ struct settings {
* @retval <0 Error. Something went wrong.
*/
int config_parse(const char *filename, config_t *cfg, struct settings *set,
struct node **nodes, struct path **paths);
struct list *nodes, struct list *paths);
/** Parse the global section of a configuration file.
*
@ -71,9 +71,9 @@ int config_parse_global(config_setting_t *cfg, struct settings *set);
* @retval <0 Error. Something went wrong.
*/
int config_parse_path(config_setting_t *cfg,
struct path **paths, struct node **nodes);
struct list *paths, struct list *nodes);
int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct node **all);
int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct list *all);
int config_parse_hooks(config_setting_t *cfg, struct list *hooks);
@ -85,7 +85,7 @@ int config_parse_hooks(config_setting_t *cfg, struct list *hooks);
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int config_parse_node(config_setting_t *cfg, struct node **nodes);
int config_parse_node(config_setting_t *cfg, struct list *nodes);
/** Parse node connection details for OPAL type
*

View file

@ -11,11 +11,15 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#ifndef _GIT_REV
#define _GIT_REV "nogit"
#endif
/** The version number of the s2ss server */
#define VERSION "v0.4" __GIT_REV__
#define VERSION "v0.4-" _GIT_REV
/** Maximum number of double values in a struct msg */
#define MAX_VALUES 64
#define MAX_VALUES 16
/** Socket priority */
#define SOCKET_PRIO 7

View file

@ -44,10 +44,10 @@ struct hist {
};
/** Initialize struct hist with supplied values and allocate memory for buckets. */
void hist_init(struct hist *h, double start, double end, double resolution);
void hist_create(struct hist *h, double start, double end, double resolution);
/** Free the dynamically allocated memory. */
void hist_free(struct hist *h);
void hist_destroy(struct hist *h);
/** Reset all counters and values back to zero. */
void hist_reset(struct hist *h);
@ -76,4 +76,4 @@ void hist_dump(struct hist *h, char *buf, int len);
/** Prints Matlab struct containing all infos to file. */
void hist_matlab(struct hist *h, FILE *f);
#endif /* _HIST_H_ */
#endif /* _HIST_H_ */

View file

@ -14,9 +14,15 @@
#include <sys/types.h>
#include <net/if.h>
#include "list.h"
#define IF_NAME_MAX IFNAMSIZ /**< Maximum length of an interface name */
#define IF_IRQ_MAX 3 /**< Maxmimal number of IRQs of an interface */
#ifndef SO_MARK
#define SO_MARK 36 /**< Workaround: add missing constant for OPAL-RT Redhawk target */
#endif
struct socket;
/** Interface data structure */
@ -31,9 +37,7 @@ struct interface {
char irqs[IF_IRQ_MAX];
/** Linked list of associated sockets */
struct socket *sockets;
/** Linked list pointer */
struct interface *next;
struct list sockets;
};
/** Add a new interface to the global list and lookup name, irqs...
@ -44,6 +48,13 @@ struct interface {
*/
struct interface * if_create(int index);
/** Destroy interface by freeing dynamically allocated memory.
*
* @param i A pointer to the interface structure.
*/
void if_destroy(struct interface *i);
/** Start interface.
*
* This setups traffic controls queue discs, network emulation and
@ -102,7 +113,7 @@ int if_getirqs(struct interface *i);
*/
int if_setaffinity(struct interface *i, int affinity);
/** Search the list of interfaces for a given index.
/** Search the global list of interfaces for a given index.
*
* @param index The interface index to search for
* @param interfaces A linked list of all interfaces

View file

@ -40,10 +40,17 @@ struct interface;
#define list_last(list) ((list)->head)
#define list_length(list) ((list)->count)
/** Callback to destroy list elements.
*
* @param data A pointer to the data which should be freed.
*/
typedef void (*dtor_cb_t)(void *data);
struct list {
struct list_elm *head, *tail;
int count;
dtor_cb_t destructor;
pthread_mutex_t lock;
};
@ -53,13 +60,14 @@ struct list_elm {
struct node *node;
struct path *path;
struct interface *interface;
struct socket *socket;
hook_cb_t hook;
};
} /* anonymous */;
struct list_elm *prev, *next;
};
void list_init(struct list *l);
void list_init(struct list *l, dtor_cb_t dtor);
void list_destroy(struct list *l);
@ -67,4 +75,4 @@ void list_push(struct list *l, void *p);
struct list_elm * list_search(struct list *l, int (*cmp)(void *));
#endif /* _LIST_H_ */
#endif /* _LIST_H_ */

77
server/include/log.h Normal file
View file

@ -0,0 +1,77 @@
/** Logging and debugging routines
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015, Institute for Automation of Complex Power Systems, EONERC
* @file
*/
#ifndef _LOG_H_
#define _LOG_H_
#ifdef __GNUC__
#define INDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_indent(1);
#else
#define INDENT ;
#endif
/** Global debug level used by the debug() macro.
* It defaults to V (defined by the Makefile) and can be
* overwritten by the 'debug' setting in the config file.
*/
extern int _debug;
/** The log level which is passed as first argument to print() */
enum log_level {
DEBUG,
INFO,
WARN,
ERROR
};
int log_indent(int levels);
void log_outdent(int *);
/** Reset the wallclock of debugging outputs */
void log_reset();
/** Logs variadic messages to stdout.
*
* @param lvl The log level
* @param fmt The format string (printf alike)
*/
void log_print(enum log_level lvl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
/** Printf alike debug message with level. */
#define debug(lvl, msg, ...) do if (lvl <= _debug) log_print(DEBUG, msg, ##__VA_ARGS__); while (0)
/** Printf alike info message. */
#define info(msg, ...) do log_print(INFO, msg, ##__VA_ARGS__); while (0)
/** Printf alike warning message. */
#define warn(msg, ...) do log_print(WARN, msg, ##__VA_ARGS__); while (0)
/** Print error and exit. */
#define error(msg, ...) do { \
log_print(ERROR, msg, ##__VA_ARGS__); \
die(); \
} while (0)
/** Print error and strerror(errno). */
#define serror(msg, ...) do { \
log_print(ERROR, msg ": %s", ##__VA_ARGS__, strerror(errno)); \
die(); \
} while (0)
/** Print configuration error and exit. */
#define cerror(c, msg, ...) do { \
log_print(ERROR, msg " in %s:%u", ##__VA_ARGS__, \
(config_setting_source_file(c)) ? \
config_setting_source_file(c) : "(stdio)", \
config_setting_source_line(c)); \
die(); \
} while (0)
#endif /* _LOG_H_ */

View file

@ -14,7 +14,7 @@
#define _BSD_SOURCE 1
#include <endian.h>
#elif defined(__PPC__) /* Xilinx toolchain */
#include <lwip/arch.h>
#include <lwip/arch.h>
#endif
#include "config.h"
@ -30,8 +30,8 @@
#define MSG_TYPE_START 1 /**< Message marks the beginning of a new simulation case */
#define MSG_TYPE_STOP 2 /**< Message marks the end of a simulation case */
#define MSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */
#define MSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */
#define MSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */
#define MSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */
#if BYTE_ORDER == LITTLE_ENDIAN
#define MSG_ENDIAN_HOST MSG_ENDIAN_LITTLE

View file

@ -20,6 +20,7 @@
#include "msg.h"
#include "tc.h"
#include "list.h"
/** Static node initialization */
#define NODE_INIT(n) { \
@ -83,9 +84,6 @@ struct node
/** A pointer to the libconfig object which instantiated this node */
config_setting_t *cfg;
/** Linked list pointer */
struct node *next;
};
/** Connect and bind the UDP socket of this node.
@ -131,12 +129,21 @@ struct node_vtable const * node_lookup_vtable(const char *str);
* @param nodes A linked list of all nodes
* @return A pointer to the node or NULL if not found
*/
struct node* node_lookup_name(const char *str, struct node *nodes);
struct node * node_lookup_name(const char *str, struct list *nodes);
/** Reverse local and remote socket address.
* This is usefull for the helper programs: send, receive, test
* because they usually use the same configuration file as the
* server and therefore the direction needs to be swapped. */
int node_reverse(struct node *n);
void node_reverse(struct node *n);
/** Create a node by allocating dynamic memory. */
struct node * node_create();
/** Destroy node by freeing dynamically allocated memory.
*
* @param i A pointer to the interface structure.
*/
void node_destroy(struct node *n);
#endif /* _NODE_H_ */

View file

@ -39,14 +39,13 @@ struct path
double rate;
/** A pointer to the last received message */
struct msg *last;
struct msg *current;
/** A pointer to the previously received message */
struct msg *previous;
/** Counter for received messages according to their sequence no displacement */
struct hist histogram;
/** Last known message number */
unsigned int sequence;
/** Counter for sent messages to all outgoing nodes */
unsigned int sent;
/** Counter for received messages from all incoming nodes */
@ -58,22 +57,30 @@ struct path
/** Counter for dropped messages due to reordering */
unsigned int dropped;
/** A timer used for fixed rate transmission. */
timer_t timer;
/** The thread id for this path */
pthread_t recv_tid;
/** A second thread id for fixed rate sending thread */
pthread_t sent_tid;
/** A pointer to the libconfig object which instantiated this path */
config_setting_t *cfg;
/** Linked list pointer */
struct path *next;
};
/** Create a path by allocating dynamic memory. */
struct path * path_create();
/** Destroy path by freeing dynamically allocated memory.
*
* @param i A pointer to the path structure.
*/
void path_destroy(struct path *p);
/** Start a path.
*
* Start a new pthread for receiving/sending messages over this path.
*
* @param p A pointer to the path struct
* @param p A pointer to the path structure.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
@ -81,7 +88,7 @@ int path_start(struct path *p);
/** Stop a path.
*
* @param p A pointer to the path struct
* @param p A pointer to the path structure.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
@ -89,12 +96,18 @@ int path_stop(struct path *p);
/** Show some basic statistics for a path.
*
* @param p A pointer to the path struct
* @param p A pointer to the path structure.
*/
void path_stats(struct path *p);
void path_print_stats(struct path *p);
/** Fills the provided buffer with a string representation of the path.
*
* Format: source => [ dest1 dest2 dest3 ]
*
* @param p A pointer to the path structure.
* @param buf A pointer to the buffer which should be filled.
* @param len The length of buf in bytes.
*/
int path_print(struct path *p, char *buf, int len);
int path_destroy(struct path *p);
#endif /* _PATH_H_ */

View file

@ -13,6 +13,9 @@
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <sys/types.h>
#include "log.h"
#ifdef __GNUC__
#define EXPECT(x, v) __builtin_expect(x, v)
@ -21,58 +24,64 @@
#endif
/* Some color escape codes for pretty log messages */
#define GRY(str) "\e[30m" str "\e[0m" /**< Print str in gray */
#define RED(str) "\e[31m" str "\e[0m" /**< Print str in red */
#define GRN(str) "\e[32m" str "\e[0m" /**< Print str in green */
#define YEL(str) "\e[33m" str "\e[0m" /**< Print str in yellow */
#define BLU(str) "\e[34m" str "\e[0m" /**< Print str in blue */
#define MAG(str) "\e[35m" str "\e[0m" /**< Print str in magenta */
#define CYN(str) "\e[36m" str "\e[0m" /**< Print str in cyan */
#define WHT(str) "\e[37m" str "\e[0m" /**< Print str in white */
#define BLD(str) "\e[1m" str "\e[0m" /**< Print str in bold */
#ifndef ENABLE_OPAL_ASYNC
#define GRY(str) "\e[30m" str "\e[0m" /**< Print str in gray */
#define RED(str) "\e[31m" str "\e[0m" /**< Print str in red */
#define GRN(str) "\e[32m" str "\e[0m" /**< Print str in green */
#define YEL(str) "\e[33m" str "\e[0m" /**< Print str in yellow */
#define BLU(str) "\e[34m" str "\e[0m" /**< Print str in blue */
#define MAG(str) "\e[35m" str "\e[0m" /**< Print str in magenta */
#define CYN(str) "\e[36m" str "\e[0m" /**< Print str in cyan */
#define WHT(str) "\e[37m" str "\e[0m" /**< Print str in white */
#define BLD(str) "\e[1m" str "\e[0m" /**< Print str in bold */
#define GFX(chr) "\e(0" chr "\e(B"
#define UP(n) "\e[" ## n ## "A"
#define DOWN(n) "\e[" ## n ## "B"
#define RIGHT(n) "\e[" ## n ## "C"
#define LEFT(n) "\e[" ## n ## "D"
#define GFX(chr) "\e(0" chr "\e(B"
#define UP(n) "\e[" ## n ## "A"
#define DOWN(n) "\e[" ## n ## "B"
#define RIGHT(n) "\e[" ## n ## "C"
#define LEFT(n) "\e[" ## n ## "D"
#else
#define GRY(str) str
#define RED(str) str
#define GRN(str) str
#define YEL(str) str
#define BLU(str) str
#define MAG(str) str
#define CYN(str) str
#define WHT(str) str
#define BLD(str) str
#define ARRAY_LEN(a) ( sizeof a / sizeof a[0] )
#define GFX(chr) " "
#define UP(n) ""
#define DOWN(n) ""
#define RIGHT(n) ""
#define LEFT(n) ""
#endif
/* CPP stringification */
#define XSTR(x) STR(x)
#define STR(x) #x
/** Calculate the number of elements in an array. */
#define ARRAY_LEN(a) ( sizeof (a) / sizeof (a)[0] )
/** Swap two values by using a local third one. */
#define SWAP(a, b) do { \
__typeof__(a) tmp = a; \
a = b; \
b = tmp; \
} while(0)
/** The log level which is passed as first argument to print() */
enum log_level { DEBUG, INFO, WARN, ERROR };
/* Forward declarations */
struct settings;
struct timespec;
/* These global variables allow changing the output style and verbosity */
extern int _debug;
extern int _indent;
void outdent(int *old);
#ifdef __GNUC__
#define INDENT int __attribute__ ((__cleanup__(outdent), unused)) _old_indent = _indent++;
#else
#define INDENT ;
#endif
/** Reset the wallclock of debugging outputs */
void epoch_reset();
/** Logs variadic messages to stdout.
*
* @param lvl The log level
* @param fmt The format string (printf alike)
/** The main thread id.
* This is used to notify the main thread about
* the program termination.
* See error() macros.
*/
void print(enum log_level lvl, const char *fmt, ...);
extern pthread_t _mtid;
/** Safely append a format string to an existing string.
*
@ -99,14 +108,11 @@ double timespec_delta(struct timespec *start, struct timespec *end);
/** Get period as timespec from rate */
struct timespec timespec_rate(double rate);
/** A system(2) emulator with popen/pclose(2) and proper output handling */
/** A system(2) emulator with popen / pclose(2) and proper output handling */
int system2(const char* cmd, ...);
/** Append an element to a single linked list */
#define list_add(list, elm) do { \
elm->next = list; \
list = elm; \
} while (0)
/** Call quit() in the main thread. */
void die();
/** Check assertion and exit if failed. */
#define assert(exp) do { \
@ -116,42 +122,5 @@ int system2(const char* cmd, ...);
exit(EXIT_FAILURE); \
} } while (0)
/** Printf alike debug message with level. */
#define debug(lvl, msg, ...) do { \
if (lvl <= _debug) \
print(DEBUG, msg, ##__VA_ARGS__); \
} while (0)
/** Printf alike info message. */
#define info(msg, ...) do { \
print(INFO, msg, ##__VA_ARGS__); \
} while (0)
/** Printf alike warning message. */
#define warn(msg, ...) do { \
print(WARN, msg, ##__VA_ARGS__); \
} while (0)
/** Print error and exit. */
#define error(msg, ...) do { \
print(ERROR, msg, ##__VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
/** Print error and strerror(errno). */
#define serror(msg, ...) do { \
print(ERROR, msg ": %s", ##__VA_ARGS__, \
strerror(errno)); \
exit(EXIT_FAILURE); \
} while (0)
/** Print configuration error and exit. */
#define cerror(c, msg, ...) do { \
print(ERROR, msg " in %s:%u", ##__VA_ARGS__, \
(config_setting_source_file(c)) ? \
config_setting_source_file(c) : "(stdio)", \
config_setting_source_line(c)); \
exit(EXIT_FAILURE); \
} while (0)
#endif /* _UTILS_H_ */

View file

@ -20,26 +20,25 @@
#include "socket.h"
#include "gtfpga.h"
#ifdef ENABLE_OPAL_ASYNC
#include "opal.h"
#endif
int config_parse(const char *filename, config_t *cfg, struct settings *set,
struct node **nodes, struct path **paths)
struct list *nodes, struct list *paths)
{
config_set_auto_convert(cfg, 1);
FILE *file = (strcmp("-", filename)) ? fopen(filename, "r") : stdin;
if (!file)
error("Failed to open configuration file: %s", filename);
int ret = strcmp("-", filename) ? config_read_file(cfg, filename)
: config_read(cfg, stdin);
if (!config_read(cfg, file))
if (ret != CONFIG_TRUE)
error("Failed to parse configuration: %s in %s:%d",
config_error_text(cfg), filename,
config_error_text(cfg),
config_error_file(cfg) ? config_error_file(cfg) : filename,
config_error_line(cfg)
);
if (file != stdin)
fclose(file);
config_setting_t *cfg_root = config_root_setting(cfg);
/* Parse global settings */
@ -74,7 +73,7 @@ int config_parse(const char *filename, config_t *cfg, struct settings *set,
}
}
return CONFIG_TRUE;
return 0;
}
int config_parse_global(config_setting_t *cfg, struct settings *set)
@ -88,11 +87,11 @@ int config_parse_global(config_setting_t *cfg, struct settings *set)
set->cfg = cfg;
return CONFIG_TRUE;
return 0;
}
int config_parse_path(config_setting_t *cfg,
struct path **paths, struct node **nodes)
struct list *paths, struct list *nodes)
{
const char *in;
int enabled = 1;
@ -106,9 +105,9 @@ int config_parse_path(config_setting_t *cfg,
cerror(cfg, "Invalid input node for path");
in = config_setting_get_string(cfg_in);
p->in = node_lookup_name(in, *nodes);
p->in = node_lookup_name(in, nodes);
if (!p->in)
cerror(cfg_in, "Invalid input node '%s", in);
cerror(cfg_in, "Invalid input node '%s'", in);
/* Output node(s) */
struct config_setting_t *cfg_out = config_setting_get_member(cfg, "out");
@ -141,7 +140,7 @@ int config_parse_path(config_setting_t *cfg,
warn("Using first destination '%s' as source for reverse path. "
"Ignoring remaining nodes", p->out->name);
struct path *r = alloc(sizeof(struct path));
struct path *r = path_create();
r->in = p->out; /* Swap in/out */
r->out = p->in;
@ -151,10 +150,10 @@ int config_parse_path(config_setting_t *cfg,
r->in->refcnt++;
r->out->refcnt++;
list_add(*paths, r);
list_push(paths, r);
}
list_add(*paths, p);
list_push(paths, p);
}
else {
char buf[33];
@ -167,14 +166,14 @@ int config_parse_path(config_setting_t *cfg,
return 0;
}
int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct node **all) {
int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct list *all) {
const char *str;
struct node *node;
switch (config_setting_type(cfg)) {
case CONFIG_TYPE_STRING:
str = config_setting_get_string(cfg);
node = node_lookup_name(str, *all);
node = node_lookup_name(str, all);
if (!node)
cerror(cfg, "Invalid outgoing node '%s'", str);
@ -184,7 +183,7 @@ int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct node
case CONFIG_TYPE_ARRAY:
for (int i=0; i<config_setting_length(cfg); i++) {
str = config_setting_get_string_elem(cfg, i);
node = node_lookup_name(str, *all);
node = node_lookup_name(str, all);
if (!node)
cerror(config_setting_get_elem(cfg, i), "Invalid outgoing node '%s'", str);
@ -231,12 +230,12 @@ int config_parse_hooks(config_setting_t *cfg, struct list *hooks) {
return 0;
}
int config_parse_node(config_setting_t *cfg, struct node **nodes)
int config_parse_node(config_setting_t *cfg, struct list *nodes)
{
const char *type;
int ret;
struct node *n = alloc(sizeof(struct node));
struct node *n = node_create();
/* Required settings */
n->cfg = cfg;
@ -244,42 +243,35 @@ int config_parse_node(config_setting_t *cfg, struct node **nodes)
if (!n->name)
cerror(cfg, "Missing node name");
if (config_setting_lookup_string(cfg, "type", &type)) {
n->vt = node_lookup_vtable(type);
if (!n->vt)
cerror(cfg, "Invalid type for node '%s'", n->name);
if (!n->vt->parse)
cerror(cfg, "Node type '%s' is not allowed in the config", type);
}
else
n->vt = node_lookup_vtable("udp");
if (!config_setting_lookup_string(cfg, "type", &type))
cerror(cfg, "Missing node name");
n->vt = node_lookup_vtable(type);
if (!n->vt)
cerror(cfg, "Invalid type for node '%s'", n->name);
ret = n->vt->parse(cfg, n);
list_add(*nodes, n);
if (!ret)
list_push(nodes, n);
return ret;
}
#ifdef ENABLE_OPAL_ASYNC
/** @todo: Remove this global variable. */
extern struct opal_global *og;
int config_parse_opal(config_setting_t *cfg, struct node *n)
{
if (!og) {
warn("Skipping this node, because this server is not running as an OPAL Async process!");
warn("Skipping node '%s', because this server is not running as an OPAL Async process!", n->name);
return -1;
}
struct opal *o = (struct opal *) malloc(sizeof(struct opal));
if (!o)
error("Failed to allocate memory for opal settings");
memset(o, 0, sizeof(struct opal));
struct opal *o = alloc(sizeof(struct opal));
config_setting_lookup_int(cfg, "send_id", &o->send_id);
config_setting_lookup_int(cfg, "recv_id", &o->send_id);
config_setting_lookup_int(cfg, "recv_id", &o->recv_id);
config_setting_lookup_bool(cfg, "reply", &o->reply);
/* Search for valid send and recv ids */
@ -292,7 +284,7 @@ int config_parse_opal(config_setting_t *cfg, struct node *n)
if (!sfound)
cerror(config_setting_get_member(cfg, "send_id"), "Invalid send_id '%u' for node '%s'", o->send_id, n->name);
if (!rfound)
cerror(config_setting_get_member(cfg, "send_id"), "Invalid send_id '%u' for node '%s'", o->send_id, n->name);
cerror(config_setting_get_member(cfg, "recv_id"), "Invalid recv_id '%u' for node '%s'", o->recv_id, n->name);
n->opal = o;
n->opal->global = og;
@ -300,12 +292,16 @@ int config_parse_opal(config_setting_t *cfg, struct node *n)
return 0;
}
#endif /* ENABLE_OPAL_ASYNC */
#ifdef ENABLE_GTFPGA
/** @todo Implement */
int config_parse_gtfpga(config_setting_t *cfg, struct node *n)
{
return 0;
}
#endif /* ENABLE_GTFPGA */
int config_parse_socket(config_setting_t *cfg, struct node *n)
{
@ -333,14 +329,14 @@ int config_parse_socket(config_setting_t *cfg, struct node *n)
/** @todo Netem settings are not usable AF_UNIX */
config_setting_t *cfg_netem = config_setting_get_member(cfg, "netem");
if (cfg_netem) {
s->netem = (struct netem *) alloc(sizeof(struct netem));
s->netem = alloc(sizeof(struct netem));
config_parse_netem(cfg_netem, s->netem);
}
n->socket = s;
return CONFIG_TRUE;
return 0;
}
int config_parse_netem(config_setting_t *cfg, struct netem *em)
@ -362,5 +358,5 @@ int config_parse_netem(config_setting_t *cfg, struct netem *em)
/** @todo Validate netem config values */
return CONFIG_TRUE;
return 0;
}

View file

@ -17,7 +17,7 @@
#define VAL(h, i) ((h)->low + (i) * (h)->resolution)
#define INDEX(h, v) round((v - (h)->low) / (h)->resolution)
void hist_init(struct hist *h, double low, double high, double resolution)
void hist_create(struct hist *h, double low, double high, double resolution)
{
h->low = low;
h->high = high;
@ -28,7 +28,7 @@ void hist_init(struct hist *h, double low, double high, double resolution)
hist_reset(h);
}
void hist_free(struct hist *h)
void hist_destroy(struct hist *h)
{
free(h->data);
}

View file

@ -71,7 +71,7 @@ int hook_log(struct msg *m, struct path *p)
if (file)
debug(5, "Opened log file for path %s: %s", pstr, fstr);
pthread_key_create(&pkey, (void (*)(void *)) fclose);
pthread_key_create(&pkey, (dtor_cb_t) fclose);
pthread_setspecific(pkey, file);
}
@ -127,8 +127,7 @@ int hook_fir(struct msg *m, struct path *p)
/* Create thread local storage for circular history buffer */
if (!history) {
history = malloc(len * sizeof(float));
history = alloc(len * sizeof(float));
pthread_key_create(&pkey, free);
pthread_setspecific(pkey, history);
}

View file

@ -22,8 +22,8 @@
#include "socket.h"
#include "utils.h"
/** Linked list of interfaces */
struct interface *interfaces;
/** Linked list of interfaces. */
struct list interfaces;
struct interface * if_create(int index) {
struct interface *i = alloc(sizeof(struct interface));
@ -31,13 +31,22 @@ struct interface * if_create(int index) {
i->index = index;
if_indextoname(index, i->name);
debug(3, "Created interface '%s'", i->name, i->index, i->refcnt);
debug(3, "Created interface '%s' (index=%u)", i->name, i->index);
list_add(interfaces, i);
list_init(&i->sockets, NULL);
list_push(&interfaces, i);
return i;
}
void if_destroy(struct interface *i)
{
/* List members are freed by their belonging nodes. */
list_destroy(&i->sockets);
free(i);
}
int if_start(struct interface *i, int affinity)
{ INDENT
if (!i->refcnt) {
@ -49,7 +58,9 @@ int if_start(struct interface *i, int affinity)
{ INDENT
int mark = 0;
for (struct socket *s = i->sockets; s; s = s->next) {
FOREACH(&i->sockets, it) {
struct socket *s = it->socket;
if (s->netem) {
s->mark = 1 + mark++;
@ -78,7 +89,7 @@ int if_start(struct interface *i, int affinity)
int if_stop(struct interface *i)
{ INDENT
info("Stopping interface '%s'", i->name);
info("Stopping interface '%s'", i->name);
{ INDENT
if_setaffinity(i, -1L);
@ -171,10 +182,9 @@ int if_setaffinity(struct interface *i, int affinity)
struct interface * if_lookup_index(int index)
{
for (struct interface *i = interfaces; i; i = i->next) {
if (i->index == index) {
return i;
}
FOREACH(&interfaces, it) {
if (it->interface->index == index)
return it->interface;
}
return NULL;

View file

@ -10,10 +10,11 @@
#include "utils.h"
#include "list.h"
void list_init(struct list *l)
void list_init(struct list *l, dtor_cb_t dtor)
{
pthread_mutex_init(&l->lock, NULL);
l->destructor = dtor;
l->count = 0;
l->head = NULL;
l->tail = NULL;
@ -26,11 +27,15 @@ void list_destroy(struct list *l)
struct list_elm *elm = l->head;
while (elm) {
struct list_elm *tmp = elm;
free(tmp);
elm = elm->next;
if (l->destructor)
l->destructor(tmp->ptr);
free(tmp);
}
pthread_mutex_unlock(&l->lock);
pthread_mutex_destroy(&l->lock);
}

75
server/src/log.c Normal file
View file

@ -0,0 +1,75 @@
/** Logging and debugging routines
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015, Institute for Automation of Complex Power Systems, EONERC
*/
#include <stdio.h>
#include <time.h>
#include "log.h"
#include "utils.h"
int _debug = V;
static struct timespec epoch;
#ifdef __GNUC__
static __thread int indent = 0;
/** Get thread-specific pointer to indent level */
int log_indent(int levels)
{
int old = indent;
indent += levels;
return old;
}
void log_outdent(int *old)
{
indent = *old;
}
#endif
void log_reset()
{
clock_gettime(CLOCK_REALTIME, &epoch);
}
void log_print(enum log_level lvl, const char *fmt, ...)
{
struct timespec ts;
char buf[512] = "";
va_list ap;
/* Timestamp */
clock_gettime(CLOCK_REALTIME, &ts);
strap(buf, sizeof(buf), "%8.3f ", timespec_delta(&epoch, &ts));
/* Severity */
switch (lvl) {
case DEBUG: strap(buf, sizeof(buf), BLD("%-5s "), GRY("Debug")); break;
case INFO: strap(buf, sizeof(buf), BLD("%-5s "), " " ); break;
case WARN: strap(buf, sizeof(buf), BLD("%-5s "), YEL(" Warn")); break;
case ERROR: strap(buf, sizeof(buf), BLD("%-5s "), RED("Error")); break;
}
/* Indention */
#ifdef __GNUC__
for (int i = 0; i < indent; i++)
strap(buf, sizeof(buf), GFX("\x78") " ");
strap(buf, sizeof(buf), GFX("\x74") " ");
#endif
/* Format String */
va_start(ap, fmt);
vstrap(buf, sizeof(buf), fmt, ap);
va_end(ap);
/* Output */
#ifdef ENABLE_OPAL_ASYNC
OpalPrint("S2SS: %s\n", buf);
#endif
fprintf(stderr, "\r%s\n", buf);
}

View file

@ -13,7 +13,9 @@
/* Node types */
#include "socket.h"
#include "gtfpga.h"
#ifdef ENABLE_OPAL_ASYNC
#include "opal.h"
#endif
#define VTABLE(type, name, fnc) { type, name, config_parse_ ## fnc, \
fnc ## _print, \
@ -35,14 +37,14 @@ static const struct node_vtable vtables[] = {
VTABLE(TCPD, "tcpd", socket)
};
/** Linked list of nodes */
struct node *nodes;
/** Linked list of nodes. */
struct list nodes;
struct node * node_lookup_name(const char *str, struct node *nodes)
struct node * node_lookup_name(const char *str, struct list *nodes)
{
for (struct node *n = nodes; n; n = n->next) {
if (!strcmp(str, n->name))
return n;
FOREACH(nodes, it) {
if (!strcmp(str, it->node->name))
return it->node;
}
return NULL;
@ -59,7 +61,7 @@ struct node_vtable const * node_lookup_vtable(const char *str)
}
int node_start(struct node *n)
{
{ INDENT
if (!n->refcnt) {
warn("Node '%s' is unused. Skipping...", n->name);
return -1;
@ -97,7 +99,7 @@ int node_start_defer(struct node *n)
}
int node_stop(struct node *n)
{
{ INDENT
int ret;
info("Stopping node '%s'", n->name);
@ -108,7 +110,7 @@ int node_stop(struct node *n)
return ret;
}
int node_reverse(struct node *n)
void node_reverse(struct node *n)
{
switch (n->vt->type) {
case IEEE_802_3:
@ -119,5 +121,24 @@ int node_reverse(struct node *n)
break;
default: { }
}
return n->vt->open == socket_open;
}
struct node * node_create()
{
return alloc(sizeof(struct node));
}
void node_destroy(struct node *n)
{
switch (n->vt->type) {
case IEEE_802_3:
case IP:
case UDP:
case TCP:
free(n->socket->netem);
default: { }
}
free(n->socket);
free(n);
}

View file

@ -22,11 +22,7 @@ int opal_init(int argc, char *argv[])
if (argc != 4)
return -1;
struct opal_global *g = (struct opal_global *) malloc(sizeof(struct opal_global));
if (!g)
error("Failed to allocate memory for global OPAL settings");
memset(g, 0, sizeof(struct opal_global));
struct opal_global *g = alloc(sizeof(struct opal_global));
pthread_mutex_init(&g->lock, NULL);
@ -48,20 +44,20 @@ int opal_init(int argc, char *argv[])
/* Get list of Send and RecvIDs */
if ((err = OpalGetNbAsyncSendIcon(&g->send_icons)) != EOK)
error("Failed to get number of send blocks (%d)", err);
if ((err = OpalGetNbAsyncRecvIcon(&g->recv_icons)) != EOK);
if ((err = OpalGetNbAsyncRecvIcon(&g->recv_icons)) != EOK)
error("Failed to get number of recv blocks (%d)", err);
g->send_ids = (int *) malloc(g->send_icons * sizeof(int));
g->recv_ids = (int *) malloc(g->recv_icons * sizeof(int));
if (!g->send_ids || !g->recv_ids)
error("Failed to allocate memory for OPAL AsyncApi ID list.");
g->send_ids = alloc(g->send_icons * sizeof(int));
g->recv_ids = alloc(g->recv_icons * sizeof(int));
if ((err = OpalGetAsyncSendIDList(g->send_ids, g->send_icons)) != EOK)
if ((err = OpalGetAsyncSendIDList(g->send_ids, g->send_icons * sizeof(int))) != EOK)
error("Failed to get list of send ids (%d)", err);
if ((err = OpalGetAsyncRecvIDList(g->recv_ids, g->recv_icons)) != EOK)
if ((err = OpalGetAsyncRecvIDList(g->recv_ids, g->recv_icons * sizeof(int))) != EOK)
error("Failed to get list of recv ids (%d)", err);
info("Started as OPAL async process:");
info("Started as OPAL Asynchronous process");
info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s, debug=%d)",
VERSION, __DATE__, __TIME__, _debug);
opal_print_global(g);
og = g;
@ -73,18 +69,22 @@ int opal_deinit()
{
int err;
if (og) {
if ((err = OpalCloseAsyncMem(og->async_shmem_size, og->async_shmem_name)) != EOK)
error("Failed to close shared memory area (%d)", err);
if ((err = OpalSystemCtrl_UnRegister(og->print_shmem_name)) != EOK)
error("Failed to close shared memory for system control (%d)", err);
if (!og)
return 0;
if ((err = OpalCloseAsyncMem(og->async_shmem_size, og->async_shmem_name)) != EOK)
error("Failed to close shared memory area (%d)", err);
debug(4, "Closing OPAL shared memory mapping");
if ((err = OpalSystemCtrl_UnRegister(og->print_shmem_name)) != EOK)
error("Failed to close shared memory for system control (%d)", err);
free(og->send_ids);
free(og->recv_ids);
free(og);
free(og->send_ids);
free(og->recv_ids);
free(og);
og = NULL;
}
og = NULL;
return 0;
}
@ -99,15 +99,15 @@ int opal_print_global(struct opal_global *g)
for (int i=0; i<g->recv_icons; i++)
strap(rbuf, sizeof(rbuf), "%u ", g->recv_ids[i]);
debug(4, "Controller ID: %u", g->params.controllerID);
debug(4, "Send Blocks: %s", sbuf);
debug(4, "Receive Blocks: %s", rbuf);
debug(2, "Controller ID: %u", g->params.controllerID);
debug(2, "Send Blocks: %s", sbuf);
debug(2, "Receive Blocks: %s", rbuf);
debug(4, "Control Block Parameters:");
debug(2, "Control Block Parameters:");
for (int i=0; i<GENASYNC_NB_FLOAT_PARAM; i++)
debug(4, "FloatParam[]%u] = %f", i, g->params.FloatParam[i]);
debug(2, "FloatParam[]%u] = %f", i, g->params.FloatParam[i]);
for (int i=0; i<GENASYNC_NB_STRING_PARAM; i++)
debug(4, "StringParam[%u] = %s", i, g->params.StringParam[i]);
debug(2, "StringParam[%u] = %s", i, g->params.StringParam[i]);
return 0;
}
@ -151,9 +151,9 @@ int opal_read(struct node *n, struct msg *m)
do {
if ((ret = OpalWaitForAsyncSendRequest(&id)) != EOK) {
state = OpalGetAsyncModelState();
if ((state != STATE_RESET) && (state != STATE_STOP)) {
OpalSetAsyncSendIconError(ret, id);
info("OpalWaitForAsyncSendRequest(), errno %d", ret);
if ((state == STATE_RESET) || (state == STATE_STOP)) {
warn("OpalGetAsyncModelState(): Model stopped or resetted!");
die();
}
return -1; // FIXME: correct return value
@ -193,8 +193,10 @@ int opal_read(struct node *n, struct msg *m)
/* Before continuing, we make sure that the real-time model
* has not been stopped. If it has, we quit. */
state = OpalGetAsyncModelState();
if ((state == STATE_RESET) || (state == STATE_STOP))
error("OpalGetAsyncModelState(): Model stopped or resetted!"); // TODO: fixme
if ((state == STATE_RESET) || (state == STATE_STOP)) {
warn("OpalGetAsyncModelState(): Model stopped or resetted!");
die();
}
return 0;
}
@ -209,8 +211,10 @@ int opal_write(struct node *n, struct msg *m)
double data[MSG_VALUES] = { NAN };
state = OpalGetAsyncModelState();
if ((state == STATE_RESET) || (state == STATE_STOP))
return -1;
if ((state == STATE_RESET) || (state == STATE_STOP)) {
warn("OpalGetAsyncModelState(): Model stopped or resetted!");
die();
}
OpalSetAsyncRecvIconStatus(m->sequence, o->recv_id); /* Set the Status to the message ID */
OpalSetAsyncRecvIconError(0, o->recv_id); /* Set the Error to 0 */

View file

@ -16,17 +16,19 @@
#include "utils.h"
#include "path.h"
#define sigev_notify_thread_id _sigev_un._tid
#ifndef sigev_notify_thread_id
#define sigev_notify_thread_id _sigev_un._tid
#endif
/** Linked list of paths */
struct path *paths;
/** Linked list of paths. */
struct list paths;
/** Send messages asynchronously */
static void * path_send(void *arg)
{
struct path *p = arg;
int sig;
struct path *p = (struct path *) arg;
timer_t tmr;
sigset_t set;
struct sigevent sev = {
@ -45,22 +47,19 @@ static void * path_send(void *arg)
if(pthread_sigmask(SIG_BLOCK, &set, NULL))
serror("Set signal mask");
if (timer_create(CLOCK_REALTIME, &sev, &tmr))
if (timer_create(CLOCK_REALTIME, &sev, &p->timer))
serror("Failed to create timer");
if (timer_settime(tmr, 0, &its, NULL))
if (timer_settime(p->timer, 0, &its, NULL))
serror("Failed to start timer");
while (1) {
sigwait(&set, &sig); /* blocking wait for next timer tick */
if (p->received) {
FOREACH(&p->destinations, it) {
node_write(it->node, p->last);
}
p->sent++;
}
FOREACH(&p->destinations, it)
node_write(it->node, p->current);
p->sent++;
}
return NULL;
@ -69,43 +68,48 @@ static void * path_send(void *arg)
/** Receive messages */
static void * path_run(void *arg)
{
char buf[33];
struct path *p = arg;
struct msg *m = alloc(sizeof(struct msg));
if (!m)
error("Failed to allocate memory for message!");
p->previous = alloc(sizeof(struct msg));
p->current = alloc(sizeof(struct msg));
char buf[33];
/* Open deferred TCP connection */
node_start_defer(p->in);
// FIXME: node_start_defer(p->out);
/* Main thread loop */
while (1) {
node_read(p->in, m); /* Receive message */
node_read(p->in, p->current); /* Receive message */
p->received++;
/* Check header fields */
if (m->version != MSG_VERSION ||
m->type != MSG_TYPE_DATA) {
if (p->current->version != MSG_VERSION ||
p->current->type != MSG_TYPE_DATA) {
p->invalid++;
continue;
}
/* Update histogram */
int dist = (UINT16_MAX + m->sequence - p->sequence) % UINT16_MAX;
int dist = (UINT16_MAX + p->current->sequence - p->previous->sequence) % UINT16_MAX;
if (dist > UINT16_MAX / 2)
dist -= UINT16_MAX;
hist_put(&p->histogram, dist);
/* Handle simulation restart */
if (m->sequence == 0 && abs(dist) >= 1) {
path_print(p, buf, sizeof(buf));
path_stats(p);
warn("Simulation for path %s restarted (p->seq=%u, m->seq=%u, dist=%d)",
buf, p->sequence, m->sequence, dist);
if (p->current->sequence == 0 && abs(dist) >= 1) {
if (p->received) {
path_print_stats(p);
hist_print(&p->histogram);
}
path_print(p, buf, sizeof(buf));
warn("Simulation for path %s restarted (prev->seq=%u, current->seq=%u, dist=%d)",
buf, p->previous->sequence, p->current->sequence, dist);
/* Reset counters */
p->sent = 0;
@ -114,7 +118,6 @@ static void * path_run(void *arg)
p->skipped = 0;
p->dropped = 0;
hist_print(&p->histogram);
hist_reset(&p->histogram);
}
else if (dist <= 0 && p->received > 1) {
@ -124,27 +127,22 @@ static void * path_run(void *arg)
/* Call hook callbacks */
FOREACH(&p->hooks, it) {
if (it->hook(m, p)) {
if (it->hook(p->current, p)) {
p->skipped++;
continue;
}
}
/* Update last known sequence number */
p->sequence = m->sequence;
p->last = m;
/* At fixed rate mode, messages are send by another thread */
if (!p->rate) {
FOREACH(&p->destinations, it) {
node_write(it->node, m);
}
FOREACH(&p->destinations, it)
node_write(it->node, p->current);
p->sent++;
}
}
free(m);
SWAP(p->previous, p->current);
}
return NULL;
}
@ -156,13 +154,11 @@ int path_start(struct path *p)
info("Starting path: %s", buf);
hist_init(&p->histogram, -HIST_SEQ, +HIST_SEQ, 1);
/* At fixed rate mode, we start another thread for sending */
if (p->rate)
pthread_create(&p->sent_tid, NULL, &path_send, (void *) p);
pthread_create(&p->sent_tid, NULL, &path_send, p);
return pthread_create(&p->recv_tid, NULL, &path_run, (void *) p);
return pthread_create(&p->recv_tid, NULL, &path_run, p);
}
int path_stop(struct path *p)
@ -178,25 +174,23 @@ int path_stop(struct path *p)
if (p->rate) {
pthread_cancel(p->sent_tid);
pthread_join(p->sent_tid, NULL);
timer_delete(p->timer);
}
if (p->sent || p->received) {
path_stats(p);
if (p->received)
hist_print(&p->histogram);
hist_free(&p->histogram);
}
return 0;
}
void path_stats(struct path *p)
void path_print_stats(struct path *p)
{
char buf[33];
path_print(p, buf, sizeof(buf));
info("%-32s : %-8u %-8u %-8u %-8u %-8u",
buf, p->sent, p->received, p->dropped, p->skipped, p->invalid
);
info("%-32s : %-8u %-8u %-8u %-8u %-8u", buf,
p->sent, p->received, p->dropped, p->skipped, p->invalid);
}
int path_print(struct path *p, char *buf, int len)
@ -215,10 +209,25 @@ int path_print(struct path *p, char *buf, int len)
return 0;
}
int path_destroy(struct path *p)
struct path * path_create()
{
struct path *p = alloc(sizeof(struct path));
list_init(&p->destinations, NULL);
list_init(&p->hooks, NULL);
hist_create(&p->histogram, -HIST_SEQ, +HIST_SEQ, 1);
return p;
}
void path_destroy(struct path *p)
{
list_destroy(&p->destinations);
list_destroy(&p->hooks);
hist_destroy(&p->histogram);
return 0;
free(p->current);
free(p->previous);
free(p);
}

View file

@ -22,7 +22,7 @@
void tick(int sig, siginfo_t *si, void *ptr)
{
struct msg *m = (struct msg*) si->si_value.sival_ptr;
struct msg *m = (struct msg *) si->si_value.sival_ptr;
msg_random(m);
msg_fprint(stdout, m);
@ -37,9 +37,12 @@ int main(int argc, char *argv[])
printf("Usage: %s VALUES RATE\n", argv[0]);
printf(" VALUES is the number of values a message contains\n");
printf(" RATE how many messages per second\n\n");
printf("Simulator2Simulator Server %s (built on %s %s)\n", BLU(VERSION), MAG(__DATE__), MAG(__TIME__));
printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <stvogel@eonerc.rwth-aachen.de>\n");
printf("Simulator2Simulator Server %s (built on %s %s)\n",
BLU(VERSION), MAG(__DATE__), MAG(__TIME__));
printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
exit(EXIT_FAILURE);
}

View file

@ -24,7 +24,7 @@
static struct settings set;
static struct msg msg = MSG_INIT(0);
extern struct node *nodes;
extern struct list nodes;
static struct node *node;
void quit(int sig, siginfo_t *si, void *ptr)
@ -35,13 +35,16 @@ void quit(int sig, siginfo_t *si, void *ptr)
void usage(char *name)
{
printf("Usage: %s CONFIG NODE\n", name);
printf("Usage: %s [-r] CONFIG NODE\n", name);
printf(" -r swap local / remote address of socket based nodes)\n\n");
printf(" CONFIG path to a configuration file\n");
printf(" NODE name of the node which shoud be used\n\n");
printf("Simulator2Simulator Server %s (built on %s %s)\n",
BLU(VERSION), MAG(__DATE__), MAG(__TIME__));
printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <stvogel@eonerc.rwth-aachen.de>\n");
printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
exit(EXIT_FAILURE);
}
@ -76,7 +79,7 @@ int main(int argc, char *argv[])
config_init(&config);
config_parse(argv[optind], &config, &set, &nodes, NULL);
node = node_lookup_name(argv[optind+1], nodes);
node = node_lookup_name(argv[optind+1], &nodes);
if (!node)
error("There's no node with the name '%s'", argv[optind+1]);

View file

@ -27,7 +27,7 @@
static struct settings set;
static struct msg msg = MSG_INIT(0);
static struct node *node;
extern struct node *nodes;
extern struct list nodes;
void quit(int sig, siginfo_t *si, void *ptr)
{
@ -38,13 +38,15 @@ void quit(int sig, siginfo_t *si, void *ptr)
void usage(char *name)
{
printf("Usage: %s [-r] CONFIG NODE\n", name);
printf(" -r swap local / remote address of socket based nodes)\n");
printf(" -r swap local / remote address of socket based nodes)\n\n");
printf(" CONFIG path to a configuration file\n");
printf(" NODE name of the node which shoud be used\n");
printf("Simulator2Simulator Server %s (built on %s %s)\n",
BLU(VERSION), MAG(__DATE__), MAG(__TIME__));
printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <stvogel@eonerc.rwth-aachen.de>\n");
printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
exit(EXIT_FAILURE);
}
@ -79,7 +81,7 @@ int main(int argc, char *argv[])
config_init(&config);
config_parse(argv[optind], &config, &set, &nodes, NULL);
node = node_lookup_name(argv[optind+1], nodes);
node = node_lookup_name(argv[optind+1], &nodes);
if (!node)
error("There's no node with the name '%s'", argv[optind+1]);

View file

@ -27,55 +27,52 @@
#endif
/** Linked list of nodes */
extern struct node *nodes;
extern struct list nodes;
/** Linked list of paths */
extern struct path *paths;
extern struct list paths;
/** Linked list of interfaces */
extern struct interface *interfaces;
extern struct list interfaces;
/** The global configuration */
struct settings settings;
config_t config;
static struct settings settings;
static config_t config;
static void quit()
{ _indent = 0;
{
info("Stopping paths:");
for (struct path *p = paths; p; p = p->next) { INDENT
path_stop(p);
path_destroy(p);
}
FOREACH(&paths, it)
path_stop(it->path);
info("Stopping nodes:");
for (struct node *n = nodes; n; n = n->next) { INDENT
node_stop(n);
}
FOREACH(&nodes, it)
node_stop(it->node);
info("Stopping interfaces:");
for (struct interface *i = interfaces; i; i = i->next) { INDENT
if_stop(i);
}
FOREACH(&interfaces, it)
if_stop(it->interface);
/** @todo Free nodes */
#ifdef ENABLE_OPAL_ASYNC
opal_deinit();
#endif
/* Freeing dynamically allocated memory */
list_destroy(&paths);
list_destroy(&nodes);
list_destroy(&interfaces);
config_destroy(&config);
info("Goodbye!");
_exit(EXIT_SUCCESS);
}
void realtime_init()
{ INDENT
/* Check for realtime kernel patch */
struct stat st;
if (stat("/sys/kernel/realtime", &st))
warn("Use a RT-preempt patched Linux for lower latencies!");
else
info("Server is running on a realtime patched kernel");
/* Use FIFO scheduler with realtime priority */
/* Use FIFO scheduler with real time priority */
if (settings.priority) {
struct sched_param param = { .sched_priority = settings.priority };
if (sched_setscheduler(0, SCHED_FIFO, &param))
serror("Failed to set realtime priority");
serror("Failed to set real time priority");
else
debug(3, "Set task priority to %u", settings.priority);
}
@ -99,9 +96,9 @@ void signals_init()
};
sigemptyset(&sa_quit.sa_mask);
sigaction(SIGQUIT, &sa_quit, NULL);
sigaction(SIGTERM, &sa_quit, NULL);
sigaction(SIGINT, &sa_quit, NULL);
atexit(&quit);
}
void usage(const char *name)
@ -113,14 +110,18 @@ void usage(const char *name)
printf(" This type of invocation is used by OPAL-RT Asynchronous processes.\n");
printf(" See in the RT-LAB User Guide for more information.\n\n");
#endif
printf("Simulator2Simulator Server %s (built on %s, %s)\n",
printf("Simulator2Simulator Server %s (built on %s %s)\n",
BLU(VERSION), MAG(__DATE__), MAG(__TIME__));
printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
_mtid = pthread_self();
/* Check arguments */
#ifdef ENABLE_OPAL_ASYNC
if (argc != 2 && argc != 4)
@ -128,28 +129,37 @@ int main(int argc, char *argv[])
if (argc != 2)
#endif
usage(argv[0]);
epoch_reset();
info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s)",
BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)));
char *configfile = argv[1];
info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s, debug=%d)",
BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)), _debug);
/* Check priviledges */
if (getuid() != 0)
error("The server requires superuser privileges!");
/* Start initialization */
/* Initialize lists */
list_init(&nodes, (dtor_cb_t) node_destroy);
list_init(&paths, (dtor_cb_t) path_destroy);
list_init(&interfaces, (dtor_cb_t) if_destroy);
info("Initialize realtime system:");
realtime_init();
info("Setup signals:");
signals_init();
info("Parsing configuration:");
config_init(&config);
#ifdef ENABLE_OPAL_ASYNC
/* Check if called as asynchronous process from RT-LAB */
/* Check if called we are called as an asynchronous process from RT-LAB. */
opal_init(argc, argv);
/* @todo: look in predefined locations for a file */
char *configfile = "opal-shmem.conf";
#else
char *configfile = argv[1];
#endif
/* Parse configuration and create nodes/paths */
@ -157,40 +167,34 @@ int main(int argc, char *argv[])
/* Connect all nodes and start one thread per path */
info("Starting nodes:");
for (struct node *n = nodes; n; n = n->next) { INDENT
node_start(n);
}
FOREACH(&nodes, it)
node_start(it->node);
info("Starting interfaces:");
for (struct interface *i = interfaces; i; i = i->next) { INDENT
if_start(i, settings.affinity);
}
FOREACH(&interfaces, it)
if_start(it->interface, settings.affinity);
info("Starting pathes:");
for (struct path *p = paths; p; p = p->next) { INDENT
path_start(p);
}
info("Starting paths:");
FOREACH(&paths, it)
path_start(it->path);
/* Run! */
if (settings.stats > 0) {
struct path *p = paths;
info("Runtime Statistics:");
info("%-32s : %-8s %-8s %-8s %-8s %-8s",
"Source " MAG("=>") " Destination", "#Sent", "#Recv", "#Drop", "#Skip", "#Inval");
info("---------------------------------------------------------------------------");
while (1) {
do { FOREACH(&paths, it) {
usleep(settings.stats * 1e6);
path_stats(p);
path_print_stats(it->path);
} } while (1);
p = (p->next) ? p->next : paths;
}
}
else
pause();
/* Note: quit() is called by exit handler! */
quit();
return 0;
}

View file

@ -34,8 +34,8 @@ int socket_print(struct node *n, char *buf, int len)
char local[INET6_ADDRSTRLEN + 16];
char remote[INET6_ADDRSTRLEN + 16];
socket_print_addr(local, sizeof(local), (struct sockaddr*) &s->local);
socket_print_addr(remote, sizeof(remote), (struct sockaddr*) &s->remote);
socket_print_addr(local, sizeof(local), (struct sockaddr *) &s->local);
socket_print_addr(remote, sizeof(remote), (struct sockaddr *) &s->remote);
return snprintf(buf, len, "local=%s, remote=%s", local, remote);
}
@ -86,7 +86,7 @@ int socket_open(struct node *n)
if (!i)
i = if_create(index);
list_add(i->sockets, s);
list_push(&i->sockets, s);
i->refcnt++;
/* Set socket priority, QoS or TOS IP options */
@ -230,7 +230,7 @@ int socket_parse_addr(const char *addr, struct sockaddr *sa, enum node_type type
else { /* Format: "192.168.0.10:12001" */
struct addrinfo hint = {
.ai_flags = flags,
.ai_family = AF_UNSPEC
.ai_family = AF_INET
};
/* Split string */

View file

@ -26,7 +26,7 @@
static struct settings set;
static struct node *node;
extern struct node *nodes;
extern struct list nodes;
/* Test options */
int running = 1;
@ -48,7 +48,7 @@ double high = 2e-4;
/** Histogram resolution. */
double res = 1e-5;
#define CLOCK_ID CLOCK_MONOTONIC_RAW
#define CLOCK_ID CLOCK_MONOTONIC
/* Prototypes */
void test_rtt();
@ -67,10 +67,12 @@ int main(int argc, char *argv[])
printf(" CONFIG path to a configuration file\n");
printf(" TEST the name of the test to execute: 'rtt'\n");
printf(" NODE name of the node which shoud be used\n\n");
printf("Simulator2Simulator Server %s (built on %s %s)\n",
BLU(VERSION), MAG(__DATE__), MAG(__TIME__));
printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <stvogel@eonerc.rwth-aachen.de>\n");
printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
exit(EXIT_FAILURE);
}
@ -87,7 +89,7 @@ int main(int argc, char *argv[])
config_init(&config);
config_parse(argv[1], &config, &set, &nodes, NULL);
node = node_lookup_name(argv[3], nodes);
node = node_lookup_name(argv[3], &nodes);
if (!node)
error("There's no node with the name '%s'", argv[3]);
@ -122,9 +124,9 @@ int main(int argc, char *argv[])
error("Unknown option '-%c'.", optopt);
else
error("Unknown option character '\\x%x'.", optopt);
exit(1);
exit(EXIT_FAILURE);
default:
abort ();
abort();
}
continue;
@ -155,7 +157,7 @@ void test_rtt() {
double avg = 0;
struct hist histogram;
hist_init(&histogram, low, high, res);
hist_create(&histogram, low, high, res);
#if 1 /* Print header */
fprintf(stdout, "%17s", "timestamp");
@ -201,5 +203,5 @@ void test_rtt() {
else
error("Invalid file descriptor: %u", fd);
hist_free(&histogram);
hist_destroy(&histogram);
}

View file

@ -12,10 +12,11 @@
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <time.h>
#include <math.h>
#include <signal.h>
#ifdef ENABLE_OPAL_ASYNC
#define RTLAB
#include <OpalPrint.h>
#endif
@ -23,20 +24,11 @@
#include "cfg.h"
#include "utils.h"
/* This global variable contains the debug level for debug() and assert() macros */
int _debug = V;
int _indent = 0;
pthread_t _mtid;
struct timespec epoch;
void outdent(int *old)
void die()
{
_indent = *old;
}
void epoch_reset()
{
clock_gettime(CLOCK_REALTIME, &epoch);
pthread_kill(_mtid, SIGINT);
}
int strap(char *dest, size_t size, const char *fmt, ...)
@ -58,43 +50,6 @@ int vstrap(char *dest, size_t size, const char *fmt, va_list ap)
return vsnprintf(dest + len, size - len, fmt, ap);
}
void print(enum log_level lvl, const char *fmt, ...)
{
struct timespec ts;
char buf[512] = "";
va_list ap;
/* Timestamp */
clock_gettime(CLOCK_REALTIME, &ts);
strap(buf, sizeof(buf), "%8.3f ", timespec_delta(&epoch, &ts));
/* Severity */
switch (lvl) {
case DEBUG: strap(buf, sizeof(buf), BLD("%-5s "), GRY("Debug")); break;
case INFO: strap(buf, sizeof(buf), BLD("%-5s "), " " ); break;
case WARN: strap(buf, sizeof(buf), BLD("%-5s "), YEL(" Warn")); break;
case ERROR: strap(buf, sizeof(buf), BLD("%-5s "), RED("Error")); break;
}
/* Indention */
for (int i = 0; i < _indent-1; i++)
strap(buf, sizeof(buf), GFX("\x78") " ");
strap(buf, sizeof(buf), GFX("\x74") " ");
/* Format String */
va_start(ap, fmt);
vstrap(buf, sizeof(buf), fmt, ap);
va_end(ap);
/* Output */
#ifdef ENABLE_OPAL_ASYNC
OpalPrint("%s\n", buf);
#else
fprintf(stderr, "%s\n", buf);
#endif
}
cpu_set_t to_cpu_set(int set)
{
cpu_set_t cset;