mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
Merge branch 'gtfpga'
This commit is contained in:
commit
7d33a2cf7b
20 changed files with 646 additions and 375 deletions
|
@ -1,76 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <pci/pci.h>
|
||||
|
||||
#define SYSFS_PATH "/sys/bus/pci"
|
||||
#define GTFPGA_DID 0x10f5
|
||||
#define GTFPGA_VID 0x8086
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct pci_access *pacc;
|
||||
struct pci_dev *dev;
|
||||
struct pci_filter filter;
|
||||
|
||||
unsigned int c;
|
||||
char namebuf[1024], *name;
|
||||
|
||||
pacc = pci_alloc(); /* Get the pci_access structure */
|
||||
|
||||
pci_init(pacc); /* Initialize the PCI library */
|
||||
pci_scan_bus(pacc); /* We want to get the list of devices */
|
||||
|
||||
pci_filter_init(pacc, &filter);
|
||||
filter.vendor = GTFPGA_VID;
|
||||
filter.device = GTFPGA_DID;
|
||||
|
||||
for (dev = pacc->devices; dev; dev = dev->next) { /* Iterate over all devices */
|
||||
if (pci_filter_match(&filter, dev))
|
||||
break;
|
||||
}
|
||||
|
||||
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
|
||||
|
||||
c = pci_read_byte(dev, PCI_INTERRUPT_PIN); /* Read config register directly */
|
||||
|
||||
printf("%04x:%02x:%02x.%d vendor=%04x device=%04x class=%04x irq=%d (pin %d)",
|
||||
dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id,
|
||||
dev->device_class, dev->irq, c);
|
||||
|
||||
/* Look up and print the full name of the device */
|
||||
printf(" (%s)\n", pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id));
|
||||
|
||||
for (int i = 0; i< 6; i++) {
|
||||
printf("base_addr[%u] = %#lx, size = %#lx\n", i,
|
||||
dev->base_addr[i],
|
||||
dev->size[i]);
|
||||
}
|
||||
|
||||
int fd = open("/dev/mem", O_RDWR);
|
||||
if (!fd)
|
||||
perror("Failed open(): ");
|
||||
|
||||
void *map = mmap(NULL, dev->size[0], PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev->base_addr[0]);
|
||||
|
||||
if (map == MAP_FAILED)
|
||||
perror("Failed mmap(): ");
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
unsigned char *p = map + i;
|
||||
printf("%02hx ", *p);
|
||||
|
||||
if (i % 32 == 31)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
getchar();
|
||||
|
||||
munmap(map, dev->size[0]);
|
||||
|
||||
pci_cleanup(pacc); /* Close everything */
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -72,10 +72,25 @@ int config_parse_global(config_setting_t *cfg, struct settings *set);
|
|||
*/
|
||||
int config_parse_path(config_setting_t *cfg,
|
||||
struct list *paths, struct list *nodes);
|
||||
|
||||
|
||||
/** Parse an array or single node and checks if they exist in the "nodes" section.
|
||||
*
|
||||
* Examples:
|
||||
* out = [ "sintef", "scedu" ]
|
||||
* out = "acs"
|
||||
*
|
||||
* @param cfg The libconfig object handle for "out".
|
||||
* @param nodes The nodes will be added to this list.
|
||||
* @param all This list contains all valid nodes.
|
||||
*/
|
||||
int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct list *all);
|
||||
|
||||
|
||||
/** Parse an array or single hook function.
|
||||
*
|
||||
* Examples:
|
||||
* hooks = [ "print", "fir" ]
|
||||
* hooks = "log"
|
||||
**/
|
||||
int config_parse_hooks(config_setting_t *cfg, struct list *hooks);
|
||||
|
||||
/** Parse a single node and add it to the global configuration.
|
||||
|
@ -87,40 +102,4 @@ int config_parse_hooks(config_setting_t *cfg, struct list *hooks);
|
|||
*/
|
||||
int config_parse_node(config_setting_t *cfg, struct list *nodes);
|
||||
|
||||
/** Parse node connection details for OPAL type
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param nodes Add new nodes to this linked list.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int config_parse_opal(config_setting_t *cfg, struct node *n);
|
||||
|
||||
/** Parse node connection details for GTFPGA type
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param n A pointer to the node structure which should be parsed.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int config_parse_gtfpga(config_setting_t *cfg, struct node *n);
|
||||
|
||||
/** Parse node connection details for SOCKET type
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param n A pointer to the node structure which should be parsed.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int config_parse_socket(config_setting_t *cfg, struct node *n);
|
||||
|
||||
/** Parse network emulator (netem) settings.
|
||||
*
|
||||
* @param cfg A libconfig object containing the settings.
|
||||
* @param em A pointer to the netem settings structure (part of the path structure).
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int config_parse_netem(config_setting_t *cfg, struct netem *em);
|
||||
|
||||
#endif /* _CFG_H_ */
|
||||
|
|
|
@ -9,8 +9,47 @@
|
|||
#ifndef _GTFPGA_H_
|
||||
#define _GTFPGA_H_
|
||||
|
||||
struct gtfpga {
|
||||
#include <pci/pci.h>
|
||||
|
||||
#define GTFPGA_BAR 0 /**< The Base Address Register which is mmap()ed to the User Space */
|
||||
|
||||
#define GTFPGA_MAX_TX 64 /**< The amount of values which is supported by the GTFPGA card */
|
||||
#define GTFPGA_MAX_RX 64 /**< The amount of values which is supported by the GTFPGA card */
|
||||
|
||||
#define GTFPGA_VID 0x10ee /**< The default vendor ID of the GTFPGA card */
|
||||
#define GTFPGA_DID 0x0007 /**< The default device ID of the GTFPGA card */
|
||||
|
||||
|
||||
struct gtfpga {
|
||||
struct pci_filter filter;
|
||||
|
||||
int fd_mmap, fd_uio;
|
||||
void *map;
|
||||
|
||||
struct pci_dev *dev;
|
||||
};
|
||||
|
||||
int gtfpga_init(int argc, char * argv[]);
|
||||
|
||||
int gtfpga_deinit();
|
||||
|
||||
/** Parse node connection details for GTFPGA type
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param n A pointer to the node structure which should be parsed.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int gtfpga_parse(config_setting_t *cfg, struct node *n);
|
||||
|
||||
int gtfpga_print(struct node *n, char *buf, int len);
|
||||
|
||||
int gtfpga_open(struct node *n);
|
||||
|
||||
int gtfpga_close(struct node *n);
|
||||
|
||||
int gtfpga_read(struct node *n, struct msg *m);
|
||||
|
||||
int gtfpga_write(struct node *n, struct msg *m);
|
||||
|
||||
#endif /* _GTFPGA_H_ */
|
||||
|
|
|
@ -5,34 +5,44 @@
|
|||
* @file
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H_
|
||||
#ifndef _LOG_H_
|
||||
#define _LOG_H_
|
||||
|
||||
#include <libconfig.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
|
||||
};
|
||||
|
||||
#define DEBUG GRY("Debug")
|
||||
#define INFO ""
|
||||
#define WARN YEL("Warn")
|
||||
#define ERROR RED("Error")
|
||||
|
||||
/** Change log indention for current thread.
|
||||
*
|
||||
* The argument level can be negative!
|
||||
*/
|
||||
int log_indent(int levels);
|
||||
|
||||
/** A helper function the restore the previous log indention level.
|
||||
*
|
||||
* This function is usually called by a __cleanup__ handler (GCC C Extension).
|
||||
* See INDENT macro.
|
||||
*/
|
||||
void log_outdent(int *);
|
||||
|
||||
/** Reset the wallclock of debugging outputs */
|
||||
/** Set the verbosity level of debug messages.
|
||||
*
|
||||
* @param lvl The new debug level.
|
||||
*/
|
||||
void log_setlevel(int lvl);
|
||||
|
||||
/** Reset the wallclock of debug messages. */
|
||||
void log_reset();
|
||||
|
||||
/** Logs variadic messages to stdout.
|
||||
|
@ -40,38 +50,40 @@ void log_reset();
|
|||
* @param lvl The log level
|
||||
* @param fmt The format string (printf alike)
|
||||
*/
|
||||
void log_print(enum log_level lvl, const char *fmt, ...)
|
||||
void log_print(const char *lvl, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
/** Logs variadic messages to stdout.
|
||||
*
|
||||
* @param lvl The log level
|
||||
* @param fmt The format string (printf alike)
|
||||
* @param va The variadic argument list (see stdarg.h)
|
||||
*/
|
||||
void log_vprint(const char *lvl, const char *fmt, va_list va);
|
||||
|
||||
/** Printf alike debug message with level. */
|
||||
#define debug(lvl, msg, ...) do if (lvl <= _debug) log_print(DEBUG, msg, ##__VA_ARGS__); while (0)
|
||||
void debug(int lvl, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
/** Printf alike info message. */
|
||||
#define info(msg, ...) do log_print(INFO, msg, ##__VA_ARGS__); while (0)
|
||||
void info(const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
/** Printf alike warning message. */
|
||||
#define warn(msg, ...) do log_print(WARN, msg, ##__VA_ARGS__); while (0)
|
||||
|
||||
void warn(const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
/** Print error and exit. */
|
||||
#define error(msg, ...) do { \
|
||||
log_print(ERROR, msg, ##__VA_ARGS__); \
|
||||
die(); \
|
||||
} while (0)
|
||||
void error(const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
/** Print error and strerror(errno). */
|
||||
#define serror(msg, ...) do { \
|
||||
log_print(ERROR, msg ": %s", ##__VA_ARGS__, strerror(errno)); \
|
||||
die(); \
|
||||
} while (0)
|
||||
void serror(const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
/** 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)
|
||||
void cerror(config_setting_t *cfg, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
#endif /* _LOG_H_ */
|
||||
|
||||
|
|
|
@ -42,13 +42,15 @@ enum node_type {
|
|||
TCPD, /* BSD socket: AF_INET SOCK_STREAM bind + listen + accept */
|
||||
TCP, /* BSD socket: AF_INET SOCK_STREAM bind + connect */
|
||||
OPAL_ASYNC, /* OPAL-RT Asynchronous Process Api */
|
||||
// GTFPGA, /* Xilinx ML507 GTFPGA card */
|
||||
GTFPGA, /* Xilinx ML507 GTFPGA card */
|
||||
INVALID
|
||||
};
|
||||
|
||||
/** C++ like vtable construct for node_types */
|
||||
/** C++ like vtable construct for node_types
|
||||
* @todo Add comments
|
||||
*/
|
||||
struct node_vtable {
|
||||
enum node_type type;
|
||||
const enum node_type type;
|
||||
const char *name;
|
||||
|
||||
int (*parse)(config_setting_t *cfg, struct node *n);
|
||||
|
@ -58,6 +60,11 @@ struct node_vtable {
|
|||
int (*close)(struct node *n);
|
||||
int (*read)(struct node *n, struct msg *m);
|
||||
int (*write)(struct node *n, struct msg *m);
|
||||
|
||||
int (*init)(int argc, char *argv[]);
|
||||
int (*deinit)();
|
||||
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
/** The data structure for a node.
|
||||
|
@ -73,7 +80,7 @@ struct node
|
|||
const char *name;
|
||||
|
||||
/** C++ like virtual function call table */
|
||||
struct node_vtable const *vt;
|
||||
struct node_vtable *vt;
|
||||
/** Virtual data (used by vtable functions) */
|
||||
union {
|
||||
struct socket *socket;
|
||||
|
@ -86,6 +93,20 @@ struct node
|
|||
config_setting_t *cfg;
|
||||
};
|
||||
|
||||
/** Initialize node type subsystems.
|
||||
*
|
||||
* These routines are only called once per type (not node).
|
||||
* See node_vtable::init
|
||||
*/
|
||||
int node_init(int argc, char *argv[]);
|
||||
|
||||
/** De-initialize node type subsystems.
|
||||
*
|
||||
* These routines are only called once per type (not node).
|
||||
* See node_vtable::deinit
|
||||
*/
|
||||
int node_deinit();
|
||||
|
||||
/** Connect and bind the UDP socket of this node.
|
||||
*
|
||||
* Depending on the type (vtable) of this node,
|
||||
|
@ -121,7 +142,7 @@ int node_stop(struct node *n);
|
|||
* @param str A string describing the socket type. This must be one of: tcp, tcpd, udp, ip, ieee802.3 or opal
|
||||
* @return A pointer to the vtable, or NULL if there is no socket type / vtable with this id.
|
||||
*/
|
||||
struct node_vtable const * node_lookup_vtable(const char *str);
|
||||
struct node_vtable * node_lookup_vtable(const char *str);
|
||||
|
||||
/** Search list of nodes for a name.
|
||||
*
|
||||
|
|
|
@ -71,6 +71,15 @@ int opal_init(int argc, char *argv[]);
|
|||
*/
|
||||
int opal_deinit();
|
||||
|
||||
/** Parse node connection details for OPAL type
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param nodes Add new nodes to this linked list.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int opal_parse(config_setting_t *cfg, struct node *n);
|
||||
|
||||
int opal_print(struct node *n, char *buf, int len);
|
||||
|
||||
int opal_print_global(struct opal_global *g);
|
||||
|
|
|
@ -67,6 +67,15 @@ int socket_write(struct node *n, struct msg *m);
|
|||
*/
|
||||
int socket_read(struct node *n, struct msg *m);
|
||||
|
||||
/** Parse node connection details for SOCKET type
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param n A pointer to the node structure which should be parsed.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int socket_parse(config_setting_t *cfg, struct node *n);
|
||||
|
||||
/** Print details of socket connection
|
||||
*
|
||||
* @param n A pointer to the node structure
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#define _TC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
/** A type alias for TC handles.
|
||||
*
|
||||
|
@ -64,6 +65,15 @@ struct netem {
|
|||
int duplicate;
|
||||
};
|
||||
|
||||
/** Parse network emulator (netem) settings.
|
||||
*
|
||||
* @param cfg A libconfig object containing the settings.
|
||||
* @param em A pointer to the netem settings structure (part of the path structure).
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int tc_parse(config_setting_t *cfg, struct netem *em);
|
||||
|
||||
/** Remove all queuing disciplines and filters.
|
||||
*
|
||||
* @param i The interface
|
||||
|
|
|
@ -24,39 +24,25 @@
|
|||
#endif
|
||||
|
||||
/* Some color escape codes for pretty log messages */
|
||||
#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 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"
|
||||
#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 GFX(chr) " "
|
||||
#define UP(n) ""
|
||||
#define DOWN(n) ""
|
||||
#define RIGHT(n) ""
|
||||
#define LEFT(n) ""
|
||||
#endif
|
||||
/* Alternate character set */
|
||||
#define ACS(chr) "\e(0" chr "\e(B"
|
||||
#define ACS_VERTICAL ACS("\x78")
|
||||
#define ACS_VERTRIGHT ACS("\x74s")
|
||||
s
|
||||
/* UTF-8 Line drawing characters */
|
||||
#define UTF8_BOX "\xE2\x96\x88"
|
||||
#define UTF8_VERTICAL "\xE2\x94\x82"
|
||||
#define UTF8_VERTRIGHT "\xE2\x94\x9C"
|
||||
|
||||
/* CPP stringification */
|
||||
#define XSTR(x) STR(x)
|
||||
|
|
123
server/src/cfg.c
123
server/src/cfg.c
|
@ -19,9 +19,12 @@
|
|||
#include "hooks.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "gtfpga.h"
|
||||
|
||||
#ifdef ENABLE_GTFPGA
|
||||
#include "gtfpga.h"
|
||||
#endif
|
||||
#ifdef ENABLE_OPAL_ASYNC
|
||||
#include "opal.h"
|
||||
#include "opal.h"
|
||||
#endif
|
||||
|
||||
int config_parse(const char *filename, config_t *cfg, struct settings *set,
|
||||
|
@ -83,8 +86,6 @@ int config_parse_global(config_setting_t *cfg, struct settings *set)
|
|||
config_setting_lookup_int(cfg, "debug", &set->debug);
|
||||
config_setting_lookup_float(cfg, "stats", &set->stats);
|
||||
|
||||
_debug = set->debug;
|
||||
|
||||
set->cfg = cfg;
|
||||
|
||||
return 0;
|
||||
|
@ -132,13 +133,16 @@ int config_parse_path(config_setting_t *cfg,
|
|||
|
||||
if (enabled) {
|
||||
p->in->refcnt++;
|
||||
FOREACH(&p->destinations, it)
|
||||
p->in->vt->refcnt++;
|
||||
|
||||
FOREACH(&p->destinations, it) {
|
||||
it->node->refcnt++;
|
||||
it->node->vt->refcnt++;
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
if (list_length(&p->destinations) > 1)
|
||||
warn("Using first destination '%s' as source for reverse path. "
|
||||
"Ignoring remaining nodes", p->out->name);
|
||||
error("Can't reverse path with multiple destination nodes");
|
||||
|
||||
struct path *r = path_create();
|
||||
|
||||
|
@ -149,6 +153,8 @@ int config_parse_path(config_setting_t *cfg,
|
|||
|
||||
r->in->refcnt++;
|
||||
r->out->refcnt++;
|
||||
r->in->vt->refcnt++;
|
||||
r->out->vt->refcnt++;
|
||||
|
||||
list_push(paths, r);
|
||||
}
|
||||
|
@ -257,106 +263,3 @@ int config_parse_node(config_setting_t *cfg, struct list *nodes)
|
|||
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 node '%s', because this server is not running as an OPAL Async process!", n->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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->recv_id);
|
||||
config_setting_lookup_bool(cfg, "reply", &o->reply);
|
||||
|
||||
/* Search for valid send and recv ids */
|
||||
int sfound = 0, rfound = 0;
|
||||
for (int i=0; i<og->send_icons; i++)
|
||||
sfound += og->send_ids[i] == o->send_id;
|
||||
for (int i=0; i<og->send_icons; i++)
|
||||
rfound += og->send_ids[i] == o->send_id;
|
||||
|
||||
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, "recv_id"), "Invalid recv_id '%u' for node '%s'", o->recv_id, n->name);
|
||||
|
||||
n->opal = o;
|
||||
n->opal->global = og;
|
||||
n->cfg = cfg;
|
||||
|
||||
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)
|
||||
{
|
||||
const char *local, *remote;
|
||||
int ret;
|
||||
|
||||
struct socket *s = alloc(sizeof(struct socket));
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "remote", &remote))
|
||||
cerror(cfg, "Missing remote address for node '%s'", n->name);
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "local", &local))
|
||||
cerror(cfg, "Missing local address for node '%s'", n->name);
|
||||
|
||||
ret = socket_parse_addr(local, (struct sockaddr *) &s->local, node_type(n), AI_PASSIVE);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to resolve local address '%s' of node '%s': %s",
|
||||
local, n->name, gai_strerror(ret));
|
||||
|
||||
ret = socket_parse_addr(remote, (struct sockaddr *) &s->remote, node_type(n), 0);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to resolve remote address '%s' of node '%s': %s",
|
||||
remote, n->name, gai_strerror(ret));
|
||||
|
||||
/** @todo Netem settings are not usable AF_UNIX */
|
||||
config_setting_t *cfg_netem = config_setting_get_member(cfg, "netem");
|
||||
if (cfg_netem) {
|
||||
s->netem = alloc(sizeof(struct netem));
|
||||
|
||||
config_parse_netem(cfg_netem, s->netem);
|
||||
}
|
||||
|
||||
n->socket = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_netem(config_setting_t *cfg, struct netem *em)
|
||||
{
|
||||
em->valid = 0;
|
||||
|
||||
if (config_setting_lookup_string(cfg, "distribution", &em->distribution))
|
||||
em->valid |= TC_NETEM_DISTR;
|
||||
if (config_setting_lookup_int(cfg, "delay", &em->delay))
|
||||
em->valid |= TC_NETEM_DELAY;
|
||||
if (config_setting_lookup_int(cfg, "jitter", &em->jitter))
|
||||
em->valid |= TC_NETEM_JITTER;
|
||||
if (config_setting_lookup_int(cfg, "loss", &em->loss))
|
||||
em->valid |= TC_NETEM_LOSS;
|
||||
if (config_setting_lookup_int(cfg, "duplicate", &em->duplicate))
|
||||
em->valid |= TC_NETEM_DUPL;
|
||||
if (config_setting_lookup_int(cfg, "corrupt", &em->corrupt))
|
||||
em->valid |= TC_NETEM_CORRUPT;
|
||||
|
||||
/** @todo Validate netem config values */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,3 +7,185 @@
|
|||
*/
|
||||
|
||||
#include "gtfpga.h"
|
||||
|
||||
#define SYSFS_PATH "/sys/bus/pci"
|
||||
|
||||
static pci_access *pacc;
|
||||
|
||||
int gtfpga_init(int argc, char *argv[])
|
||||
{
|
||||
pacc = pci_alloc(); /* Get the pci_access structure */
|
||||
pci_init(pacc); /* Initialize the PCI library */
|
||||
|
||||
pacc->error = error; /* Replace logging and debug functions */
|
||||
pacc->warning = warn;
|
||||
pacc->debug = debug;
|
||||
|
||||
pci_scan_bus(pacc); /* We want to get the list of devices */
|
||||
}
|
||||
|
||||
int gtfpga_deinit()
|
||||
{
|
||||
pci_cleanup(pacc);
|
||||
}
|
||||
|
||||
int gtfpga_parse(config_setting_t *cfg, struct node *n)
|
||||
{
|
||||
char *slot, *id;
|
||||
config_setting_t *cfg_slot, *cfg_id;
|
||||
struct gtfpga *g = alloc(sizeof(struct gtfpga));
|
||||
|
||||
pci_filter_init(NULL, &g->filter);
|
||||
|
||||
if (cfg_slot = config_setting_get_member(cfg, "slot")) {
|
||||
if (slot = config_setting_get_string(cfg_slot)) {
|
||||
if ((err = pci_filter_parse_slot(&g->filter, slot))
|
||||
cerror(cfg_slot, "%s", err);
|
||||
}
|
||||
else
|
||||
cerror(cfg_slot, "Invalid slot format");
|
||||
}
|
||||
|
||||
if (cfg_id = config_setting_get_member(cfg, "id")) {
|
||||
if (id = config_setting_get_string(cfg_id)) {
|
||||
if ((err = pci_filter_parse_id(&g->filter, id))
|
||||
cerror(cfg_id, "%s", err);
|
||||
}
|
||||
else
|
||||
cerror(cfg_slot, "Invalid id format");
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gtfpga_print(struct node *n, char *buf, int len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int gtfpga_load_driver(struct pci_dev *d)
|
||||
{
|
||||
FILE *f;
|
||||
char slot[16];
|
||||
int ret;
|
||||
|
||||
/* Prepare slot identifier */
|
||||
snprintf(slot, sizeof(slot), "%04x:%02x:%02x.%x",
|
||||
d->domain, d->bus, d->slot, d->func);
|
||||
|
||||
/* Load uio_pci_generic module */
|
||||
ret = system2("modprobe uio_pci_generic");
|
||||
if (ret)
|
||||
serror("Failed to load module");
|
||||
|
||||
/* Add new ID to uio_pci_generic */
|
||||
f = fopen(SYSFS_PATH "/drivers/uio_pci_generic/new_id", "w");
|
||||
if (!f)
|
||||
serror("Failed to add PCI id to uio_pci_generic driver");
|
||||
|
||||
fprintf(f, "%04x %04x", d->vendor_id, d->device_id);
|
||||
fclose(f);
|
||||
|
||||
/* Bind to uio_pci_generic */
|
||||
f = fopen(SYSFS_PATH "/drivers/uio_pci_generic/bind", "w");
|
||||
if (!f)
|
||||
serror("Failed to add PCI id to uio_pci_generic driver");
|
||||
|
||||
fprintf(f, "%s\n", slot);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static struct pci_dev * gtfpga_find_device(struct pci_filter *f)
|
||||
{
|
||||
struct pci_dev *d;
|
||||
|
||||
/* Iterate over all devices */
|
||||
for (d = pacc->devices; d; d = d->next) {
|
||||
if (pci_filter_match(&f, d))
|
||||
return d;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int gtfpga_mmap(struct node *n)
|
||||
{
|
||||
struct gtfpga *g = n->gtfpga;
|
||||
|
||||
int fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (!fd)
|
||||
serror("Failed open()");
|
||||
|
||||
long int addr = g->dev->base_addr[GTFPGA_BAR] & ~0xfff;
|
||||
int size = g->dev->size[GTFPGA_BAR];
|
||||
|
||||
/* mmap() first BAR */
|
||||
printf("mmap(NULL, %#x, PROT_READ | PROT_WRITE, MAP_SHARED, %u, %#lx)", size, fd, addr);
|
||||
void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr);
|
||||
if (map == MAP_FAILED)
|
||||
serror("Failed mmap()");
|
||||
}
|
||||
|
||||
int gtfpga_open(struct node *n)
|
||||
{
|
||||
struct gtfpga *g = n->gtfpga;
|
||||
struct pci_dev *dev;
|
||||
|
||||
int ret;
|
||||
|
||||
dev = gtfpga_find_device(g->filter);
|
||||
if (!dev)
|
||||
error("No GTFPGA card detected");
|
||||
|
||||
g->dev = dev;
|
||||
|
||||
ret = gtfpga_load_driver(dev);
|
||||
if (ret)
|
||||
error("Failed to load and bind driver (uio_pci_generic)");
|
||||
|
||||
ret = gtfpga_mmap(g);
|
||||
if (ret)
|
||||
error("Failed to setup memory mapping for GTFGPA card");
|
||||
|
||||
/* Show some debug infos */
|
||||
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
|
||||
|
||||
debug(3, "Found GTFPGA card: %04x:%02x:%02x.%d vendor=%04x device=%04x class=%04x irq=%d",
|
||||
dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id,
|
||||
dev->device_class, dev->irq);
|
||||
|
||||
debug(3, " (%s)\n", pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gtfpga_close(struct node *n)
|
||||
{
|
||||
struct gtfpga *g = n->gtfpga;
|
||||
|
||||
if (g->map)
|
||||
munmap(g->map, g->dev->size[GTFPGA_BAR]);
|
||||
|
||||
close(g->fd_mmap);
|
||||
close(g->fd_uio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @todo implement */
|
||||
int gtfpga_read(struct node *n, struct msg *m)
|
||||
{
|
||||
struct gtfpga *g = n->gtfpga;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @todo implement */
|
||||
int gtfpga_write(struct node *n, struct msg *m)
|
||||
{
|
||||
struct gtfpga *g = n->gtfpga;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,25 +95,24 @@ double hist_stddev(struct hist *h)
|
|||
|
||||
void hist_print(struct hist *h)
|
||||
{ INDENT
|
||||
char buf[h->length * 8];
|
||||
hist_dump(h, buf, sizeof(buf));
|
||||
|
||||
info("Total: %u values between %f and %f", h->total, h->low, h->high);
|
||||
info("Missed: %u (above), %u (below) ", h->higher, h->lower);
|
||||
info("Highest value: %f, lowest %f", h->highest, h->lowest);
|
||||
info("Mean: %f", hist_mean(h));
|
||||
info("Variance: %f", hist_var(h));
|
||||
info("Standard derivation: %f", hist_stddev(h));
|
||||
|
||||
|
||||
hist_plot(h);
|
||||
|
||||
char buf[h->length * 8];
|
||||
hist_dump(h, buf, sizeof(buf));
|
||||
|
||||
info("hist = %s", buf);
|
||||
info(buf);
|
||||
}
|
||||
|
||||
void hist_plot(struct hist *h)
|
||||
{
|
||||
unsigned min = UINT_MAX;
|
||||
unsigned max = 0;
|
||||
char buf[HIST_HEIGHT] = { '#' };
|
||||
unsigned int min = UINT_MAX, max = 0;
|
||||
|
||||
/* Get max, first & last */
|
||||
for (int i = 0; i < h->length; i++) {
|
||||
|
@ -123,9 +122,6 @@ void hist_plot(struct hist *h)
|
|||
min = h->data[i];
|
||||
}
|
||||
|
||||
char buf[HIST_HEIGHT];
|
||||
memset(buf, '#', HIST_HEIGHT);
|
||||
|
||||
/* Print plot */
|
||||
info("%9s | %5s | %s", "Value", "Occur", "Histogram Plot:");
|
||||
for (int i = 0; i < h->length; i++) {
|
||||
|
@ -139,17 +135,14 @@ void hist_plot(struct hist *h)
|
|||
|
||||
void hist_dump(struct hist *h, char *buf, int len)
|
||||
{
|
||||
char tok[8];
|
||||
memset(buf, 0, len);
|
||||
*buf = 0;
|
||||
|
||||
strncat(buf, "[ ", len);
|
||||
strap(buf, len, "[ ");
|
||||
|
||||
for (int i = 0; i < h->length; i++) {
|
||||
snprintf(tok, sizeof(tok), "%u ", h->data[i]);
|
||||
strncat(buf, tok, len - strlen(buf));
|
||||
}
|
||||
|
||||
strncat(buf, "]", len - strlen(buf));
|
||||
for (int i = 0; i < h->length; i++)
|
||||
strap(buf, len, "%u ", h->data[i]);
|
||||
|
||||
strap(buf, len, "]");
|
||||
}
|
||||
|
||||
void hist_matlab(struct hist *h, FILE *f)
|
||||
|
|
|
@ -65,8 +65,6 @@ int hook_log(struct msg *m, struct path *p)
|
|||
localtime_r(&ts, &tm);
|
||||
strftime(fstr, sizeof(fstr), HOOK_LOG_TEMPLATE, &tm);
|
||||
|
||||
|
||||
|
||||
file = fopen(fstr, HOOK_LOG_MODE);
|
||||
if (file)
|
||||
debug(5, "Opened log file for path %s: %s", pstr, fstr);
|
||||
|
|
123
server/src/log.c
123
server/src/log.c
|
@ -4,20 +4,25 @@
|
|||
* @copyright 2015, Institute for Automation of Complex Power Systems, EONERC
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
int _debug = V;
|
||||
/** 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 configuration file.
|
||||
*/
|
||||
static int level = V;
|
||||
|
||||
/** A global clock used to prefix the log messages. */
|
||||
static struct timespec epoch;
|
||||
|
||||
#ifdef __GNUC__
|
||||
/** The current log indention level (per thread!). */
|
||||
static __thread int indent = 0;
|
||||
|
||||
/** Get thread-specific pointer to indent level */
|
||||
int log_indent(int levels)
|
||||
{
|
||||
int old = indent;
|
||||
|
@ -31,41 +36,47 @@ void log_outdent(int *old)
|
|||
}
|
||||
#endif
|
||||
|
||||
void log_setlevel(int lvl)
|
||||
{
|
||||
level = lvl;
|
||||
debug(10, "Switched to debug level %u", level);
|
||||
}
|
||||
|
||||
void log_reset()
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, &epoch);
|
||||
debug(10, "Debug clock resetted");
|
||||
}
|
||||
|
||||
void log_print(enum log_level lvl, const char *fmt, ...)
|
||||
void log_print(const char *lvl, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
log_vprint(lvl, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_vprint(const char *lvl, const char *fmt, va_list ap)
|
||||
{
|
||||
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));
|
||||
strap(buf, sizeof(buf), "%10.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;
|
||||
}
|
||||
|
||||
strap(buf, sizeof(buf), BLD("%-5s "), lvl);
|
||||
|
||||
/* Indention */
|
||||
#ifdef __GNUC__
|
||||
for (int i = 0; i < indent; i++)
|
||||
strap(buf, sizeof(buf), GFX("\x78") " ");
|
||||
strap(buf, sizeof(buf), GFX("\x74") " ");
|
||||
strap(buf, sizeof(buf), ACS_VERTICAL " ");
|
||||
strap(buf, sizeof(buf), ACS_VERTRIGHT " ");
|
||||
#endif
|
||||
|
||||
/* Format String */
|
||||
va_start(ap, fmt);
|
||||
vstrap(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Output */
|
||||
#ifdef ENABLE_OPAL_ASYNC
|
||||
|
@ -73,3 +84,79 @@ void log_print(enum log_level lvl, const char *fmt, ...)
|
|||
#endif
|
||||
fprintf(stderr, "\r%s\n", buf);
|
||||
}
|
||||
|
||||
/** Printf alike debug message with level. */
|
||||
void debug(int lvl, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (lvl <= level) {
|
||||
va_start(ap, fmt);
|
||||
log_vprint(DEBUG, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
/** Printf alike info message. */
|
||||
void info(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_vprint(INFO, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/** Printf alike warning message. */
|
||||
void warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_vprint(WARN, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/** Print error and exit. */
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_vprint(ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/** Print error and strerror(errno). */
|
||||
void serror(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
log_print(ERROR, "%s: %s", buf, strerror(errno));
|
||||
die();
|
||||
}
|
||||
|
||||
/** Print configuration error and exit. */
|
||||
void cerror(config_setting_t *cfg, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
log_print(ERROR, "%s in %s:%u", buf,
|
||||
config_setting_source_file(cfg)
|
||||
? config_setting_source_file(cfg)
|
||||
: "(stdio)",
|
||||
config_setting_source_line(cfg));
|
||||
die();
|
||||
}
|
|
@ -18,17 +18,24 @@
|
|||
#include "opal.h"
|
||||
#endif
|
||||
|
||||
#define VTABLE(type, name, fnc) { type, name, config_parse_ ## fnc, \
|
||||
fnc ## _print, \
|
||||
fnc ## _open, \
|
||||
fnc ## _close, \
|
||||
fnc ## _read, \
|
||||
fnc ## _write }
|
||||
#define VTABLE(type, name, fnc) { type, name, \
|
||||
fnc ## _parse, fnc ## _print, \
|
||||
fnc ## _open, fnc ## _close, \
|
||||
fnc ## _read, fnc ## _write }
|
||||
|
||||
#define VTABLE2(type, name, fnc) { type, name, \
|
||||
fnc ## _parse, fnc ## _print, \
|
||||
fnc ## _open, fnc ## _close, \
|
||||
fnc ## _read, fnc ## _write, \
|
||||
fnc ## _init, fnc ## _deinit }
|
||||
|
||||
/** Vtable for virtual node sub types */
|
||||
static const struct node_vtable vtables[] = {
|
||||
struct node_vtable vtables[] = {
|
||||
#ifdef ENABLE_OPAL_ASYNC
|
||||
VTABLE(OPAL_ASYNC, "opal", opal),
|
||||
VTABLE2(OPAL_ASYNC, "opal", opal),
|
||||
#endif
|
||||
#ifdef ENABLE_GTFPGA
|
||||
VTABLE2(GTFPGA, "gtfpga", gtfpga),
|
||||
#endif
|
||||
VTABLE(LOG_FILE, "file", file),
|
||||
VTABLE(IEEE_802_3, "ieee802.3", socket),
|
||||
|
@ -41,6 +48,37 @@ static const struct node_vtable vtables[] = {
|
|||
/** Linked list of nodes. */
|
||||
struct list nodes;
|
||||
|
||||
int node_init(int argc, char *argv[])
|
||||
{ INDENT
|
||||
for (int i=0; i<ARRAY_LEN(vtables); i++) {
|
||||
const struct node_vtable *vt = &vtables[i];
|
||||
if (vt->refcnt && vt->init) {
|
||||
if (vt->init(argc, argv))
|
||||
error("Failed to initialize '%s' node type", vt->name);
|
||||
else
|
||||
info("Initializing '%s' node type", vt->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int node_deinit()
|
||||
{ INDENT
|
||||
/* De-initialize node types */
|
||||
for (int i=0; i<ARRAY_LEN(vtables); i++) {
|
||||
struct node_vtable *vt = &vtables[i];
|
||||
if (vt->refcnt && vt->deinit) {
|
||||
if (vt->deinit())
|
||||
error("Failed to de-initialize '%s' node type", vt->name);
|
||||
else
|
||||
info("De-initializing '%s' node type", vt->name);
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct node * node_lookup_name(const char *str, struct list *nodes)
|
||||
{
|
||||
FOREACH(nodes, it) {
|
||||
|
@ -51,7 +89,7 @@ struct node * node_lookup_name(const char *str, struct list *nodes)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct node_vtable const * node_lookup_vtable(const char *str)
|
||||
struct node_vtable * node_lookup_vtable(const char *str)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_LEN(vtables); i++) {
|
||||
if (!strcmp(vtables[i].name, str))
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
#include "opal.h"
|
||||
#include "utils.h"
|
||||
|
||||
/** @todo: delcare statice */
|
||||
struct opal_global *og = NULL;
|
||||
static struct opal_global *og = NULL;
|
||||
|
||||
int opal_init(int argc, char *argv[])
|
||||
{
|
||||
|
@ -112,6 +111,40 @@ int opal_print_global(struct opal_global *g)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int opal_parse(config_setting_t *cfg, struct node *n)
|
||||
{
|
||||
if (!og) {
|
||||
warn("Skipping node '%s', because this server is not running as an OPAL Async process!", n->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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->recv_id);
|
||||
config_setting_lookup_bool(cfg, "reply", &o->reply);
|
||||
|
||||
/* Search for valid send and recv ids */
|
||||
int sfound = 0, rfound = 0;
|
||||
for (int i=0; i<og->send_icons; i++)
|
||||
sfound += og->send_ids[i] == o->send_id;
|
||||
for (int i=0; i<og->send_icons; i++)
|
||||
rfound += og->send_ids[i] == o->send_id;
|
||||
|
||||
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, "recv_id"),
|
||||
"Invalid recv_id '%u' for node '%s'", o->recv_id, n->name);
|
||||
|
||||
n->opal = o;
|
||||
n->opal->global = og;
|
||||
n->cfg = cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opal_print(struct node *n, char *buf, int len)
|
||||
{
|
||||
struct opal *o = n->opal;
|
||||
|
|
|
@ -51,15 +51,13 @@ static void quit()
|
|||
FOREACH(&interfaces, it)
|
||||
if_stop(it->interface);
|
||||
|
||||
#ifdef ENABLE_OPAL_ASYNC
|
||||
opal_deinit();
|
||||
#endif
|
||||
|
||||
/* Freeing dynamically allocated memory */
|
||||
list_destroy(&paths);
|
||||
list_destroy(&nodes);
|
||||
list_destroy(&interfaces);
|
||||
config_destroy(&config);
|
||||
|
||||
node_deinit();
|
||||
|
||||
info("Goodbye!");
|
||||
|
||||
|
@ -89,7 +87,7 @@ void realtime_init()
|
|||
|
||||
/* Setup exit handler */
|
||||
void signals_init()
|
||||
{ INDENT
|
||||
{
|
||||
struct sigaction sa_quit = {
|
||||
.sa_flags = SA_SIGINFO,
|
||||
.sa_sigaction = quit
|
||||
|
@ -129,9 +127,12 @@ int main(int argc, char *argv[])
|
|||
if (argc != 2)
|
||||
#endif
|
||||
usage(argv[0]);
|
||||
|
||||
char *configfile = (argc == 2) ? argv[1] : "opal-shmem.conf";
|
||||
|
||||
info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s, debug=%d)",
|
||||
BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)), _debug);
|
||||
log_reset();
|
||||
info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s)",
|
||||
BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)));
|
||||
|
||||
/* Check priviledges */
|
||||
if (getuid() != 0)
|
||||
|
@ -141,28 +142,18 @@ int main(int argc, char *argv[])
|
|||
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:");
|
||||
|
||||
info("Initialize real-time system:");
|
||||
realtime_init();
|
||||
|
||||
info("Setup signals:");
|
||||
info("Initialize signals:");
|
||||
signals_init();
|
||||
|
||||
info("Initialize node types:");
|
||||
node_init(argc, argv);
|
||||
|
||||
info("Parsing configuration:");
|
||||
config_init(&config);
|
||||
|
||||
#ifdef ENABLE_OPAL_ASYNC
|
||||
/* 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 */
|
||||
config_parse(configfile, &config, &settings, &nodes, &paths);
|
||||
|
||||
/* Connect all nodes and start one thread per path */
|
||||
|
|
|
@ -172,6 +172,42 @@ int socket_write(struct node *n, struct msg *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int socket_parse(config_setting_t *cfg, struct node *n)
|
||||
{
|
||||
const char *local, *remote;
|
||||
int ret;
|
||||
|
||||
struct socket *s = alloc(sizeof(struct socket));
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "remote", &remote))
|
||||
cerror(cfg, "Missing remote address for node '%s'", n->name);
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "local", &local))
|
||||
cerror(cfg, "Missing local address for node '%s'", n->name);
|
||||
|
||||
ret = socket_parse_addr(local, (struct sockaddr *) &s->local, node_type(n), AI_PASSIVE);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to resolve local address '%s' of node '%s': %s",
|
||||
local, n->name, gai_strerror(ret));
|
||||
|
||||
ret = socket_parse_addr(remote, (struct sockaddr *) &s->remote, node_type(n), 0);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to resolve remote address '%s' of node '%s': %s",
|
||||
remote, n->name, gai_strerror(ret));
|
||||
|
||||
/** @todo Netem settings are not usable AF_UNIX */
|
||||
config_setting_t *cfg_netem = config_setting_get_member(cfg, "netem");
|
||||
if (cfg_netem) {
|
||||
s->netem = alloc(sizeof(struct netem));
|
||||
|
||||
tc_parse(cfg_netem, s->netem);
|
||||
}
|
||||
|
||||
n->socket = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_print_addr(char *buf, int len, struct sockaddr *sa)
|
||||
{
|
||||
switch (sa->sa_family) {
|
||||
|
|
|
@ -14,6 +14,28 @@
|
|||
#include "if.h"
|
||||
#include "tc.h"
|
||||
|
||||
int tc_parse(config_setting_t *cfg, struct netem *em)
|
||||
{
|
||||
em->valid = 0;
|
||||
|
||||
if (config_setting_lookup_string(cfg, "distribution", &em->distribution))
|
||||
em->valid |= TC_NETEM_DISTR;
|
||||
if (config_setting_lookup_int(cfg, "delay", &em->delay))
|
||||
em->valid |= TC_NETEM_DELAY;
|
||||
if (config_setting_lookup_int(cfg, "jitter", &em->jitter))
|
||||
em->valid |= TC_NETEM_JITTER;
|
||||
if (config_setting_lookup_int(cfg, "loss", &em->loss))
|
||||
em->valid |= TC_NETEM_LOSS;
|
||||
if (config_setting_lookup_int(cfg, "duplicate", &em->duplicate))
|
||||
em->valid |= TC_NETEM_DUPL;
|
||||
if (config_setting_lookup_int(cfg, "corrupt", &em->corrupt))
|
||||
em->valid |= TC_NETEM_CORRUPT;
|
||||
|
||||
/** @todo Validate netem config values */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tc_reset(struct interface *i)
|
||||
{
|
||||
char cmd[128];
|
||||
|
|
|
@ -101,16 +101,15 @@ struct timespec timespec_rate(double rate)
|
|||
/** @todo: Proper way: create additional pipe for stderr in child process */
|
||||
int system2(const char *cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, cmd);
|
||||
|
||||
vsnprintf(buf, sizeof(buf), cmd, ap);
|
||||
strncat(buf, " 2>&1", sizeof(buf));
|
||||
|
||||
vsnprintf(buf, sizeof(buf), cmd, ap);
|
||||
va_end(ap);
|
||||
|
||||
strap(buf, sizeof(buf), " 2>&1", sizeof(buf)); /* redirect stderr to stdout */
|
||||
|
||||
debug(1, "System: %s", buf);
|
||||
|
||||
FILE *f = popen(buf, "r");
|
||||
|
|
Loading…
Add table
Reference in a new issue