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:
commit
b657d795d6
56 changed files with 716 additions and 430 deletions
2
Doxyfile
2
Doxyfile
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
7
contrib/liveusb/etc/default/grub
Normal file
7
contrib/liveusb/etc/default/grub
Normal 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
|
1
contrib/liveusb/etc/hostname
Normal file
1
contrib/liveusb/etc/hostname
Normal file
|
@ -0,0 +1 @@
|
|||
unknown-s2ss
|
10
contrib/liveusb/etc/hosts
Normal file
10
contrib/liveusb/etc/hosts
Normal 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
|
15
contrib/liveusb/etc/systemd/system/mongoose.service
Normal file
15
contrib/liveusb/etc/systemd/system/mongoose.service
Normal 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
|
1
contrib/liveusb/etc/tuned/active_profile
Normal file
1
contrib/liveusb/etc/tuned/active_profile
Normal file
|
@ -0,0 +1 @@
|
|||
latency-performance
|
9
contrib/liveusb/prepare.sh
Normal file
9
contrib/liveusb/prepare.sh
Normal 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
|
|
@ -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
24
contrib/liveusb/update_boot.sh
Executable 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
12
contrib/update_docs.sh
Executable 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
|
|
@ -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
|
||||
|
|
28
server/etc/opal-shmem.conf
Normal file
28
server/etc/opal-shmem.conf
Normal 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";
|
||||
}
|
||||
);
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
77
server/include/log.h
Normal 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_ */
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
75
server/src/log.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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, ¶m))
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue