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

replaced libconfig by jansson for parsing the configuration (huge commit)

This commit is contained in:
Steffen Vogel 2017-08-03 00:19:27 +02:00
parent 0f6aaafeb6
commit 434fe6dbd6
80 changed files with 1471 additions and 987 deletions

View file

@ -33,5 +33,12 @@ json_t * config_to_json(config_setting_t *cfg);
/* Convert a jansson object into a libconfig object. */
int json_to_config(json_t *json, config_setting_t *parent);
/* Create a libconfig object from command line parameters. */
int config_read_cli(config_t *cfg, int argc, char *argv[]);
/* Create a JSON object from command line parameters. */
json_t * json_load_cli(int argc, char *argv[]);
int json_object_extend_str(json_t *orig, const char *str);
void json_object_extend_key_value(json_t *obj, const char *key, const char *value);
/* Merge two JSON objects recursively. */
int json_object_extend(json_t *orig, json_t *merge);

View file

@ -29,8 +29,6 @@
#pragma once
#include <libconfig.h>
#include "common.h"
#include "kernel/pci.h"
#include "kernel/vfio.h"
@ -70,9 +68,9 @@ struct fpga_card {
int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc);
/** Parse configuration of FPGA card including IP cores from config. */
int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg);
int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name);
int fpga_card_parse_list(struct list *l, config_setting_t *cfg);
int fpga_card_parse_list(struct list *l, json_t *cfg);
/** Check if the FPGA card configuration is plausible. */
int fpga_card_check(struct fpga_card *c);

View file

@ -30,7 +30,6 @@
#pragma once
#include <stdint.h>
#include <libconfig.h>
#include "common.h"
@ -60,7 +59,7 @@ struct fpga_ip_type {
enum fpga_ip_types type;
int (*init)(struct fpga_ip *c);
int (*parse)(struct fpga_ip *c);
int (*parse)(struct fpga_ip *c, json_t *cfg);
int (*check)(struct fpga_ip *c);
int (*start)(struct fpga_ip *c);
int (*stop)(struct fpga_ip *c);
@ -93,7 +92,7 @@ struct fpga_ip {
int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt);
/** Parse IP core configuration from configuration file */
int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg);
int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name);
/** Check configuration of IP core. */
int fpga_ip_check(struct fpga_ip *c);

View file

@ -25,7 +25,7 @@ struct dft {
int decimation;
};
int dft_parse(struct fpga_ip *c);
int dft_parse(struct fpga_ip *c, json_t *cfg);
int dft_start(struct fpga_ip *c);

View file

@ -33,20 +33,20 @@ enum model_xsg_block_type {
XSG_BLOCK_INFO = 0x2000
};
enum model_param_type {
MODEL_PARAM_TYPE_UFIX,
MODEL_PARAM_TYPE_FIX,
MODEL_PARAM_TYPE_FLOAT,
MODEL_PARAM_TYPE_BOOLEAN
enum model_parameter_type {
MODEL_PARAMETER_TYPE_UFIX,
MODEL_PARAMETER_TYPE_FIX,
MODEL_PARAMETER_TYPE_FLOAT,
MODEL_PARAMETER_TYPE_BOOLEAN
};
enum model_param_direction {
MODEL_PARAM_IN,
MODEL_PARAM_OUT,
MODEL_PARAM_INOUT
enum model_parameter_direction {
MODEL_PARAMETER_IN,
MODEL_PARAMETER_OUT,
MODEL_PARAMETER_INOUT
};
union model_param_value {
union model_parameter_value {
uint32_t ufix;
int32_t fix;
float flt;
@ -75,16 +75,16 @@ struct model_info {
char *value;
};
struct model_param {
struct model_parameter {
char *name; /**< Name of the parameter */
enum model_param_direction direction; /**< Read / Write / Read-write? */
enum model_param_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */
enum model_parameter_direction direction; /**< Read / Write / Read-write? */
enum model_parameter_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */
int binpt; /**< Binary point for type == MODEL_GW_TYPE_(U)FIX */
uintptr_t offset; /**< Register offset to model::baseaddress */
union model_param_value default_value;
union model_parameter_value default_value;
struct fpga_ip *ip; /**< A pointer to the model structure to which this parameters belongs to. */
};
@ -93,7 +93,7 @@ struct model_param {
int model_init(struct fpga_ip *c);
/** Parse model */
int model_parse(struct fpga_ip *c);
int model_parse(struct fpga_ip *c, json_t *cfg);
/** Destroy a model */
int model_destroy(struct fpga_ip *c);
@ -102,17 +102,17 @@ int model_destroy(struct fpga_ip *c);
void model_dump(struct fpga_ip *c);
/** Add a new parameter to the model */
void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direction dir, enum model_param_type type);
void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type);
/** Remove an existing parameter by its name */
int model_param_remove(struct fpga_ip *c, const char *name);
int model_parameter_remove(struct fpga_ip *c, const char *name);
/** Read a model parameter.
*
* Note: the data type of the register is taken into account.
* All datatypes are converted to double.
*/
int model_param_read(struct model_param *p, double *v);
int model_parameter_read(struct model_parameter *p, double *v);
/** Update a model parameter.
*
@ -120,8 +120,8 @@ int model_param_read(struct model_param *p, double *v);
* The double argument will be converted to the respective data type of the
* GatewayIn/Out block.
*/
int model_param_write(struct model_param *p, double v);
int model_parameter_write(struct model_parameter *p, double v);
int model_param_update(struct model_param *p, struct model_param *u);
int model_parameter_update(struct model_parameter *p, struct model_parameter *u);
/** @} */

View file

@ -13,6 +13,7 @@
#pragma once
#include <jansson.h>
#include <xilinx/xaxis_switch.h>
#include "list.h"
@ -41,7 +42,7 @@ int switch_init_paths(struct fpga_ip *c);
int switch_destroy(struct fpga_ip *c);
int switch_parse(struct fpga_ip *c);
int switch_parse(struct fpga_ip *c, json_t *cfg);
int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si);

View file

@ -93,12 +93,8 @@ char * hist_dump(struct hist *h);
/** Prints Matlab struct containing all infos to file. */
int hist_dump_matlab(struct hist *h, FILE *f);
#ifdef WITH_JSON
/** Write the histogram in JSON format to fiel \p f. */
int hist_dump_json(struct hist *h, FILE *f);
/** Build a libjansson / JSON object of the histogram. */
json_t * hist_json(struct hist *h);
#endif /* WITH_JSON */

View file

@ -52,21 +52,13 @@ struct hook {
void *_vd; /**< Private data for this hook. This pointer can be used to pass data between consecutive calls of the callback. */
int priority; /**< A priority to change the order of execution within one type of hook. */
json_t *cfg; /**< A JSON object containing the configuration of the hook. */
};
/** Save references to global nodes, paths and settings */
int hook_init(struct hook *h, struct hook_type *vt, struct path *p);
/** Parse a single hook.
*
* A hook definition is composed of the hook name and optional parameters
* seperated by a colon.
*
* Examples:
* "print:stdout"
*/
int hook_parse(struct hook *h, config_setting_t *cfg);
int hook_parse(struct hook *h, json_t *cfg);
int hook_parse_cli(struct hook *h, int argc, char *argv[]);
int hook_destroy(struct hook *h);
@ -100,4 +92,4 @@ int hook_cmp_priority(const void *a, const void *b);
* hooks = [ "print" ]
* }
*/
int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *p);
int hook_parse_list(struct list *list, json_t *cfg, struct path *p);

View file

@ -37,7 +37,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <libconfig.h>
#include <jansson.h>
/* Forward declarations */
struct hook;
@ -49,7 +49,7 @@ struct hook_type {
size_t size; /**< Size of allocation for struct hook::_vd */
int (*parse)(struct hook *h, config_setting_t *cfg);
int (*parse)(struct hook *h, json_t *cfg);
int (*parse_cli)(struct hook *h, int argc, char *argv[]);
int (*init)(struct hook *h); /**< Called before path is started to parseHOOK_DESTROYs. */

View file

@ -35,7 +35,7 @@
#include <netlink/route/qdisc.h>
#include <netlink/route/classifier.h>
#include <libconfig.h>
#include <jansson.h>
typedef uint32_t tc_hdl_t;
@ -43,12 +43,12 @@ struct interface;
/** Parse network emulator (netem) settings.
*
* @param cfg A libconfig object containing the settings.
* @param cfg A jansson object containing the settings.
* @param[out] ne A pointer to a libnl3 qdisc object where setting will be written to.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **ne);
int tc_parse(struct rtnl_qdisc **ne, json_t *cfg);
/** Print network emulator (netem) setting into buffer.
*

View file

@ -1,4 +1,4 @@
/** Logging routines that depend on libconfig.
/** Logging routines that depend on jansson.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
@ -25,14 +25,13 @@
struct log;
#include <libconfig.h>
#include <jansson.h>
#include "log.h"
/** Parse logging configuration. */
int log_parse(struct log *l, config_setting_t *cfg);
int log_parse(struct log *l, json_t *cfg);
/** Print configuration error and exit. */
void cerror(config_setting_t *cfg, const char *fmt, ...)
void jerror(json_error_t *err, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));

View file

@ -23,7 +23,7 @@
#pragma once
#include <libconfig.h>
#include <jansson.h>
#include "stats.h"
#include "common.h"
@ -87,7 +87,7 @@ struct mapping {
int mapping_init(struct mapping *m);
int mapping_parse(struct mapping *m, config_setting_t *cfg);
int mapping_parse(struct mapping *m, json_t *cfg);
int mapping_check(struct mapping *m);
@ -95,6 +95,6 @@ int mapping_destroy(struct mapping *m);
int mapping_remap(struct mapping *m, struct sample *orig, struct sample *remapped, struct stats *s);
int mapping_entry_parse(struct mapping_entry *e, config_setting_t *cfg);
int mapping_entry_parse(struct mapping_entry *e, json_t *cfg);
int mapping_entry_parse_str(struct mapping_entry *e, const char *str);

View file

@ -28,7 +28,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <libconfig.h>
#include <jansson.h>
#include "node_type.h"
#include "sample.h"
@ -58,17 +58,19 @@ struct node
struct node_type *_vt; /**< Virtual functions (C++ OOP style) */
void *_vd; /**< Virtual data (used by struct node::_vt functions) */
json_t *cfg; /**< A JSON object containing the configuration of the node. */
};
int node_init(struct node *n, struct node_type *vt);
/** Parse settings of a node.
*
* @param cfg A libconfig object pointing to the node.
* @param cfg A JSON object containing the configuration of the node.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int node_parse(struct node *n, config_setting_t *cfg);
int node_parse(struct node *n, json_t *cfg, const char *name);
/** Parse settings of a node from cmdline. */
int node_parse_cli(struct node *n, int argc, char *argv[]);
@ -128,10 +130,10 @@ int node_write(struct node *n, struct sample *smps[], unsigned cnt);
* out = [ "sintef", "scedu" ]
* out = "acs"
*
* @param cfg The libconfig object handle for "out".
* @param cfg A JSON array or string. See examples above.
* @param nodes The nodes will be added to this list.
* @param all This list contains all valid nodes.
*/
int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all);
int node_parse_list(struct list *list, json_t *cfg, struct list *all);
/** @} */

View file

@ -26,7 +26,7 @@
#pragma once
#include <libconfig.h>
#include <jansson.h>
#include "list.h"
#include "common.h"
@ -78,11 +78,11 @@ struct node_type {
/** Parse node connection details.
*
* @param n A pointer to the node object.
* @param cfg A libconfig object pointing to the node.
* @param cfg A JSON object containing the configuration of the node.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int (*parse)(struct node *n, config_setting_t *cfg);
int (*parse)(struct node *n, json_t *cfg);
/** Parse node from command line arguments. */
int (*parse_cli)(struct node *n, int argc, char *argv[]);
@ -118,10 +118,10 @@ struct node_type {
* Indexes used to address @p m will wrap around after len messages.
* Some node-types might only support to receive one message at a time.
*
* @param n A pointer to the node object.
* @param smps An array of pointers to memory blocks where the function should store received samples.
* @param cnt The number of messages which should be received.
* @return The number of messages actually received.
* @param n A pointer to the node object.
* @param smps An array of pointers to memory blocks where the function should store received samples.
* @param cnt The number of messages which should be received.
* @return The number of messages actually received.
*/
int (*read) (struct node *n, struct sample *smps[], unsigned cnt);
@ -132,10 +132,10 @@ struct node_type {
* The messages have to be stored in a circular buffer / array m.
* So the indexes will wrap around after len.
*
* @param n A pointer to the node object.
* @param smps An array of pointers to memory blocks where samples read from.
* @param cnt The number of messages which should be sent.
* @return The number of messages actually sent.
* @param n A pointer to the node object.
* @param smps An array of pointers to memory blocks where samples read from.
* @param cnt The number of messages which should be sent.
* @return The number of messages actually sent.
*/
int (*write)(struct node *n, struct sample *smps[], unsigned cnt);
@ -143,7 +143,7 @@ struct node_type {
*
* This is not supported by all node-types!
*
* @param n A pointer to the node object.
* @param n A pointer to the node object.
*/
int (*reverse)(struct node *n);
};

View file

@ -46,7 +46,7 @@ struct file {
AFILE *handle; /**< libc: stdio file handle. */
const char *mode; /**< libc: fopen() mode. */
const char *fmt; /**< Format string for file name. */
const char *format; /**< Format string for file name. */
char *uri; /**< Real file name. */
} read, write;
@ -78,7 +78,7 @@ struct file {
char * file_print(struct node *n);
/** @see node_type::parse */
int file_parse(struct node *n, config_setting_t *cfg);
int file_parse(struct node *n, json_t *cfg);
/** @see node_type::open */
int file_start(struct node *n);

View file

@ -44,7 +44,7 @@ int fpga_init(struct super_node *sn);
int fpga_deinit();
/** @see node_type::parse */
int fpga_parse(struct node *n, config_setting_t *cfg);
int fpga_parse(struct node *n, json_t *cfg);
struct fpga_card * fpga_lookup_card(const char *name);

View file

@ -29,8 +29,6 @@
#pragma once
#include <libconfig.h>
#include "queue_signalled.h"
#include "pool.h"
@ -53,7 +51,7 @@ struct loopback {
char * loopback_print(struct node *n);
/** @see node_type::parse */
int loopback_parse(struct node *n, config_setting_t *cfg);
int loopback_parse(struct node *n, json_t *cfg);
/** @see node_type::open */
int loopback_open(struct node *n);

View file

@ -50,7 +50,7 @@ struct nanomsg {
char * nanomsg_print(struct node *n);
/** @see node_type::parse */
int nanomsg_parse(struct node *n, config_setting_t *cfg);
int nanomsg_parse(struct node *n, json_t *cfg);
/** @see node_type::open */
int nanomsg_start(struct node *n);

View file

@ -39,7 +39,6 @@
#include <jansson.h>
#include "list.h"
#include "msg.h"
#include "super_node.h"
#include "node.h"
@ -77,7 +76,7 @@ int ngsi_init(struct super_node *sn);
int ngsi_deinit();
/** @see node_type::parse */
int ngsi_parse(struct node *n, config_setting_t *cfg);
int ngsi_parse(struct node *n, json_t *cfg);
/** @see node_type::print */
char * ngsi_print(struct node *n);

View file

@ -67,7 +67,7 @@ int opal_init(struct super_node *sn);
int opal_deinit();
/** @see node_type::parse */
int opal_parse(struct node *n, config_setting_t *cfg);
int opal_parse(struct node *n, json_t *cfg);
/** @see node_type::print */
char * opal_print(struct node *n);

View file

@ -51,7 +51,7 @@ struct shmem {
char * shmem_print(struct node *n);
/** @see node_type::parse */
int shmem_parse(struct node *n, config_setting_t *cfg);
int shmem_parse(struct node *n, json_t *cfg);
/** @see node_type::open */
int shmem_open(struct node *n);

View file

@ -29,8 +29,6 @@
#pragma once
#include <libconfig.h>
#include "timing.h"
/* Forward declarations */
@ -71,7 +69,7 @@ struct signal {
char * signal_print(struct node *n);
/** @see node_type::parse */
int signal_parse(struct node *n, config_setting_t *cfg);
int signal_parse(struct node *n, json_t *cfg);
/** @see node_type::open */
int signal_open(struct node *n);

View file

@ -112,7 +112,7 @@ int socket_write(struct node *n, struct sample *smps[], unsigned cnt);
int socket_read(struct node *n, struct sample *smps[], unsigned cnt);
/** @see node_type::parse */
int socket_parse(struct node *n, config_setting_t *cfg);
int socket_parse(struct node *n, json_t *cfg);
/** @see node_type::print */
char * socket_print(struct node *n);

View file

@ -55,7 +55,7 @@ struct test_rtt {
char * test_rtt_print(struct node *n);
/** @see node_type::parse */
int test_rtt_parse(struct node *n, config_setting_t *cfg);
int test_rtt_parse(struct node *n, json_t *cfg);
/** @see node_type::open */
int test_rtt_start(struct node *n);

View file

@ -74,7 +74,7 @@ struct zeromq {
char * zeromq_print(struct node *n);
/** @see node_type::parse */
int zeromq_parse(struct node *n, config_setting_t *cfg);
int zeromq_parse(struct node *n, json_t *cfg);
/** @see node_type::init */
int zeromq_init();

View file

@ -30,7 +30,7 @@
#pragma once
#include <pthread.h>
#include <libconfig.h>
#include <jansson.h>
#include "list.h"
#include "queue.h"
@ -83,6 +83,8 @@ struct path
struct stats *stats; /**< Statistic counters. This is a pointer to the statistic hooks private data. */
struct super_node *super_node; /**< The super node this path belongs to. */
json_t *cfg; /**< A JSON object containing the configuration of the path. */
};
/** Initialize internal data structures. */
@ -140,12 +142,12 @@ int path_uses_node(struct path *p, struct node *n);
/** Parse a single path and add it to the global configuration.
*
* @param cfg A libconfig object pointing to the path
* @param cfg A JSON object containing the configuration of the path.
* @param p Pointer to the allocated memory for this path
* @param nodes A linked list of all existing nodes
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes);
int path_parse(struct path *p, json_t *cfg, struct list *nodes);
/** @} */

View file

@ -94,7 +94,7 @@ int plugin_init(struct plugin *p);
int plugin_destroy(struct plugin *p);
int plugin_parse(struct plugin *p, config_setting_t *cfg);
int plugin_parse(struct plugin *p, json_t *cfg);
int plugin_load(struct plugin *p);

View file

@ -25,6 +25,7 @@
#define _STATS_H_
#include <stdint.h>
#include <jansson.h>
#include "hist.h"
@ -73,11 +74,7 @@ void stats_collect(struct stats_delta *s, struct sample *smps[], size_t cnt);
int stats_commit(struct stats *s, struct stats_delta *d);
#ifdef WITH_JSON
#include <jansson.h>
json_t * stats_json(struct stats *s);
#endif
void stats_reset(struct stats *s);

View file

@ -1,8 +1,4 @@
/** Configuration file parser.
*
* The server program is configured by a single file.
* This config file is parsed with a third-party library:
* libconfig http://www.hyperrealm.com/libconfig/
/** The super node object holding the state of the application.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
@ -27,8 +23,6 @@
#pragma once
#include <libconfig.h>
#include "list.h"
#include "api.h"
#include "web.h"
@ -57,8 +51,7 @@ struct super_node {
enum state state;
config_t cfg; /**< Pointer to configuration file */
json_t *json; /**< JSON representation of the same config. */
json_t *cfg; /**< JSON representation of the configuration. */
};
/* Compatibility with libconfig < 1.5 */
@ -82,7 +75,7 @@ int super_node_parse_uri(struct super_node *sn, const char *uri);
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int super_node_parse(struct super_node *sn, config_setting_t *cfg);
int super_node_parse_json(struct super_node *sn, json_t *cfg);
/** Check validity of super node configuration. */
int super_node_check(struct super_node *sn);

View file

@ -23,7 +23,6 @@
#pragma once
#include <libconfig.h>
#include <pthread.h>
#include "common.h"
@ -60,4 +59,4 @@ int web_start(struct web *w);
int web_stop(struct web *w);
/** Parse HTTPd and WebSocket related options */
int web_parse(struct web *w, config_setting_t *lcs);
int web_parse(struct web *w, json_t *cfg);

View file

@ -26,7 +26,6 @@ LIB = $(BUILDDIR)/$(LIB_NAME).so.$(LIB_ABI_VERSION)
WITH_WEB ?= 1
WITH_API ?= 1
WITH_JSON ?= 1
# Object files for libvillas
LIB_SRCS += $(addprefix lib/kernel/, kernel.c rt.c) \
@ -46,12 +45,6 @@ endif
LIB_PKGS += openssl libcurl
ifeq ($(WITH_JSON),1)
LIB_SRCS += lib/formats/json.c
LIB_PKGS += jansson
LIB_CFLAGS += -DWITH_JSON
endif
ifeq ($(WITH_WEB),1)
-include lib/web/Makefile.inc
endif

View file

@ -20,10 +20,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###################################################################################
ifndef WITH_JSON
$(error API support requires JSON)
endif
LIB_SRCS += lib/api.c
LIB_SRCS += $(wildcard lib/api/*.c)

View file

@ -20,8 +20,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <libconfig.h>
#include "api.h"
#include "utils.h"
#include "plugin.h"
@ -30,9 +28,7 @@
static int api_config(struct api_action *h, json_t *args, json_t **resp, struct api_session *s)
{
config_setting_t *cfg_root = config_root_setting(&s->api->super_node->cfg);
*resp = cfg_root ? config_to_json(cfg_root) : json_object();
*resp = s->api->super_node->cfg;
return 0;
}

View file

@ -47,7 +47,7 @@ static int api_nodes(struct api_action *r, json_t *args, json_t **resp, struct a
/* Add all additional fields of node here.
* This can be used for metadata */
json_object_update(json_node, config_to_json(n->cfg));
json_object_update(json_node, n->cfg);
json_array_append_new(json_nodes, json_node);
}

View file

@ -47,7 +47,7 @@ static int api_paths(struct api_action *r, json_t *args, json_t **resp, struct a
/* Add all additional fields of node here.
* This can be used for metadata */
json_object_update(json_path, config_to_json(p->cfg));
json_object_update(json_path, p->cfg);
json_array_append_new(json_paths, json_path);
}

View file

@ -20,10 +20,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <string.h>
#include "config_helper.h"
#include "utils.h"
#ifdef WITH_JSON
#ifdef WITH_LIBCONFIG
static int json_to_config_type(int type)
{
switch (type) {
@ -139,24 +142,180 @@ int json_to_config(json_t *json, config_setting_t *parent)
return 0;
}
#endif /* WITH_JSON */
#endif /* WITH_LIBCONFIG */
int config_read_cli(config_t *cfg, int argc, char *argv[])
void json_object_extend_key_value(json_t *obj, const char *key, const char *value)
{
int ret;
char *str = NULL;
char *end, *cpy, *key1, *key2;
for (int i = 0; i < argc; i++)
str = strcatf(&str, "%s", argv[i]);
double real;
long integer;
if (!str)
return 0;
json_t *arr, *new, *existing, *subobj;
config_set_auto_convert(cfg, 1);
/* Is the key pointing to an object? */
subobj = obj;
cpy = strdup(key);
ret = config_read_string(cfg, str);
key1 = strtok(cpy, ".");
key2 = strtok(NULL, ".");
free(str);
while (key1 && key2) {
existing = json_object_get(subobj, key1);
if (existing)
subobj = existing;
else {
new = json_object();
json_object_set(subobj, key1, new);
return ret != CONFIG_TRUE;
subobj = new;
}
key1 = key2;
key2 = strtok(NULL, ".");
}
/* Try to parse as integer */
integer = strtol(value, &end, 0);
if (*end == 0) {
new = json_integer(integer);
goto success;
}
/* Try to parse as floating point */
real = strtod(value, &end);
if (*end == 0) {
new = json_real(real);
goto success;
}
/* Try to parse special types */
if (!strcmp(value, "true")) {
new = json_true();
goto success;
}
if (!strcmp(value, "false")) {
new = json_false();
goto success;
}
if (!strcmp(value, "null")) {
new = json_null();
goto success;
}
/* Fallback to string */
new = json_string(value);
success:
/* Does the key already exist?
* If yes, transform to array. */
existing = json_object_get(subobj, key1);
if (existing) {
if (json_is_array(existing))
arr = existing;
else {
arr = json_array();
json_object_set(subobj, key1, arr);
json_array_append(arr, existing);
}
json_array_append(arr, new);
}
else
json_object_set(subobj, key1, new);
}
json_t * json_load_cli(int argc, char *argv[])
{
char *opt;
char *key = NULL;
char *value = NULL;
char *sep, *cpy;
json_t *json = json_object();
for (int i = 1; i < argc; i++) {
opt = argv[i];
/* Long Option */
if (opt[0] == '-' && opt[1] == '-') {
/* Option without value? Abort. */
if (key != NULL)
return NULL;
key = opt + 2;
/* Does this option has the form "--option=value"? */
sep = strchr(key, '=');
if (sep) {
cpy = strdup(key);
key = strtok(cpy, "=");
value = strtok(NULL, "");
json_object_extend_key_value(json, key, value);
free(cpy);
key = NULL;
}
}
/* Value */
else {
/* Value without key. Abort. */
if (key == NULL)
return NULL;
value = opt;
json_object_extend_key_value(json, key, value);
key = NULL;
}
}
return json;
}
int json_object_extend(json_t *obj, json_t *merge)
{
const char *key;
void *tmp;
int ret;
json_t *merge_value, *obj_value;
if (!json_is_object(obj) || !json_is_object(merge))
return -1;
json_object_foreach_safe(merge, tmp, key, merge_value) {
obj_value = json_object_get(obj, key);
if (obj_value && json_is_object(obj_value))
ret = json_object_extend(obj_value, merge_value);
else
ret = json_object_set(obj, key, merge_value);
if (ret)
return ret;
}
return 0;
}
int json_object_extend_str(json_t *obj, const char *str)
{
char *key, *value, *cpy;
cpy = strdup(str);
key = strtok(cpy, "=");
value = strtok(NULL, "");
if (!key || !value)
return -1;
json_object_extend_key_value(obj, key, value);
free(cpy);
return 0;
}

View file

@ -55,48 +55,59 @@ int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *
return 0;
}
int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg)
int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name)
{
int ret;
const char *slot, *id, *err;
config_setting_t *cfg_ips, *cfg_slot, *cfg_id;
c->name = config_setting_name(cfg);
json_t *cfg_ips;
json_t *cfg_slot = NULL;
json_t *cfg_id = NULL;
json_error_t err;
config_setting_lookup_int(cfg, "affinity", &c->affinity);
config_setting_lookup_bool(cfg, "do_reset", &c->do_reset);
c->name = strdup(name);
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: b, s?: o, s?: o, s: o }"
"affinity", &c->affinity,
"do_reset", &c->do_reset,
"slot", &cfg_slot,
"id", &cfg_id,
"ips", &cfg_ips
);
if (ret)
jerror(&err, "Failed to parse FPGA vard configuration");
cfg_slot = config_setting_get_member(cfg, "slot");
if (cfg_slot) {
slot = config_setting_get_string(cfg_slot);
const char *err, *slot;
slot = json_string_value(cfg_slot);
if (slot) {
ret = pci_device_parse_slot(&c->filter, slot, &err);
if (ret)
cerror(cfg_slot, "Failed to parse PCI slot: %s", err);
error("Failed to parse PCI slot: %s", err);
}
else
cerror(cfg_slot, "PCI slot must be a string");
error("PCI slot must be a string");
}
cfg_id = config_setting_get_member(cfg, "id");
if (cfg_id) {
id = config_setting_get_string(cfg_id);
const char *err, *id;
id = json_string_value(cfg_id);
if (id) {
ret = pci_device_parse_id(&c->filter, (char*) id, &err);
if (ret)
cerror(cfg_id, "Failed to parse PCI id: %s", err);
error("Failed to parse PCI id: %s", err);
}
else
cerror(cfg_slot, "PCI ID must be a string");
error("PCI ID must be a string");
}
cfg_ips = config_setting_get_member(cfg, "ips");
if (!cfg_ips)
cerror(cfg, "FPGA configuration is missing ips section");
for (int i = 0; i < config_setting_length(cfg_ips); i++) {
config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
if (!json_is_object(cfg_ips))
error("FPGA card IPs section must be an object");
const char *name_ip;
json_t *cfg_ip;
json_object_foreach(cfg_ips, name_ip, cfg_ip) {
const char *vlnv;
struct fpga_ip_type *vt;
@ -104,45 +115,45 @@ int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg)
ip->card = c;
if (!config_setting_lookup_string(cfg, "vlnv", &vlnv))
cerror(cfg, "FPGA IP core %s is missing the VLNV identifier", c->name);
ret = json_unpack_ex(cfg_ip, &err, 0, "{ s: s }", "vlnv", &vlnv);
if (ret)
error("Failed to parse FPGA IP '%s' of card '%s'", name_ip, name);
vt = fpga_ip_type_lookup(vlnv);
if (!vt)
cerror(cfg, "FPGA IP core VLNV identifier '%s' is invalid", vlnv);
error("FPGA IP core VLNV identifier '%s' is invalid", vlnv);
ret = fpga_ip_init(ip, vt);
if (ret)
error("Failed to initalize FPGA IP core");
ret = fpga_ip_parse(ip, cfg_ip);
ret = fpga_ip_parse(ip, cfg_ip, name_ip);
if (ret)
cerror(cfg_ip, "Failed to parse FPGA IP core");
error("Failed to parse FPGA IP core");
list_push(&c->ips, ip);
}
c->cfg = cfg;
c->state = STATE_PARSED;
return 0;
}
int fpga_card_parse_list(struct list *cards, config_setting_t *cfg)
int fpga_card_parse_list(struct list *cards, json_t *cfg)
{
int ret;
if (!config_setting_is_group(cfg))
cerror(cfg, "FPGA configuration section must be a group");
for (int i = 0; i < config_setting_length(cfg); i++) {
config_setting_t *cfg_fpga = config_setting_get_elem(cfg, i);
if (!json_is_object(cfg))
error("FPGA card configuration section must be a JSON object");
const char *name;
json_t *cfg_fpga;
json_object_foreach(cfg, name, cfg_fpga) {
struct fpga_card *c = alloc(sizeof(struct fpga_card));
ret = fpga_card_parse(c, cfg_fpga);
ret = fpga_card_parse(c, cfg_fpga, name);
if (ret)
cerror(cfg_fpga, "Failed to parse FPGA card configuration");
error("Failed to parse FPGA card configuration");
list_push(cards, c);
}

View file

@ -20,8 +20,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <libconfig.h>
#include "log_config.h"
#include "log.h"
#include "plugin.h"
@ -46,34 +44,33 @@ int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt)
return ret;
}
int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg)
int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name)
{
int ret;
long long baseaddr;
int ret, baseaddr = -1;
assert(c->state != STATE_STARTED && c->state != STATE_DESTROYED);
c->cfg = cfg;
c->name = strdup(name);
c->baseaddr = -1;
c->irq = -1;
c->port = -1;
c->name = config_setting_name(cfg);
if (!c->name)
cerror(cfg, "IP is missing a name");
json_error_t err;
/* Common settings */
if (config_setting_lookup_int64(cfg, "baseaddr", &baseaddr))
c->baseaddr = baseaddr;
else
c->baseaddr = -1;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i, s?: i }",
"baseaddr", &baseaddr,
"irq", &c->irq,
"port", &c->port
);
if (ret)
jerror(&err, "Failed to parse configuration for FPGA IP '%s'", name);
if (!config_setting_lookup_int(cfg, "irq", &c->irq))
c->irq = -1;
if (!config_setting_lookup_int(cfg, "port", &c->port))
c->port = -1;
c->baseaddr = baseaddr;
/* Type sepecific settings */
ret = c->_vt && c->_vt->parse ? c->_vt->parse(c) : 0;
ret = c->_vt && c->_vt->parse ? c->_vt->parse(c, cfg) : 0;
if (ret)
error("Failed to parse settings for IP core '%s'", c->name);
error("Failed to parse settings for IP core '%s'", name);
c->state = STATE_PARSED;

View file

@ -13,33 +13,40 @@
#include "fpga/card.h"
#include "fpga/ips/dft.h"
int dft_parse(struct fpga_ip *c)
int dft_parse(struct fpga_ip *c, json_t *cfg)
{
struct dft *dft = c->_vd;
config_setting_t *cfg_harms;
int ret;
if (!config_setting_lookup_int(c->cfg, "period", &dft->period))
cerror(c->cfg, "DFT IP core requires 'period' setting");
json_t *cfg_harms;
json_error_t err;
if (!config_setting_lookup_int(c->cfg, "decimation", &dft->decimation))
cerror(c->cfg, "DFT IP core requires 'decimation' setting");
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: o }",
"period", &dft->period,
"decimation", &dft->decimation,
"harmonics", &cfg_harms
);
if (ret)
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
cfg_harms = config_setting_get_member(c->cfg, "harmonics");
if (!cfg_harms)
cerror(c->cfg, "DFT IP core requires 'harmonics' setting!");
if (!json_is_array(cfg_harms))
error("DFT IP core requires 'harmonics' to be an array of integers!");
if (!config_setting_is_array(cfg_harms))
cerror(c->cfg, "DFT IP core requires 'harmonics' to be an array of integers!");
dft->num_harmonics = config_setting_length(cfg_harms);
dft->num_harmonics = json_array_size(cfg_harms);
if (dft->num_harmonics <= 0)
cerror(cfg_harms, "DFT IP core requires 'harmonics' to contain at least 1 integer!");
error("DFT IP core requires 'harmonics' to contain at least 1 value!");
dft->fharmonics = alloc(sizeof(float) * dft->num_harmonics);
for (int i = 0; i < dft->num_harmonics; i++)
dft->fharmonics[i] = (float) config_setting_get_int_elem(cfg_harms, i) / dft->period;
size_t index;
json_t *cfg_harm;
json_array_foreach(cfg_harms, index, cfg_harm) {
if (!json_is_real(cfg_harm))
error("DFT IP core requires all 'harmonics' values to be of floating point type");
dft->fharmonics[index] = (float) json_number_value(cfg_harm) / dft->period;
}
return 0;
}

View file

@ -91,16 +91,21 @@ ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len)
return nextlen;
}
int fifo_parse(struct fpga_ip *c)
int fifo_parse(struct fpga_ip *c, json_t *cfg)
{
struct fifo *fifo = c->_vd;
int baseaddr_axi4;
int baseaddr_axi4 = -1, ret;
if (config_setting_lookup_int(c->cfg, "baseaddr_axi4", &baseaddr_axi4))
fifo->baseaddr_axi4 = baseaddr_axi4;
else
fifo->baseaddr_axi4 = -1;
json_error_t err;
fifo->baseaddr_axi4 = -1;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }", "baseaddr_axi4", &baseaddr_axi4);
if (ret)
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
fifo->baseaddr_axi4 = baseaddr_axi4;
return 0;
}

View file

@ -18,7 +18,7 @@
#include "fpga/card.h"
#include "fpga/ips/model.h"
static int model_param_destroy(struct model_param *p)
static int model_parameter_destroy(struct model_parameter *p)
{
free(p->name);
@ -64,7 +64,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter
if (length < 4)
break; /* block is to small to describe a gateway */
struct model_param *e, *p = alloc(sizeof(struct model_param));
struct model_parameter *e, *p = alloc(sizeof(struct model_parameter));
p->name = copy_string(3);
p->default_value.flt = *((float *) &data[1]);
@ -75,7 +75,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter
e = list_lookup(parameters, p->name);
if (e)
model_param_update(e, p);
model_parameter_update(e, p);
else
list_push(parameters, p);
break;
@ -133,28 +133,40 @@ static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr)
return i;
}
int model_parse(struct fpga_ip *c)
int model_parse(struct fpga_ip *c, json_t *cfg)
{
struct model *m = c->_vd;
config_setting_t *cfg_params, *cfg_param;
int ret;
json_t *cfg_params;
json_error_t err;
if (strcmp(c->vlnv.library, "hls") == 0)
m->type = MODEL_TYPE_HLS;
else if (strcmp(c->vlnv.library, "sysgen") == 0)
m->type = MODEL_TYPE_XSG;
else
cerror(c->cfg, "Invalid model type: %s", c->vlnv.library);
error("Unsupported model type: %s", c->vlnv.library);
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "parameters", &cfg_params);
if (ret)
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
cfg_params = config_setting_get_member(c->cfg, "parameters");
if (cfg_params) {
for (int i = 0; i < config_setting_length(cfg_params); i++) {
cfg_param = config_setting_get_elem(cfg_params, i);
if (!json_is_object(cfg_params))
error("Setting 'parameters' must be a JSON object");
struct model_param *p = alloc(sizeof(struct model_param));
const char *name;
json_t *value;
json_object_foreach(cfg_params, name, value) {
if (!json_is_real(value))
error("Parameters of FPGA IP '%s' must be of type floating point", c->name);
p->name = config_setting_name(cfg_param);
p->default_value.flt = config_setting_get_float(cfg_param);
struct model_parameter *p = alloc(sizeof(struct model_parameter));
p->name = strdup(name);
p->default_value.flt = json_real_value(value);
list_push(&m->parameters, p);
}
@ -206,12 +218,12 @@ int model_init(struct fpga_ip *c)
/* Set default values for parameters */
for (size_t i = 0; i < list_length(&m->parameters); i++) {
struct model_param *p = list_at(&m->parameters, i);
struct model_parameter *p = list_at(&m->parameters, i);
p->ip = c;
if (p->direction == MODEL_PARAM_IN) {
model_param_write(p, p->default_value.flt);
if (p->direction == MODEL_PARAMETER_IN) {
model_parameter_write(p, p->default_value.flt);
info("Set parameter '%s' updated to default value: %f", p->name, p->default_value.flt);
}
}
@ -226,7 +238,7 @@ int model_destroy(struct fpga_ip *c)
{
struct model *m = c->_vd;
list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true);
list_destroy(&m->parameters, (dtor_cb_t) model_parameter_destroy, true);
list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true);
if (m->xsg.map != NULL)
@ -245,9 +257,9 @@ void model_dump(struct fpga_ip *c)
{ INDENT
info("Parameters:");
for (size_t i = 0; i < list_length(&m->parameters); i++) { INDENT
struct model_param *p = list_at(&m->parameters, i);
struct model_parameter *p = list_at(&m->parameters, i);
if (p->direction == MODEL_PARAM_IN)
if (p->direction == MODEL_PARAMETER_IN)
info("%#jx: %s (%s) = %.3f %s %u",
p->offset,
p->name,
@ -256,7 +268,7 @@ void model_dump(struct fpga_ip *c)
param_type[p->type],
p->binpt
);
else if (p->direction == MODEL_PARAM_OUT)
else if (p->direction == MODEL_PARAMETER_OUT)
info("%#jx: %s (%s)",
p->offset,
p->name,
@ -273,52 +285,52 @@ void model_dump(struct fpga_ip *c)
}
}
int model_param_read(struct model_param *p, double *v)
int model_parameter_read(struct model_parameter *p, double *v)
{
struct fpga_ip *c = p->ip;
union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset);
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
case MODEL_PARAMETER_TYPE_UFIX:
*v = (double) ptr->ufix / (1 << p->binpt);
break;
case MODEL_PARAM_TYPE_FIX:
case MODEL_PARAMETER_TYPE_FIX:
*v = (double) ptr->fix / (1 << p->binpt);
break;
case MODEL_PARAM_TYPE_FLOAT:
case MODEL_PARAMETER_TYPE_FLOAT:
*v = (double) ptr->flt;
break;
case MODEL_PARAM_TYPE_BOOLEAN:
case MODEL_PARAMETER_TYPE_BOOLEAN:
*v = (double) ptr->ufix ? 1 : 0;
}
return 0;
}
int model_param_write(struct model_param *p, double v)
int model_parameter_write(struct model_parameter *p, double v)
{
struct fpga_ip *c = p->ip;
union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset);
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
case MODEL_PARAMETER_TYPE_UFIX:
ptr->ufix = (uint32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAM_TYPE_FIX:
case MODEL_PARAMETER_TYPE_FIX:
ptr->fix = (int32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAM_TYPE_FLOAT:
case MODEL_PARAMETER_TYPE_FLOAT:
ptr->flt = (float) v;
break;
case MODEL_PARAM_TYPE_BOOLEAN:
case MODEL_PARAMETER_TYPE_BOOLEAN:
ptr->bol = (bool) v;
break;
}
@ -326,10 +338,10 @@ int model_param_write(struct model_param *p, double v)
return 0;
}
void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direction dir, enum model_param_type type)
void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type)
{
struct model *m = c->_vd;
struct model_param *p = alloc(sizeof(struct model_param));
struct model_parameter *p = alloc(sizeof(struct model_parameter));
p->name = strdup(name);
p->type = type;
@ -338,10 +350,10 @@ void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direc
list_push(&m->parameters, p);
}
int model_param_remove(struct fpga_ip *c, const char *name)
int model_parameter_remove(struct fpga_ip *c, const char *name)
{
struct model *m = c->_vd;
struct model_param *p;
struct model_parameter *p;
p = list_lookup(&m->parameters, name);
if (!p)
@ -352,7 +364,7 @@ int model_param_remove(struct fpga_ip *c, const char *name)
return 0;
}
int model_param_update(struct model_param *p, struct model_param *u)
int model_parameter_update(struct model_parameter *p, struct model_parameter *u)
{
if (strcmp(p->name, u->name) != 0)
return -1;

View file

@ -88,43 +88,41 @@ int switch_destroy(struct fpga_ip *c)
return 0;
}
int switch_parse(struct fpga_ip *c)
int switch_parse(struct fpga_ip *c, json_t *cfg)
{
struct fpga_card *f = c->card;
struct sw *sw = c->_vd;
int ret;
size_t index;
json_error_t err;
json_t *cfg_path, *cfg_paths = NULL;
list_init(&sw->paths);
config_setting_t *cfg_sw, *cfg_path;
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s?: o }",
"num_ports", &sw->num_ports,
"paths", &cfg_paths
);
if (ret)
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
if (!config_setting_lookup_int(c->cfg, "num_ports", &sw->num_ports))
cerror(c->cfg, "Switch IP '%s' requires 'num_ports' option", c->name);
cfg_sw = config_setting_get_member(f->cfg, "paths");
if (!cfg_sw)
if (!cfg_paths)
return 0; /* no switch config available */
for (int i = 0; i < config_setting_length(cfg_sw); i++) {
cfg_path = config_setting_get_elem(cfg_sw, i);
if (!json_is_array(cfg_paths))
error("Setting 'paths' of FPGA IP '%s' should be an array of JSON objects", c->name);
json_array_foreach(cfg_paths, index, cfg_path) {
struct sw_path *p = alloc(sizeof(struct sw_path));
int reverse;
int reverse = 0;
if (!config_setting_lookup_bool(cfg_path, "reverse", &reverse))
reverse = 0;
if (!config_setting_lookup_string(cfg_path, "in", &p->in) &&
!config_setting_lookup_string(cfg_path, "from", &p->in) &&
!config_setting_lookup_string(cfg_path, "src", &p->in) &&
!config_setting_lookup_string(cfg_path, "source", &p->in))
cerror(cfg_path, "Path is missing 'in' setting");
if (!config_setting_lookup_string(cfg_path, "out", &p->out) &&
!config_setting_lookup_string(cfg_path, "to", &p->out) &&
!config_setting_lookup_string(cfg_path, "dst", &p->out) &&
!config_setting_lookup_string(cfg_path, "dest", &p->out) &&
!config_setting_lookup_string(cfg_path, "sink", &p->out))
cerror(cfg_path, "Path is missing 'out' setting");
ret = json_unpack_ex(cfg_path, &err, 0, "{ s?: b, s: s, s: s }",
"reverse", &reverse,
"in", &p->in,
"out", &p->out
);
if (ret)
jerror(&err, "Failed to parse path %zu of FPGA IP '%s'", index, c->name);
list_push(&sw->paths, p);

View file

@ -212,7 +212,6 @@ char * hist_dump(struct hist *h)
return buf;
}
#ifdef WITH_JSON
json_t * hist_json(struct hist *h)
{
json_t *json_buckets, *json_hist;
@ -257,7 +256,6 @@ int hist_dump_json(struct hist *h, FILE *f)
return ret;
}
#endif /* WITH_JSON */
int hist_dump_matlab(struct hist *h, FILE *f)
{

View file

@ -21,7 +21,6 @@
*********************************************************************************/
#include <string.h>
#include <math.h>
#include <libconfig.h>
#include "timing.h"
#include "config.h"
@ -54,18 +53,24 @@ int hook_init(struct hook *h, struct hook_type *vt, struct path *p)
return 0;
}
int hook_parse(struct hook *h, config_setting_t *cfg)
int hook_parse(struct hook *h, json_t *cfg)
{
int ret;
json_error_t err;
assert(h->state != STATE_DESTROYED);
config_setting_lookup_int(cfg, "priority", &h->priority);
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }",
"priority", &h->priority
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
ret = h->_vt->parse ? h->_vt->parse(h, cfg) : 0;
if (ret)
return ret;
h->cfg = cfg;
h->state = STATE_PARSED;
return 0;
@ -83,20 +88,11 @@ int hook_parse_cli(struct hook *h, int argc, char *argv[])
h->state = STATE_PARSED;
}
else {
config_t cfg;
config_setting_t *cfg_root;
h->cfg = json_load_cli(argc, argv);
if (!h->cfg)
return -1;
config_init(&cfg);
ret = config_read_cli(&cfg, argc, argv);
if (ret)
goto out;
cfg_root = config_root_setting(&cfg);
ret = hook_parse(h, cfg_root);
out: config_destroy(&cfg);
ret = hook_parse(h, h->cfg);
}
return ret;
@ -204,38 +200,36 @@ int hook_cmp_priority(const void *a, const void *b)
return ha->priority - hb->priority;
}
int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *o)
int hook_parse_list(struct list *list, json_t *cfg, struct path *o)
{
struct plugin *p;
if (!json_is_array(cfg))
error("Hooks must be configured as a list of objects");
int ret;
const char *type;
size_t index;
json_t *cfg_hook;
json_array_foreach(cfg, index, cfg_hook) {
int ret;
const char *type;
struct plugin *p;
json_error_t err;
if (!config_setting_is_list(cfg))
cerror(cfg, "Hooks must be configured as a list of objects");
for (int i = 0; i < config_setting_length(cfg); i++) {
config_setting_t *cfg_hook = config_setting_get_elem(cfg, i);
if (!config_setting_is_group(cfg_hook))
cerror(cfg_hook, "The 'hooks' setting must be an array of strings.");
if (!config_setting_lookup_string(cfg_hook, "type", &type))
cerror(cfg_hook, "Missing setting 'type' for hook");
ret = json_unpack_ex(cfg_hook, &err, 0, "{ s: s }", "type", &type);
if (ret)
jerror(&err, "Failed to parse hook");
p = plugin_lookup(PLUGIN_TYPE_HOOK, type);
if (!p)
continue; /* We ignore all non hook settings in this libconfig object setting */
jerror(&err, "Unkown hook type '%s'", type);
struct hook *h = alloc(sizeof(struct hook));
ret = hook_init(h, &p->hook, o);
if (ret)
cerror(cfg_hook, "Failed to initialize hook");
jerror(&err, "Failed to initialize hook");
ret = hook_parse(h, cfg_hook);
if (ret)
cerror(cfg_hook, "Failed to parse hook configuration");
jerror(&err, "Failed to parse hook configuration");
list_push(list, h);
}

View file

@ -49,24 +49,28 @@ static int convert_init(struct hook *h)
return 0;
}
static int convert_parse(struct hook *h, config_setting_t *cfg)
static int convert_parse(struct hook *h, json_t *cfg)
{
struct convert *p = h->_vd;
const char *mode;
int ret;
json_error_t err;
const char *mode = NULL;
config_setting_lookup_float(cfg, "scale", &p->scale);
config_setting_lookup_int64(cfg, "mask", &p->mask);
if (!config_setting_lookup_string(cfg, "mode", &mode))
cerror(cfg, "Missing setting 'mode' for hook '%s'", plugin_name(h->_vt));
ret = json_unpack_ex(cfg, &err, 0, "{ s?: F, s?: i, s: s }",
"scale", &p->scale,
"mask", &p->mask,
"mode", &mode
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
if (!strcmp(mode, "fixed"))
p->mode = TO_FIXED;
else if (!strcmp(mode, "float"))
p->mode = TO_FLOAT;
else
error("Invalid parameter '%s' for hook 'convert'", mode);
error("Invalid 'mode' setting '%s' for hook '%s'", mode, plugin_name(h->_vt));
return 0;
}

View file

@ -41,15 +41,18 @@ static int decimate_init(struct hook *h)
return 0;
}
static int decimate_parse(struct hook *h, config_setting_t *cfg)
static int decimate_parse(struct hook *h, json_t *cfg)
{
struct decimate *p = h->_vd;
if (!cfg)
error("Missing configuration for hook: '%s'", plugin_name(h->_vt));
int ret;
json_error_t err;
if (!config_setting_lookup_int(cfg, "ratio", &p->ratio))
cerror(cfg, "Missing setting 'ratio' for hook '%s'", plugin_name(h->_vt));
ret = json_unpack_ex(cfg, &err, 0, "{ s: i }",
"ratio", &p->ratio
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
return 0;
}

View file

@ -51,15 +51,18 @@ static int map_destroy(struct hook *h)
return mapping_destroy(&p->mapping);
}
static int map_parse(struct hook *h, config_setting_t *cfg)
static int map_parse(struct hook *h, json_t *cfg)
{
int ret;
struct map *p = h->_vd;
config_setting_t *cfg_mapping;
json_error_t err;
json_t *cfg_mapping;
cfg_mapping = config_setting_lookup(cfg, "mapping");
if (!cfg_mapping || !config_setting_is_array(cfg_mapping))
return -1;
ret = json_unpack_ex(cfg, &err, 0, "{ s: o }",
"map", &cfg_mapping
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
ret = mapping_parse(&p->mapping, cfg_mapping);
if (ret)

View file

@ -31,6 +31,8 @@
struct print {
struct io output;
struct io_format *format;
const char *uri;
};
@ -38,7 +40,14 @@ static int print_init(struct hook *h)
{
struct print *p = h->_vd;
struct plugin *pl;
pl = plugin_lookup(PLUGIN_TYPE_FORMAT, "villas");
if (!pl)
return -1;
p->uri = NULL;
p->format = &pl->io;
return 0;
}
@ -46,22 +55,56 @@ static int print_init(struct hook *h)
static int print_start(struct hook *h)
{
struct print *p = h->_vd;
int ret;
return io_open(&p->output, p->uri, "w+");
ret = io_init(&p->output, p->format, IO_FORMAT_ALL);
if (ret)
return ret;
ret = io_open(&p->output, p->uri, "w+");
if (ret)
return ret;
return 0;
}
static int print_stop(struct hook *h)
{
struct print *p = h->_vd;
int ret;
return io_close(&p->output);
ret = io_close(&p->output);
if (ret)
return ret;
ret = io_destroy(&p->output);
if (ret)
return ret;
return 0;
}
static int print_parse(struct hook *h, config_setting_t *cfg)
static int print_parse(struct hook *h, json_t *cfg)
{
struct print *p = h->_vd;
struct plugin *pl;
const char *format = NULL;
int ret;
json_error_t err;
config_setting_lookup_string(cfg, "output", &p->uri);
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s }",
"output", &p->uri
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
if (format) {
pl = plugin_lookup(PLUGIN_TYPE_FORMAT, format);
if (!pl)
jerror(&err, "Invalid format '%s'", format);
p->format = &pl->io;
}
return 0;
}

View file

@ -32,12 +32,18 @@ struct shift {
int offset;
};
static int shift_seq_parse(struct hook *h, config_setting_t *cfg)
static int shift_seq_parse(struct hook *h, json_t *cfg)
{
struct shift *p = h->_vd;
if (!config_setting_lookup_int(cfg, "offset", &p->offset))
cerror(cfg, "Missing setting 'offset' for hook '%s'", plugin_name(h->_vt));
json_error_t err;
int ret;
ret = json_unpack_ex(cfg, &err, 0, "{ s: i }",
"offset", &p->offset
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
return 0;
}

View file

@ -47,13 +47,22 @@ static int shift_ts_init(struct hook *h)
return 0;
}
static int shift_ts_parse(struct hook *h, config_setting_t *cfg)
static int shift_ts_parse(struct hook *h, json_t *cfg)
{
struct shift_ts *p = h->_vd;
double offset;
const char *mode = NULL;
int ret;
json_error_t err;
const char *mode;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s: f }",
"mode", &mode,
"offset", &offset
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
if (config_setting_lookup_string(cfg, "mode", &mode)) {
if (mode) {
if (!strcmp(mode, "origin"))
p->mode = SHIFT_ORIGIN;
else if (!strcmp(mode, "received"))
@ -61,13 +70,9 @@ static int shift_ts_parse(struct hook *h, config_setting_t *cfg)
else if (!strcmp(mode, "sent"))
p->mode = SHIFT_SENT;
else
cerror(cfg, "Invalid mode parameter '%s' for hook '%s'", mode, plugin_name(h->_vt));
jerror(&err, "Invalid mode parameter '%s' for hook '%s'", mode, plugin_name(h->_vt));
}
double offset;
if (!config_setting_lookup_float(cfg, "offset", &offset))
cerror(cfg, "Missing setting 'offset' for hook '%s'", plugin_name(h->_vt));
p->offset = time_from_double(offset);
return 0;

View file

@ -24,8 +24,6 @@
* @{
*/
#include <libconfig.h>
#include "hook.h"
#include "plugin.h"
#include "timing.h"
@ -53,23 +51,33 @@ struct skip_first {
};
};
static int skip_first_parse(struct hook *h, config_setting_t *cfg)
static int skip_first_parse(struct hook *h, json_t *cfg)
{
struct skip_first *p = h->_vd;
double seconds;
if (config_setting_lookup_float(cfg, "seconds", &seconds)) {
int ret;
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s: F }", "seconds", &seconds);
if (!ret) {
p->seconds.wait = time_from_double(seconds);
p->mode = HOOK_SKIP_MODE_SECONDS;
}
else if (config_setting_lookup_int(cfg, "samples", &p->samples.wait)) {
p->mode = HOOK_SKIP_MODE_SAMPLES;
}
else
cerror(cfg, "Missing setting 'seconds' or 'samples' for hook '%s'", plugin_name(h->_vt));
return 0;
return 0;
}
ret = json_unpack_ex(cfg, &err, 0, "{ s: i }", "samples", &p->samples.wait);
if (!ret) {
p->mode = HOOK_SKIP_MODE_SAMPLES;
return 0;
}
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
return -1;
}
static int skip_first_restart(struct hook *h)

View file

@ -116,26 +116,35 @@ static int stats_collect_periodic(struct hook *h)
return 0;
}
static int stats_collect_parse(struct hook *h, config_setting_t *cfg)
static int stats_collect_parse(struct hook *h, json_t *cfg)
{
struct stats_collect *p = h->_vd;
const char *format, *uri;
if (config_setting_lookup_string(cfg, "format", &format)) {
int fmt;
int ret, fmt;
json_error_t err;
const char *format = NULL;
const char *uri = NULL;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: s?: i, s?: s }"
"format", &format,
"verbose", &p->verbose,
"warmup", &p->warmup,
"buckets", &p->buckets,
"output", &uri
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
if (format) {
fmt = stats_lookup_format(format);
if (fmt < 0)
cerror(cfg, "Invalid statistic output format: %s", format);
jerror(&err, "Invalid statistic output format: %s", format);
p->format = fmt;
}
config_setting_lookup_bool(cfg, "verbose", &p->verbose);
config_setting_lookup_int(cfg, "warmup", &p->warmup);
config_setting_lookup_int(cfg, "buckets", &p->buckets);
if (config_setting_lookup_string(cfg, "output", &uri))
if (uri)
p->uri = strdup(uri);
return 0;

View file

@ -53,35 +53,45 @@ static int stats_send_init(struct hook *h)
return 0;
}
static int stats_send_parse(struct hook *h, config_setting_t *cfg)
static int stats_send_parse(struct hook *h, json_t *cfg)
{
struct stats_send *p = h->_vd;
assert(h->path && h->path->super_node);
const char *dest, *mode;
const char *dest = NULL;
const char *mode = NULL;
if (config_setting_lookup_string(cfg, "destination", &dest)) {
int ret;
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s, s?: i }"
"destination", &dest,
"mode", &mode,
"decimation", &p->decimation
);
if (ret)
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
if (dest) {
assert(h->path);
p->dest = list_lookup(&h->path->super_node->nodes, dest);
if (!p->dest)
cerror(cfg, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt));
jerror(&err, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt));
}
else
cerror(cfg, "Missing setting 'destination' for hook '%s'", plugin_name(h->_vt));
jerror(&err, "Missing setting 'destination' for hook '%s'", plugin_name(h->_vt));
if (config_setting_lookup_string(cfg, "mode", &mode)) {
if (mode) {
if (!strcmp(mode, "periodic"))
p->mode = STATS_SEND_MODE_PERIODIC;
else if (!strcmp(mode, "read"))
p->mode = STATS_SEND_MODE_READ;
else
cerror(cfg, "Invalid value '%s' for setting 'mode' of hook '%s'", mode, plugin_name(h->_vt));
jerror(&err, "Invalid value '%s' for setting 'mode' of hook '%s'", mode, plugin_name(h->_vt));
}
config_setting_lookup_int(cfg, "decimation", &p->decimation);
return 0;
}

View file

@ -35,10 +35,32 @@
#include "utils.h"
int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem)
int tc_parse(struct rtnl_qdisc **netem, json_t *cfg)
{
const char *str;
int val;
int ret, val;
json_t *cfg_distribution = NULL;
json_t *cfg_limit = NULL;
json_t *cfg_delay = NULL;
json_t *cfg_jitter = NULL;
json_t *cfg_loss = NULL;
json_t *cfg_duplicate = NULL;
json_t *cfg_corruption = NULL;
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: i, s?: i, s?: i, s?: i, s?: i, s?: i }",
"distribution", &cfg_distribution,
"limit", &cfg_limit,
"delay", &cfg_delay,
"jitter", &cfg_jitter,
"loss", &cfg_loss,
"duplicate", &cfg_duplicate,
"corruption", &cfg_corruption
);
if (ret)
jerror(&err, "Failed to parse setting network emulation settings");
struct rtnl_qdisc *ne = rtnl_qdisc_alloc();
if (!ne)
@ -46,51 +68,67 @@ int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem)
rtnl_tc_set_kind(TC_CAST(ne), "netem");
if (config_setting_lookup_string(cfg, "distribution", &str)) {
if (cfg_distribution) {
str = json_string_value(cfg_distribution);
if (!str)
error("Setting 'distribution' must be a JSON string");
if (rtnl_netem_set_delay_distribution(ne, str))
cerror(cfg, "Invalid delay distribution '%s' in netem config", str);
error("Invalid delay distribution '%s' in netem config", str);
}
if (config_setting_lookup_int(cfg, "limit", &val)) {
if (val <= 0)
cerror(cfg, "Invalid value '%d' for limit setting", val);
if (cfg_limit) {
val = json_integer_value(cfg_limit);
if (!json_is_integer(cfg_limit) || val <= 0)
error("Setting 'limit' must be a positive integer");
rtnl_netem_set_limit(ne, val);
}
else
rtnl_netem_set_limit(ne, 0);
if (config_setting_lookup_int(cfg, "delay", &val)) {
if (val <= 0)
cerror(cfg, "Invalid value '%d' for delay setting", val);
if (cfg_delay) {
val = json_integer_value(cfg_delay);
if (!json_is_integer(cfg_delay) || val <= 0)
error("Setting 'delay' must be a positive integer");
rtnl_netem_set_delay(ne, val);
}
if (config_setting_lookup_int(cfg, "jitter", &val)) {
if (val <= 0)
cerror(cfg, "Invalid value '%d' for jitter setting", val);
if (cfg_jitter) {
val = json_integer_value(cfg_jitter);
if (!json_is_integer(cfg_jitter) || val <= 0)
error("Setting 'jitter' must be a positive integer");
rtnl_netem_set_jitter(ne, val);
}
if (config_setting_lookup_int(cfg, "loss", &val)) {
if (val < 0 || val > 100)
cerror(cfg, "Invalid percentage value '%d' for loss setting", val);
if (cfg_loss) {
val = json_integer_value(cfg_loss);
if (!json_is_integer(cfg_loss) || val < 0 || val > 100)
error("Setting 'loss' must be a positive integer within the range [ 0, 100 ]");
rtnl_netem_set_loss(ne, val);
}
if (config_setting_lookup_int(cfg, "duplicate", &val)) {
if (val < 0 || val > 100)
cerror(cfg, "Invalid percentage value '%d' for duplicate setting", val);
if (cfg_duplicate) {
val = json_integer_value(cfg_duplicate);
if (!json_is_integer(cfg_duplicate) || val < 0 || val > 100)
error("Setting 'duplicate' must be a positive integer within the range [ 0, 100 ]");
rtnl_netem_set_duplicate(ne, val);
}
if (config_setting_lookup_int(cfg, "corruption", &val)) {
if (val < 0 || val > 100)
cerror(cfg, "Invalid percentage value '%d' for corruption setting", val);
if (cfg_corruption) {
val = json_integer_value(cfg_corruption);
if (!json_is_integer(cfg_corruption) || val < 0 || val > 100)
error("Setting 'corruption' must be a positive integer within the range [ 0, 100 ]");
rtnl_netem_set_corruption_probability(ne, val);
}

View file

@ -1,4 +1,4 @@
/** Logging routines that depend on libconfig.
/** Logging routines that depend on jansson.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
@ -28,35 +28,39 @@
#include "log.h"
#include "log_config.h"
#include "utils.h"
#include "string.h"
int log_parse(struct log *l, config_setting_t *cfg)
int log_parse(struct log *l, json_t *cfg)
{
const char *fac, *pth;
int lvl;
const char *facilities = NULL;
const char *path = NULL;
int ret;
if (!config_setting_is_group(cfg))
cerror(cfg, "Setting 'log' must be a group.");
json_error_t err;
if (config_setting_lookup_int(cfg, "level", &lvl))
l->level = lvl;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: s, s?: s }",
"level", &l->level,
"file", &path,
"facilities", &facilities
);
if (ret)
jerror(&err, "Failed to parse logging configuration");
if (config_setting_lookup_string(cfg, "file", &pth))
l->path = pth;
if (path)
l->path = strdup(path);
if (config_setting_lookup_string(cfg, "facilities", &fac))
log_set_facility_expression(l, fac);
if (facilities)
log_set_facility_expression(l, facilities);
l->state = STATE_PARSED;
return 0;
}
void cerror(config_setting_t *cfg, const char *fmt, ...)
void jerror(json_error_t *err, const char *fmt, ...)
{
va_list ap;
char *buf = NULL;
const char *file;
int line;
struct log *l = global_log ? global_log : &default_log;
@ -64,12 +68,10 @@ void cerror(config_setting_t *cfg, const char *fmt, ...)
vstrcatf(&buf, fmt, ap);
va_end(ap);
line = config_setting_source_line(cfg);
file = config_setting_source_file(cfg);
if (!file)
file = config_setting_get_hook(config_root_setting(cfg->config));
log_print(l, LOG_LVL_ERROR, "%s in %s:%u", buf, file, line);
log_print(l, LOG_LVL_ERROR, "%s:", buf);
{ INDENT
log_print(l, LOG_LVL_ERROR, "%s in %s:%d:%d", err->text, err->source, err->line, err->column);
}
free(buf);

View file

@ -162,11 +162,11 @@ invalid_format:
return -1;
}
int mapping_entry_parse(struct mapping_entry *e, config_setting_t *cfg)
int mapping_entry_parse(struct mapping_entry *e, json_t *cfg)
{
const char *str;
str = config_setting_get_string(cfg);
str = json_string_value(cfg);
if (!str)
return -1;
@ -195,27 +195,23 @@ int mapping_destroy(struct mapping *m)
return 0;
}
int mapping_parse(struct mapping *m, config_setting_t *cfg)
int mapping_parse(struct mapping *m, json_t *cfg)
{
int ret;
assert(m->state == STATE_INITIALIZED);
if (!config_setting_is_array(cfg))
if (!json_is_array(cfg))
return -1;
m->real_length = 0;
for (int i = 0; i < config_setting_length(cfg); i++) {
config_setting_t *cfg_mapping;
cfg_mapping = config_setting_get_elem(cfg, i);
if (!cfg_mapping)
return -1;
size_t index;
json_t *cfg_entry;
json_array_foreach(cfg, index, cfg_entry) {
struct mapping_entry *e = alloc(sizeof(struct mapping_entry));
ret = mapping_entry_parse(e, cfg_mapping);
ret = mapping_entry_parse(e, cfg_entry);
if (ret)
return ret;

View file

@ -21,7 +21,6 @@
*********************************************************************************/
#include <string.h>
#include <libconfig.h>
#include "sample.h"
#include "node.h"
@ -52,28 +51,32 @@ int node_init(struct node *n, struct node_type *vt)
return 0;
}
int node_parse(struct node *n, config_setting_t *cfg)
int node_parse(struct node *n, json_t *cfg, const char *name)
{
struct plugin *p;
const char *type, *name;
int ret;
name = config_setting_name(cfg);
json_error_t err;
if (!config_setting_lookup_string(cfg, "type", &type))
cerror(cfg, "Missing node type");
const char *type;
n->name = strdup(name);
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: i }",
"type", &type,
"vectorize", &n->vectorize
);
if (ret)
jerror(&err, "Failed to parse node '%s'", node_name(n));
p = plugin_lookup(PLUGIN_TYPE_NODE, type);
assert(&p->node == n->_vt);
config_setting_lookup_int(cfg, "vectorize", &n->vectorize);
n->name = strdup(name);
ret = n->_vt->parse ? n->_vt->parse(n, cfg) : 0;
if (ret)
cerror(cfg, "Failed to parse node '%s'", node_name(n));
error("Failed to parse node '%s'", node_name(n));
n->cfg = cfg;
n->state = STATE_PARSED;
return ret;
@ -85,10 +88,9 @@ int node_parse_cli(struct node *n, int argc, char *argv[])
assert(n->_vt);
n->vectorize = 1;
n->name = "cli";
if (n->_vt->parse_cli) {
n->name = strdup("cli");
ret = n->_vt->parse_cli(n, argc, argv);
if (ret)
return ret;
@ -96,21 +98,11 @@ int node_parse_cli(struct node *n, int argc, char *argv[])
n->state = STATE_PARSED;
}
else {
config_t cfg;
config_setting_t *cfg_root;
n->cfg = json_load_cli(argc, argv);
if (!n->cfg)
return -1;
config_init(&cfg);
ret = config_read_cli(&cfg, argc, argv);
if (ret)
goto out;
cfg_root = config_root_setting(&cfg);
ret = node_parse(n, cfg_root);
out:
config_destroy(&cfg);
ret = node_parse(n, n->cfg, "cli");
}
return ret;
@ -279,47 +271,57 @@ int node_reverse(struct node *n)
return n->_vt->reverse ? n->_vt->reverse(n) : -1;
}
int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all)
int node_parse_list(struct list *list, json_t *cfg, struct list *all)
{
const char *str;
struct node *node;
const char *str;
char *allstr = NULL;
switch (config_setting_type(cfg)) {
case CONFIG_TYPE_STRING:
str = config_setting_get_string(cfg);
if (str) {
node = list_lookup(all, str);
if (node)
list_push(list, node);
else
cerror(cfg, "Unknown outgoing node '%s'", str);
}
else
cerror(cfg, "Invalid outgoing node");
size_t index;
json_t *elm;
switch (json_typeof(cfg)) {
case JSON_STRING:
str = json_string_value(cfg);
node = list_lookup(all, str);
if (!node)
goto invalid2;
list_push(list, node);
break;
case CONFIG_TYPE_ARRAY:
for (int i = 0; i < config_setting_length(cfg); i++) {
config_setting_t *elm = config_setting_get_elem(cfg, i);
case JSON_ARRAY:
json_array_foreach(cfg, index, elm) {
if (!json_is_string(elm))
goto invalid;
str = config_setting_get_string(elm);
if (str) {
node = list_lookup(all, str);
if (!node)
cerror(elm, "Unknown outgoing node '%s'", str);
else if (node->_vt->write == NULL)
cerror(cfg, "Output node '%s' is not supported as a sink.", node_name(node));
node = list_lookup(all, json_string_value(elm));
if (!node)
list_push(list, node);
}
else
cerror(cfg, "Invalid outgoing node");
list_push(list, node);
}
break;
default:
cerror(cfg, "Invalid output node(s)");
goto invalid;
}
return 0;
invalid:
error("The node list must be an a single or an array of strings referring to the keys of the 'nodes' section");
return -1;
invalid2:
for (size_t i = 0; i < list_length(all); i++) {
struct node *n = list_at(all, i);
strcatf(&allstr, " %s", node_name_short(n));
}
error("Unknown node '%s'. Choose of one of: %s", str, allstr);
return 0;
}

View file

@ -11,33 +11,43 @@
#include "nodes/cbuilder.h"
int cbuilder_parse(struct node *n, config_setting_t *cfg)
int cbuilder_parse(struct node *n, json_t *cfg)
{
struct cbuilder *cb = n->_vd;
config_setting_t *cfg_params;
json_t *cfg_param, *cfg_params = NULL;
const char *model;
if (!config_setting_lookup_float(cfg, "timestep", &cb->timestep))
cerror(cfg, "CBuilder model requires 'timestep' setting");
int ret;
size_t index;
json_error_t err;
if (!config_setting_lookup_string(cfg, "model", &model))
cerror(cfg, "CBuilder model requires 'model' setting");
ret = json_unpack_ex(cfg, &err, 0, "{ s: f, s: s, s: b }",
"timestep", &cb->timestep,
"model", &model,
"parameters", &cfg_params
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
cb->model = (struct cbuilder_model *) plugin_lookup(PLUGIN_TYPE_MODEL_CBUILDER, model);
if (!cb->model)
cerror(cfg, "Unknown model '%s'", model);
error("Unknown model '%s' of node %s", model, node_name(n));
cfg_params = config_setting_get_member(cfg, "parameters");
if (cfg_params) {
if (!config_setting_is_array(cfg_params))
cerror(cfg_params, "Model parameters must be an array of numbers!");
if (!json_is_array(cfg_params))
error("Setting 'parameters' of node %s must be an JSON array of numbers!", node_name(n));
cb->paramlen = config_setting_length(cfg_params);
cb->paramlen = json_array_size(cfg_params);
cb->params = alloc(cb->paramlen * sizeof(double));
for (int i = 0; i < cb->paramlen; i++)
cb->params[i] = config_setting_get_float_elem(cfg_params, i);
json_array_foreach(cfg_params, index, cfg_param) {
if (json_is_number(cfg_param))
error("Setting 'parameters' of node %s must be an JSON array of numbers!", node_name(n));
cb->params[index] = json_number_value(cfg_params);
}
}
return 0;

View file

@ -64,15 +64,29 @@ static AFILE * file_reopen(struct file_direction *dir)
return afopen(dir->uri, dir->mode);
}
static int file_parse_direction(config_setting_t *cfg, struct file *f, int d)
static int file_parse_direction(json_t *cfg, struct file *f, int d)
{
struct file_direction *dir = (d == FILE_READ) ? &f->read : &f->write;
int ret;
json_error_t err;
if (!config_setting_lookup_string(cfg, "uri", &dir->fmt))
return -1;
const char *format = NULL;
const char *mode = NULL;
if (!config_setting_lookup_string(cfg, "mode", &dir->mode))
dir->mode = (d == FILE_READ) ? "r" : "w+";
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s }",
"uri", &format,
"mode", &mode
);
if (ret)
jerror(&err, "Failed to ");
if (format)
dir->format = strdup(format);
if (mode)
dir->mode = strdup(mode);
else
dir->mode = strdup(d == FILE_READ ? "r" : "w+");
return 0;
}
@ -104,30 +118,61 @@ static struct timespec file_calc_read_offset(const struct timespec *first, const
}
}
int file_parse(struct node *n, config_setting_t *cfg)
int file_parse(struct node *n, json_t *cfg)
{
struct file *f = n->_vd;
config_setting_t *cfg_in, *cfg_out;
json_t *cfg_in = NULL;
json_t *cfg_out = NULL;
int ret;
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o }",
"in", &cfg_in,
"out", &cfg_out
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
cfg_out = config_setting_get_member(cfg, "out");
if (cfg_out) {
if (file_parse_direction(cfg_out, f, FILE_WRITE))
cerror(cfg_out, "Failed to parse output file for node %s", node_name(n));
error("Failed to parse output file for node %s", node_name(n));
if (!config_setting_lookup_bool(cfg_out, "flush", &f->flush))
f->flush = 0;
f->flush = 0;
ret = json_unpack_ex(cfg_out, &err, 0, "{ s?: b }", "flush", &f->flush);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
}
cfg_in = config_setting_get_member(cfg, "in");
if (cfg_in) {
const char *eof;
const char *eof = NULL;
const char *epoch_mode = NULL;
double epoch_flt = 0;
/* Default values */
f->read_rate = 0;
f->read_eof = FILE_EOF_EXIT;
f->read_epoch_mode = FILE_EPOCH_DIRECT;
if (file_parse_direction(cfg_in, f, FILE_READ))
cerror(cfg_in, "Failed to parse input file for node %s", node_name(n));
error("Failed to parse input file for node %s", node_name(n));
ret = json_unpack_ex(cfg_in, &err, 0, "{ s?: s, s?: f, s?: s, s?: f }",
"eof", &eof,
"rate", &f->read_rate,
"epoch_mode", &epoch_mode,
"epoch", &epoch_flt
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
f->read_epoch = time_from_double(epoch_flt);
/* More read specific settings */
if (config_setting_lookup_string(cfg_in, "eof", &eof)) {
if (eof) {
if (!strcmp(eof, "exit"))
f->read_eof = FILE_EOF_EXIT;
else if (!strcmp(eof, "rewind"))
@ -135,22 +180,10 @@ int file_parse(struct node *n, config_setting_t *cfg)
else if (!strcmp(eof, "wait"))
f->read_eof = FILE_EOF_WAIT;
else
cerror(cfg_in, "Invalid mode '%s' for 'eof' setting", eof);
error("Invalid mode '%s' for 'eof' setting of node %s", eof, node_name(n));
}
else
f->read_eof = FILE_EOF_EXIT;
if (!config_setting_lookup_float(cfg_in, "rate", &f->read_rate))
f->read_rate = 0; /* Disable fixed rate sending. Using timestamps of file instead */
double epoch_flt;
if (!config_setting_lookup_float(cfg_in, "epoch", &epoch_flt))
epoch_flt = 0;
f->read_epoch = time_from_double(epoch_flt);
const char *epoch_mode;
if (config_setting_lookup_string(cfg_in, "epoch_mode", &epoch_mode)) {
if (epoch_mode) {
if (!strcmp(epoch_mode, "direct"))
f->read_epoch_mode = FILE_EPOCH_DIRECT;
else if (!strcmp(epoch_mode, "wait"))
@ -162,10 +195,8 @@ int file_parse(struct node *n, config_setting_t *cfg)
else if (!strcmp(epoch_mode, "original"))
f->read_epoch_mode = FILE_EPOCH_ORIGINAL;
else
cerror(cfg_in, "Invalid value '%s' for setting 'epoch_mode'", epoch_mode);
error("Invalid value '%s' for setting 'epoch_mode' of node %s", epoch_mode, node_name(n));
}
else
f->read_epoch_mode = FILE_EPOCH_DIRECT;
}
n->_vd = f;
@ -178,7 +209,7 @@ char * file_print(struct node *n)
struct file *f = n->_vd;
char *buf = NULL;
if (f->read.fmt) {
if (f->read.format) {
const char *epoch_str = NULL;
switch (f->read_epoch_mode) {
case FILE_EPOCH_DIRECT: epoch_str = "direct"; break;
@ -196,7 +227,7 @@ char * file_print(struct node *n)
}
strcatf(&buf, "in=%s, mode=%s, eof=%s, epoch_mode=%s, epoch=%.2f",
f->read.uri ? f->read.uri : f->read.fmt,
f->read.uri ? f->read.uri : f->read.format,
f->read.mode,
eof_str,
epoch_str,
@ -207,9 +238,9 @@ char * file_print(struct node *n)
strcatf(&buf, ", rate=%.1f", f->read_rate);
}
if (f->write.fmt) {
if (f->write.format) {
strcatf(&buf, ", out=%s, mode=%s",
f->write.uri ? f->write.uri : f->write.fmt,
f->write.uri ? f->write.uri : f->write.format,
f->write.mode
);
}
@ -241,9 +272,9 @@ int file_start(struct node *n)
struct timespec now = time_now();
int ret;
if (f->read.fmt) {
if (f->read.format) {
/* Prepare file name */
f->read.uri = file_format_name(f->read.fmt, &now);
f->read.uri = file_format_name(f->read.format, &now);
/* Open file */
f->read.handle = file_reopen(&f->read);
@ -262,9 +293,10 @@ int file_start(struct node *n)
/* Get timestamp of first line */
if (f->read_epoch_mode != FILE_EPOCH_ORIGINAL) {
struct sample s;
struct sample *smps[] = { &s };
s.capacity = 0;
ret = io_format_villas_fscan(f->read.handle->file, &s, NULL);
ret = io_format_villas_fscan(f->read.handle->file, smps, 1, NULL);
if (ret < 0)
error("Failed to read first timestamp of node %s", node_name(n));
@ -274,9 +306,9 @@ int file_start(struct node *n)
}
}
if (f->write.fmt) {
if (f->write.format) {
/* Prepare file name */
f->write.uri = file_format_name(f->write.fmt, &now);
f->write.uri = file_format_name(f->write.format, &now);
/* Open file */
f->write.handle = file_reopen(&f->write);
@ -307,15 +339,14 @@ int file_stop(struct node *n)
int file_read(struct node *n, struct sample *smps[], unsigned cnt)
{
struct file *f = n->_vd;
struct sample *s = smps[0];
int values, flags;
uint64_t ex;
assert(f->read.handle);
assert(cnt == 1);
retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get message and timestamp */
if (values < 0) {
retry: values = io_format_villas_fscan(f->read.handle->file, smps, 1, &flags); /* Get message and timestamp */
if (values <= 0) {
if (afeof(f->read.handle)) {
switch (f->read_eof) {
case FILE_EOF_REWIND:
@ -345,14 +376,14 @@ retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get
if (f->read_epoch_mode != FILE_EPOCH_ORIGINAL) {
if (!f->read_rate || aftell(f->read.handle) == 0) {
s->ts.origin = time_add(&s->ts.origin, &f->read_offset);
smps[0]->ts.origin = time_add(&smps[0]->ts.origin, &f->read_offset);
ex = timerfd_wait_until(f->read_timer, &s->ts.origin);
ex = timerfd_wait_until(f->read_timer, &smps[0]->ts.origin);
}
else { /* Wait with fixed rate delay */
ex = timerfd_wait(f->read_timer);
s->ts.origin = time_now();
smps[0]->ts.origin = time_now();
}
/* Check for overruns */
@ -368,12 +399,11 @@ retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get
int file_write(struct node *n, struct sample *smps[], unsigned cnt)
{
struct file *f = n->_vd;
struct sample *s = smps[0];
assert(f->write.handle);
assert(cnt == 1);
io_format_villas_fprint(f->write.handle->file, s, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET);
io_format_villas_fprint(f->write.handle->file, smps, cnt, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET);
if (f->flush)
afflush(f->write.handle);

View file

@ -34,7 +34,6 @@ void fpga_dump(struct fpga *f)
int fpga_init(struct super_node *sn)
{
int ret;
config_setting_t *cfg, *cfg_fpgas;
ret = pci_init(&pci);
if (ret)
@ -44,6 +43,9 @@ int fpga_init(struct super_node *sn)
if (ret)
error("Failed to initiliaze VFIO sub-system");
#if 0
json_t *cfg, *cfg_fpgas;
/* Parse FPGA configuration */
cfg = config_root_setting(&sn->cfg);
cfg_fpgas = config_setting_lookup(cfg, "fpgas");
@ -53,7 +55,7 @@ int fpga_init(struct super_node *sn)
ret = fpga_card_parse_list(&cards, cfg_fpgas);
if (ret)
cerror(cfg, "Failed to parse VILLASfpga config");
#endif
return 0;
}
@ -76,7 +78,7 @@ int fpga_deinit()
return 0;
}
int fpga_parse(struct node *n, config_setting_t *cfg)
int fpga_parse(struct node *n, json_t *cfg)
{
struct fpga *f = n->_vd;
struct fpga_card *card;
@ -85,11 +87,18 @@ int fpga_parse(struct node *n, config_setting_t *cfg)
char *cpy, *card_name, *ip_name;
const char *dm;
if (!config_setting_lookup_string(cfg, "datamover", &dm))
cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n));
json_error_t err;
int ret;
if (!config_setting_lookup_bool(cfg, "use_irqs", &f->use_irqs))
f->use_irqs = false;
/* Default values */
f->use_irqs = false;
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: b }",
"datamover", &dm,
"use_irqs", &f->use_irqs
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
cpy = strdup(dm); /* strtok can not operate on type const char * */
@ -98,13 +107,13 @@ int fpga_parse(struct node *n, config_setting_t *cfg)
card = list_lookup(&cards, card_name);
if (!card)
cerror(cfg, "There is no FPGA card named '%s", card_name);
error("There is no FPGA card named '%s' used by node %s", card_name, node_name(n));
ip = list_lookup(&card->ips, ip_name);
if (!ip)
cerror(cfg, "There is no datamover named '%s' on the FPGA card '%s'", ip_name, card_name);
error("There is no datamover named '%s' on the FPGA card '%s' used by node %s", ip_name, card_name, node_name(n));
if (ip->_vt->type != FPGA_IP_TYPE_DM_DMA && ip->_vt->type != FPGA_IP_TYPE_DM_FIFO)
cerror(cfg, "The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name);
error("The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name);
free(cpy);

View file

@ -27,15 +27,23 @@
#include "nodes/loopback.h"
#include "memory.h"
int loopback_parse(struct node *n, config_setting_t *cfg)
int loopback_parse(struct node *n, json_t *cfg)
{
struct loopback *l = n->_vd;
if (!config_setting_lookup_int(cfg, "queuelen", &l->queuelen))
l->queuelen = DEFAULT_QUEUELEN;
json_error_t err;
int ret;
if (!config_setting_lookup_int(cfg, "samplelen", &l->samplelen))
l->samplelen = DEFAULT_SAMPLELEN;
/* Default values */
l->queuelen = DEFAULT_QUEUELEN;
l->samplelen = DEFAULT_SAMPLELEN;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i }",
"queuelen", &l->queuelen,
"samplelen", &l->samplelen
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
return 0;
}

View file

@ -46,25 +46,28 @@ int nanomsg_reverse(struct node *n)
return 0;
}
static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg)
static int nanomsg_parse_endpoints(struct list *l, json_t *cfg)
{
const char *ep;
switch (config_setting_type(cfg)) {
case CONFIG_TYPE_LIST:
case CONFIG_TYPE_ARRAY:
for (int j = 0; j < config_setting_length(cfg); j++) {
const char *ep = config_setting_get_string_elem(cfg, j);
size_t index;
json_t *cfg_val;
switch (json_typeof(cfg)) {
case JSON_ARRAY:
json_array_foreach(cfg, index, cfg_val) {
ep = json_string_value(cfg_val);
if (!ep)
return -1;
list_push(l, strdup(ep));
}
break;
case CONFIG_TYPE_STRING:
ep = config_setting_get_string(cfg);
case JSON_STRING:
ep = json_string_value(cfg);
list_push(l, strdup(ep));
break;
default:
@ -74,28 +77,36 @@ static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg)
return 0;
}
int nanomsg_parse(struct node *n, config_setting_t *cfg)
int nanomsg_parse(struct node *n, json_t *cfg)
{
int ret;
struct nanomsg *m = n->_vd;
config_setting_t *cfg_pub, *cfg_sub;
json_error_t err;
json_t *cfg_pub = NULL;
json_t *cfg_sub = NULL;
list_init(&m->publisher.endpoints);
list_init(&m->subscriber.endpoints);
cfg_pub = config_setting_lookup(cfg, "publish");
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o }",
"publish", &cfg_pub,
"subscribe", &cfg_sub
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
if (cfg_pub) {
ret = nanomsg_parse_endpoints(&m->publisher.endpoints, cfg_pub);
if (ret < 0)
cerror(cfg_pub, "Invalid type for 'publish' setting of node %s", node_name(n));
error("Invalid type for 'publish' setting of node %s", node_name(n));
}
cfg_sub = config_setting_lookup(cfg, "subscribe");
if (cfg_sub) {
ret = nanomsg_parse_endpoints(&m->subscriber.endpoints, cfg_sub);
if (ret < 0)
cerror(cfg_pub, "Invalid type for 'subscribe' setting of node %s", node_name(n));
error("Invalid type for 'subscribe' setting of node %s", node_name(n));
}
return 0;

View file

@ -197,26 +197,31 @@ static int ngsi_parse_entity(json_t *entity, struct ngsi *i, struct sample *smps
return cnt;
}
static int ngsi_parse_mapping(struct list *mapping, config_setting_t *cfg)
static int ngsi_parse_mapping(struct list *mapping, json_t *cfg)
{
if (!config_setting_is_array(cfg))
if (!json_is_array(cfg))
return -1;
list_init(mapping);
for (int j = 0; j < config_setting_length(cfg); j++) {
const char *token = config_setting_get_string_elem(cfg, j);
size_t index;
json_t *cfg_token;
json_array_foreach(cfg, index, cfg_token) {
const char *token;
token = json_string_value(cfg_token);
if (!token)
return -2;
struct ngsi_attribute *a = alloc(sizeof(struct ngsi_attribute));
a->index = j;
a->index = index;
/* Parse Attribute: AttributeName(AttributeType) */
int bytes;
if (sscanf(token, "%m[^(](%m[^)])%n", &a->name, &a->type, &bytes) != 2)
cerror(cfg, "Invalid mapping token: '%s'", token);
error("Invalid mapping token: '%s'", token);
token += bytes;
@ -241,7 +246,7 @@ static int ngsi_parse_mapping(struct list *mapping, config_setting_t *cfg)
.name = "index",
.type = "integer"
};
assert(asprintf(&i.value, "%u", j));
assert(asprintf(&i.value, "%zu", index));
list_push(&a->metadata, memdup(&s, sizeof(s)));
list_push(&a->metadata, memdup(&i, sizeof(i)));
@ -387,18 +392,6 @@ out: json_decref(request);
int ngsi_init(struct super_node *sn)
{
config_setting_t *cfg;
cfg = config_root_setting(&sn->cfg);
const char *tname;
if (config_setting_lookup_string(cfg, "name", &tname))
name = strdup(tname);
else {
name = alloc(128); /** @todo missing free */
gethostname((char *) name, 128);
}
return curl_global_init(CURL_GLOBAL_ALL);
}
@ -411,37 +404,36 @@ int ngsi_deinit()
return 0;
}
int ngsi_parse(struct node *n, config_setting_t *cfg)
int ngsi_parse(struct node *n, json_t *cfg)
{
struct ngsi *i = n->_vd;
if (!config_setting_lookup_string(cfg, "access_token", &i->access_token))
i->access_token = NULL; /* disabled by default */
int ret;
json_error_t err;
json_t *cfg_mapping;
if (!config_setting_lookup_string(cfg, "endpoint", &i->endpoint))
cerror(cfg, "Missing NGSI endpoint for node %s", node_name(n));
/* Default values */
i->access_token = NULL; /* disabled by default */
i->ssl_verify = 1; /* verify by default */
i->timeout = 1; /* default value */
i->rate = 5; /* default value */
if (!config_setting_lookup_string(cfg, "entity_id", &i->entity_id))
cerror(cfg, "Missing NGSI entity ID for node %s", node_name(n));
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s: s, s: s, s: s, s?: b, s?: f, s?: f }",
"access_token", &i->access_token,
"endpoint", &i->endpoint,
"entity_id", &i->entity_id,
"entity_type", &i->entity_type,
"ssl_verify", &i->ssl_verify,
"timeout", &i->timeout,
"rate", &i->rate,
"mapping", &cfg_mapping
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
if (!config_setting_lookup_string(cfg, "entity_type", &i->entity_type))
cerror(cfg, "Missing NGSI entity type for node %s", node_name(n));
if (!config_setting_lookup_bool(cfg, "ssl_verify", &i->ssl_verify))
i->ssl_verify = 1; /* verify by default */
if (!config_setting_lookup_float(cfg, "timeout", &i->timeout))
i->timeout = 1; /* default value */
if (!config_setting_lookup_float(cfg, "rate", &i->rate))
i->rate = 5; /* default value */
config_setting_t *cfg_mapping = config_setting_get_member(cfg, "mapping");
if (!cfg_mapping)
cerror(cfg, "Missing mapping for node %s", node_name(n));
if (ngsi_parse_mapping(&i->mapping, cfg_mapping))
cerror(cfg_mapping, "Invalid mapping for node %s", node_name(n));
ret = ngsi_parse_mapping(&i->mapping, cfg_mapping);
if (ret)
error("Invalid setting 'mapping' of node %s", node_name(n));
return 0;
}

View file

@ -144,13 +144,20 @@ int opal_print_global()
return 0;
}
int opal_parse(struct node *n, config_setting_t *cfg)
int opal_parse(struct node *n, json_t *cfg)
{
struct opal *o = n->_vd;
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);
int ret;
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: b }",
"send_id", &o->send_id,
"recv_id", &o->recv_id,
"reply", &o->reply
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
return 0;
}

View file

@ -36,44 +36,49 @@
#include "timing.h"
#include "utils.h"
int shmem_parse(struct node *n, config_setting_t *cfg)
int shmem_parse(struct node *n, json_t *cfg)
{
struct shmem *shm = n->_vd;
const char *val;
if (!config_setting_lookup_string(cfg, "out_name", &shm->out_name))
cerror(cfg, "Missing shared memory output queue name");
int ret;
json_t *cfg_exec = NULL;
json_error_t err;
if (!config_setting_lookup_string(cfg, "in_name", &shm->in_name))
cerror(cfg, "Missing shared memory input queue name");
/* Default values */
shm->conf.queuelen = MAX(DEFAULT_SHMEM_QUEUELEN, n->vectorize);
shm->conf.samplelen = DEFAULT_SHMEM_SAMPLELEN;
shm->conf.polling = false;
shm->exec = NULL;
if (!config_setting_lookup_int(cfg, "queuelen", &shm->conf.queuelen))
shm->conf.queuelen = MAX(DEFAULT_SHMEM_QUEUELEN, n->vectorize);
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s: s, s?: i, s?: i, s?: b, s?: o }",
"out_name", &shm->out_name,
"in_name", &shm->in_name,
"queuelen", &shm->conf.queuelen,
"samplelen", &shm->conf.samplelen,
"polling", &shm->conf.polling,
"exec", &cfg_exec
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
if (!config_setting_lookup_int(cfg, "samplelen", &shm->conf.samplelen))
shm->conf.samplelen = DEFAULT_SHMEM_SAMPLELEN;
if (cfg_exec) {
if (!json_is_array(cfg_exec))
error("Setting 'exec' of node %s must be a JSON array of strings", node_name(n));
if (!config_setting_lookup_bool(cfg, "polling", &shm->conf.polling))
shm->conf.polling = false;
shm->exec = alloc(sizeof(char *) * (json_array_size(cfg_exec) + 1));
config_setting_t *exec_cfg = config_setting_lookup(cfg, "exec");
if (!exec_cfg)
shm->exec = NULL;
else {
if (!config_setting_is_array(exec_cfg))
cerror(exec_cfg, "Invalid format for exec");
size_t index;
json_t *cfg_val;
json_array_foreach(cfg_exec, index, cfg_val) {
val = json_string_value(cfg_exec);
if (!val)
error("Setting 'exec' of node %s must be a JSON array of strings", node_name(n));
shm->exec = alloc(sizeof(char *) * (config_setting_length(exec_cfg) + 1));
int i;
for (i = 0; i < config_setting_length(exec_cfg); i++) {
const char *elm = config_setting_get_string_elem(exec_cfg, i);
if (!elm)
cerror(exec_cfg, "Invalid format for exec");
shm->exec[i] = strdup(elm);
shm->exec[index] = strdup(val);
}
shm->exec[i] = NULL;
shm->exec[index] = NULL;
}
return 0;

View file

@ -45,43 +45,46 @@ enum signal_type signal_lookup_type(const char *type)
return -1;
}
int signal_parse(struct node *n, config_setting_t *cfg)
int signal_parse(struct node *n, json_t *cfg)
{
struct signal *s = n->_vd;
int ret;
const char *type;
const char *type = NULL;
if (!config_setting_lookup_string(cfg, "signal", &type))
s->type = SIGNAL_TYPE_MIXED;
else {
json_error_t err;
s->rt = 1;
s->limit = -1;
s->values = 1;
s->rate = 10;
s->frequency = 1;
s->amplitude = 1;
s->stddev = 0.02;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: i, s?: f, s?: f, s?: f, s?: f }",
"signal", &type,
"realtime", &s->rt,
"limit", &s->limit,
"values", &s->values,
"rate", &s->rate,
"frequency", &s->frequency,
"amplitude", &s->amplitude,
"stddev", &s->stddev
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
if (type) {
ret = signal_lookup_type(type);
if (ret == -1)
cerror(cfg, "Unknown signal type '%s'", type);
error("Unknown signal type '%s' of node %s", type, node_name(n));
s->type = ret;
}
if (!config_setting_lookup_bool(cfg, "realtime", &s->rt))
s->rt = 1;
if (!config_setting_lookup_int(cfg, "limit", &s->limit))
s->limit = -1;
if (!config_setting_lookup_int(cfg, "values", &s->values))
s->values = 1;
if (!config_setting_lookup_float(cfg, "rate", &s->rate))
s->rate = 10;
if (!config_setting_lookup_float(cfg, "frequency", &s->frequency))
s->frequency = 1;
if (!config_setting_lookup_float(cfg, "amplitude", &s->amplitude))
s->amplitude = 1;
if (!config_setting_lookup_float(cfg, "stddev", &s->stddev))
s->stddev = 0.02;
else
s->type = SIGNAL_TYPE_MIXED;
return 0;
}
@ -226,7 +229,7 @@ int signal_read(struct node *n, struct sample *smps[], unsigned cnt)
}
if (s->limit > 0 && s->counter >= s->limit) {
info("Reached limit");
info("Reached limit of node %s", node_name(n));
killme(SIGTERM);
pause();
}

View file

@ -561,18 +561,40 @@ int socket_write(struct node *n, struct sample *smps[], unsigned cnt)
return -1;
}
int socket_parse(struct node *n, config_setting_t *cfg)
int socket_parse(struct node *n, json_t *cfg)
{
config_setting_t *cfg_multicast;
const char *local, *remote, *layer, *hdr, *endian;
int ret;
struct socket *s = n->_vd;
const char *local, *remote;
const char *endian = NULL;
const char *layer = NULL;
const char *header = NULL;
int ret;
json_t *cfg_multicast = NULL;
json_error_t err;
/* Default values */
s->layer = SOCKET_LAYER_UDP;
s->header = SOCKET_HEADER_DEFAULT;
s->endian = SOCKET_ENDIAN_BIG;
s->verify_source = 0;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s: s, s: s, s?: b, s?: o }",
"layer", &layer,
"header", &header,
"endian", &endian,
"remote", &remote,
"local", &local,
"verify_source", &s->verify_source,
"multicast", &cfg_multicast
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
/* IP layer */
if (!config_setting_lookup_string(cfg, "layer", &layer))
s->layer = SOCKET_LAYER_UDP;
else {
if (layer) {
if (!strcmp(layer, "ip"))
s->layer = SOCKET_LAYER_IP;
#ifdef __linux__
@ -582,103 +604,89 @@ int socket_parse(struct node *n, config_setting_t *cfg)
else if (!strcmp(layer, "udp"))
s->layer = SOCKET_LAYER_UDP;
else
cerror(cfg, "Invalid layer '%s' for node %s", layer, node_name(n));
error("Invalid layer '%s' for node %s", layer, node_name(n));
}
/* Application header */
if (!config_setting_lookup_string(cfg, "header", &hdr))
s->header = SOCKET_HEADER_DEFAULT;
else {
if (!strcmp(hdr, "gtnet-skt") || (!strcmp(hdr, "none")))
if (header) {
if (!strcmp(header, "gtnet-skt") || (!strcmp(header, "none")))
s->header = SOCKET_HEADER_NONE;
else if (!strcmp(hdr, "gtnet-skt:fake") || (!strcmp(hdr, "fake")))
else if (!strcmp(header, "gtnet-skt:fake") || (!strcmp(header, "fake")))
s->header = SOCKET_HEADER_FAKE;
else if (!strcmp(hdr, "villas") || !strcmp(hdr, "default"))
else if (!strcmp(header, "villas") || !strcmp(header, "default"))
s->header = SOCKET_HEADER_DEFAULT;
else
cerror(cfg, "Invalid application header type '%s' for node %s", hdr, node_name(n));
error("Invalid application header type '%s' for node %s", header, node_name(n));
}
if (!config_setting_lookup_string(cfg, "endian", &endian))
s->endian = SOCKET_ENDIAN_BIG;
else {
if (endian) {
if (!strcmp(endian, "big") || !strcmp(endian, "network"))
s->endian = SOCKET_ENDIAN_BIG;
else if (!strcmp(endian, "little"))
s->endian = SOCKET_ENDIAN_LITTLE;
else
cerror(cfg, "Invalid endianness type '%s' for node %s", endian, node_name(n));
error("Invalid endianness type '%s' for node %s", endian, node_name(n));
}
if (!config_setting_lookup_string(cfg, "remote", &remote))
cerror(cfg, "Missing remote address for node %s", node_name(n));
if (!config_setting_lookup_string(cfg, "local", &local))
cerror(cfg, "Missing local address for node %s", node_name(n));
if (!config_setting_lookup_bool(cfg, "verify_source", &s->verify_source))
s->verify_source = 0;
ret = socket_parse_addr(local, (struct sockaddr *) &s->local, s->layer, AI_PASSIVE);
if (ret) {
cerror(cfg, "Failed to resolve local address '%s' of node %s: %s",
error("Failed to resolve local address '%s' of node %s: %s",
local, node_name(n), gai_strerror(ret));
}
ret = socket_parse_addr(remote, (struct sockaddr *) &s->remote, s->layer, 0);
if (ret) {
cerror(cfg, "Failed to resolve remote address '%s' of node %s: %s",
error("Failed to resolve remote address '%s' of node %s: %s",
remote, node_name(n), gai_strerror(ret));
}
cfg_multicast = config_setting_get_member(cfg, "multicast");
if (cfg_multicast) {
const char *group, *interface;
const char *group, *interface = NULL;
if (!config_setting_lookup_bool(cfg_multicast, "enabled", &s->multicast.enabled))
s->multicast.enabled = true;
/* Default values */
s->multicast.enabled = true;
s->multicast.mreq.imr_interface.s_addr = INADDR_ANY;
s->multicast.loop = 0;
s->multicast.ttl = 255;
if (!config_setting_lookup_string(cfg_multicast, "group", &group))
cerror(cfg_multicast, "The multicast group requires a 'group' setting.");
else {
ret = inet_aton(group, &s->multicast.mreq.imr_multiaddr);
if (!ret) {
cerror(cfg_multicast, "Failed to resolve multicast group address '%s' of node %s",
group, node_name(n));
}
ret = json_unpack_ex(cfg_multicast, &err, 0, "{ s?: b, s: s, s?: s, s?: b, s?: i }",
"enabled", &s->multicast.enabled,
"group", &group,
"interface", &interface,
"loop", &s->multicast.loop,
"ttl", &s->multicast.ttl
);
if (ret)
jerror(&err, "Failed to parse setting 'multicast' of node %s", node_name(n));
ret = inet_aton(group, &s->multicast.mreq.imr_multiaddr);
if (!ret) {
error("Failed to resolve multicast group address '%s' of node %s",
group, node_name(n));
}
if (!config_setting_lookup_string(cfg_multicast, "interface", &interface))
s->multicast.mreq.imr_interface.s_addr = INADDR_ANY;
else {
if (interface) {
ret = inet_aton(group, &s->multicast.mreq.imr_interface);
if (!ret) {
cerror(cfg_multicast, "Failed to resolve multicast interface address '%s' of node %s",
error("Failed to resolve multicast interface address '%s' of node %s",
interface, node_name(n));
}
}
int loop;
if (!config_setting_lookup_bool(cfg_multicast, "loop", &loop))
s->multicast.loop = 0;
else
s->multicast.loop = loop;
int ttl;
if (!config_setting_lookup_int(cfg_multicast, "ttl", &ttl))
s->multicast.ttl = 255;
else
s->multicast.ttl = ttl;
}
#ifdef WITH_NETEM
config_setting_t *cfg_netem;
json_t *cfg_netem;
cfg_netem = config_setting_get_member(cfg, "netem");
cfg_netem = json_object_get(cfg, "netem");
if (cfg_netem) {
int enabled = 1;
if (!config_setting_lookup_bool(cfg_netem, "enabled", &enabled) || enabled)
tc_parse(cfg_netem, &s->tc_qdisc);
ret = json_unpack_ex(cfg_netem, &err, 0, "{ s?: b }", "enabled", &enabled);
if (ret)
jerror(&err, "Failed to parse setting 'netem' of node %s", node_name(n));
if (enabled)
tc_parse(&s->tc_qdisc, cfg_netem);
else
s->tc_qdisc = NULL;
}

View file

@ -26,8 +26,6 @@
#include <string.h>
#include <signal.h>
#include <libconfig.h>
#include "super_node.h"
#include "webmsg.h"
#include "webmsg_format.h"
@ -510,36 +508,41 @@ int websocket_write(struct node *n, struct sample *smps[], unsigned cnt)
return cnt;
}
int websocket_parse(struct node *n, config_setting_t *cfg)
int websocket_parse(struct node *n, json_t *cfg)
{
struct websocket *w = n->_vd;
config_setting_t *cfg_dests;
int ret;
size_t index;
json_t *cfg_dests = NULL;
json_t *cfg_dest;
json_error_t err;
list_init(&w->connections);
list_init(&w->destinations);
cfg_dests = config_setting_get_member(cfg, "destinations");
if (cfg_dests) {
if (!config_setting_is_array(cfg_dests))
cerror(cfg_dests, "The 'destinations' setting must be an array of URLs");
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "destinations", &cfg_dests);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
for (int i = 0; i < config_setting_length(cfg_dests); i++) {
if (cfg_dests) {
if (!json_is_array(cfg_dests))
error("The 'destinations' setting of node %s must be an array of URLs", node_name(n));
json_array_foreach(cfg_dests, index, cfg_dest) {
const char *uri, *prot, *ads, *path;
uri = config_setting_get_string_elem(cfg_dests, i);
uri = json_string_value(cfg_dest);
if (!uri)
cerror(cfg_dests, "The 'destinations' setting must be an array of URLs");
error("The 'destinations' setting of node %s must be an array of URLs", node_name(n));
struct websocket_destination *d = alloc(sizeof(struct websocket_destination));
d->uri = strdup(uri);
if (!d->uri)
serror("Failed to allocate memory");
ret = lws_parse_uri(d->uri, &prot, &ads, &d->info.port, &path);
if (ret)
cerror(cfg_dests, "Failed to parse websocket URI: '%s'", uri);
error("Failed to parse WebSocket URI: '%s'", uri);
d->info.ssl_connection = !strcmp(prot, "https");
d->info.address = strdup(ads);

View file

@ -89,83 +89,92 @@ int zeromq_reverse(struct node *n)
return 0;
}
int zeromq_parse(struct node *n, config_setting_t *cfg)
int zeromq_parse(struct node *n, json_t *cfg)
{
struct zeromq *z = n->_vd;
const char *ep, *type, *filter;
int ret;
const char *ep = NULL;
const char *type = NULL;
const char *filter = NULL;
config_setting_t *cfg_pub, *cfg_curve;
size_t index;
json_t *cfg_pub = NULL;
json_t *cfg_curve = NULL;
json_t *cfg_val;
json_error_t err;
list_init(&z->publisher.endpoints);
if (config_setting_lookup_string(cfg, "subscribe", &ep))
z->subscriber.endpoint = strdup(ep);
else
z->subscriber.endpoint = NULL;
z->curve.enabled = false;
z->ipv6 = 0;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: o, s?: o, s?: s, s?: s, s?: b }",
"subscribe", &ep,
"publish", &cfg_pub,
"curve", &cfg_curve,
"filter", &filter,
"pattern", &type,
"ipv6", &z->ipv6
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
z->subscriber.endpoint = ep ? strdup(ep) : NULL;
z->filter = filter ? strdup(filter) : NULL;
cfg_pub = config_setting_lookup(cfg, "publish");
if (cfg_pub) {
switch (config_setting_type(cfg_pub)) {
case CONFIG_TYPE_LIST:
case CONFIG_TYPE_ARRAY:
for (int j = 0; j < config_setting_length(cfg_pub); j++) {
const char *ep = config_setting_get_string_elem(cfg_pub, j);
switch (json_typeof(cfg_pub)) {
case JSON_ARRAY:
json_array_foreach(cfg_pub, index, cfg_val) {
ep = json_string_value(cfg_pub);
if (!ep)
error("All 'publish' settings must be strings");
list_push(&z->publisher.endpoints, strdup(ep));
}
break;
case CONFIG_TYPE_STRING:
ep = config_setting_get_string(cfg_pub);
case JSON_STRING:
ep = json_string_value(cfg_pub);
list_push(&z->publisher.endpoints, strdup(ep));
break;
default:
cerror(cfg_pub, "Invalid type for ZeroMQ publisher setting");
error("Invalid type for ZeroMQ publisher setting");
}
}
cfg_curve = config_setting_lookup(cfg, "curve");
if (cfg_curve) {
if (!config_setting_is_group(cfg_curve))
cerror(cfg_curve, "The curve setting must be a group");
const char *public_key, *secret_key;
if (!config_setting_lookup_string(cfg_curve, "public_key", &public_key))
cerror(cfg_curve, "Setting 'curve.public_key' is missing");
z->curve.enabled = true;
if (!config_setting_lookup_string(cfg_curve, "secret_key", &secret_key))
cerror(cfg_curve, "Setting 'curve.secret_key' is missing");
if (!config_setting_lookup_bool(cfg_curve, "enabled", &z->curve.enabled))
z->curve.enabled = true;
ret = json_unpack_ex(cfg_curve, &err, 0, "{ s: s, s: s, s?: b }",
"public_key", &public_key,
"secret_key", &secret_key,
"enabled", &z->curve.enabled
);
if (ret)
jerror(&err, "Failed to parse setting 'curve' of node %s", node_name(n));
if (strlen(secret_key) != 40)
cerror(cfg_curve, "Setting 'curve.secret_key' must be a Z85 encoded CurveZMQ key");
error("Setting 'curve.secret_key' of node %s must be a Z85 encoded CurveZMQ key", node_name(n));
if (strlen(public_key) != 40)
cerror(cfg_curve, "Setting 'curve.public_key' must be a Z85 encoded CurveZMQ key");
error("Setting 'curve.public_key' of node %s must be a Z85 encoded CurveZMQ key", node_name(n));
strncpy(z->curve.server.public_key, public_key, 41);
strncpy(z->curve.server.secret_key, secret_key, 41);
}
else
z->curve.enabled = false;
/** @todo We should fix this. Its mostly done. */
if (z->curve.enabled)
cerror(cfg_curve, "CurveZMQ support is currently broken");
error("CurveZMQ support is currently broken");
if (config_setting_lookup_string(cfg, "filter", &filter))
z->filter = strdup(filter);
else
z->filter = NULL;
if (config_setting_lookup_string(cfg, "pattern", &type)) {
if (type) {
if (!strcmp(type, "pubsub"))
z->pattern = ZEROMQ_PATTERN_PUBSUB;
#ifdef ZMQ_BUILD_DISH
@ -173,12 +182,9 @@ int zeromq_parse(struct node *n, config_setting_t *cfg)
z->pattern = ZEROMQ_PATTERN_RADIODISH;
#endif
else
cerror(cfg, "Invalid type for ZeroMQ node: %s", node_name_short(n));
error("Invalid type for ZeroMQ node: %s", node_name_short(n));
}
if (!config_setting_lookup_bool(cfg, "ipv6", &z->ipv6))
z->ipv6 = 0;
return 0;
}

View file

@ -25,7 +25,6 @@
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include <libconfig.h>
#include "config.h"
#include "utils.h"
@ -39,6 +38,7 @@
#include "memory.h"
#include "stats.h"
#include "node.h"
#include "config_helper.h"
static void path_read(struct path *p)
{
@ -180,46 +180,51 @@ int path_init(struct path *p, struct super_node *sn)
return 0;
}
int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes)
int path_parse(struct path *p, json_t *cfg, struct list *nodes)
{
config_setting_t *cfg_out, *cfg_hooks;
const char *in;
int ret;
const char *in;
json_error_t err;
json_t *cfg_out = NULL;
json_t *cfg_hooks = NULL;
struct node *source;
struct list destinations = { .state = STATE_DESTROYED };
list_init(&destinations);
/* Input node */
if (!config_setting_lookup_string(cfg, "in", &in))
cerror(cfg, "Missing input node for path");
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: o, s?: o, s?: b, s?: b, s?: i, s?: i }",
"in", &in,
"out", &cfg_out,
"hooks", &cfg_hooks,
"reverse", &p->reverse,
"enabled", &p->enabled,
"samplelen", &p->samplelen,
"queuelen", &p->queuelen
);
if (ret)
jerror(&err, "Failed to parse path configuration");
/* Input node */
source = list_lookup(nodes, in);
if (!source)
cerror(cfg, "Invalid input node '%s'", in);
jerror(&err, "Invalid input node '%s'", in);
/* Output node(s) */
cfg_out = config_setting_get_member(cfg, "out");
if (cfg_out) {
ret = node_parse_list(&destinations, cfg_out, nodes);
if (ret)
cerror(cfg_out, "Failed to parse output nodes");
jerror(&err, "Failed to parse output nodes");
}
/* Optional settings */
cfg_hooks = config_setting_get_member(cfg, "hooks");
if (cfg_hooks) {
ret = hook_parse_list(&p->hooks, cfg_hooks, p);
if (ret)
return ret;
}
config_setting_lookup_bool(cfg, "reverse", &p->reverse);
config_setting_lookup_bool(cfg, "enabled", &p->enabled);
config_setting_lookup_int(cfg, "samplelen", &p->samplelen);
config_setting_lookup_int(cfg, "queuelen", &p->queuelen);
if (!IS_POW2(p->queuelen)) {
p->queuelen = LOG2_CEIL(p->queuelen);
warn("Queue length should always be a power of 2. Adjusting to %d", p->queuelen);
@ -242,6 +247,9 @@ int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes)
list_destroy(&destinations, NULL, false);
p->cfg = cfg;
p->state = STATE_PARSED;
return 0;
}

View file

@ -23,6 +23,7 @@
#include <dlfcn.h>
#include "plugin.h"
#include "config_helper.h"
/** Global list of all known plugins */
struct list plugins = { .state = STATE_DESTROYED };
@ -38,13 +39,15 @@ int plugin_init(struct plugin *p)
return 0;
}
int plugin_parse(struct plugin *p, config_setting_t *cfg)
int plugin_parse(struct plugin *p, json_t *cfg)
{
const char *path;
path = config_setting_get_string(cfg);
path = json_string_value(cfg);
if (!path)
cerror(cfg, "Setting 'plugin' must be a string.");
return -1;
p->path = strdup(path);
return 0;
}

View file

@ -124,7 +124,6 @@ void stats_collect(struct stats_delta *s, struct sample *smps[], size_t cnt)
s->last = previous;
}
#ifdef WITH_JSON
json_t * stats_json(struct stats *s)
{
json_t *obj = json_object();
@ -150,7 +149,6 @@ json_t * stats_json_periodic(struct stats *s, struct path *p)
"skipped", s->histograms[STATS_SKIPPED].total
);
}
#endif /* WITH_JSON */
void stats_reset(struct stats *s)
{
@ -209,13 +207,11 @@ void stats_print_periodic(struct stats *s, FILE *f, enum stats_format fmt, int v
);
break;
#ifdef WITH_JSON
case STATS_FORMAT_JSON: {
json_t *json_stats = stats_json_periodic(s, p);
json_dumpf(json_stats, f, 0);
break;
}
#endif /* WITH_JSON */
default: { }
}
@ -233,14 +229,12 @@ void stats_print(struct stats *s, FILE *f, enum stats_format fmt, int verbose)
}
break;
#ifdef WITH_JSON
case STATS_FORMAT_JSON: {
json_t *json_stats = stats_json(s);
json_dumpf(json_stats, f, 0);
fflush(f);
break;
}
#endif /* WITH_JSON */
default: { }
}

View file

@ -1,4 +1,4 @@
/** Configuration parser.
/** The super node object holding the state of the application.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
@ -42,30 +42,10 @@
#include "kernel/rt.h"
static void config_dtor(void *data)
{
if (data)
free(data);
}
static int super_node_parse_global(struct super_node *sn, config_setting_t *cfg)
{
if (!config_setting_is_group(cfg))
cerror(cfg, "Global section must be a dictionary.");
config_setting_lookup_int(cfg, "hugepages", &sn->hugepages);
config_setting_lookup_int(cfg, "affinity", &sn->affinity);
config_setting_lookup_int(cfg, "priority", &sn->priority);
config_setting_lookup_float(cfg, "stats", &sn->stats);
return 0;
}
int super_node_init(struct super_node *sn)
{
assert(sn->state == STATE_DESTROYED);
log_init(&sn->log, V, LOG_ALL);
#ifdef WITH_API
api_init(&sn->api, sn);
#endif /* WITH_API */
@ -83,6 +63,9 @@ int super_node_init(struct super_node *sn)
sn->stats = 0;
sn->hugepages = DEFAULT_NR_HUGEPAGES;
sn->name = alloc(128); /** @todo missing free */
gethostname(sn->name, 128);
sn->state = STATE_INITIALIZED;
return 0;
@ -90,85 +73,81 @@ int super_node_init(struct super_node *sn)
int super_node_parse_uri(struct super_node *sn, const char *uri)
{
int ret = CONFIG_FALSE;
json_error_t err;
if (uri) { INDENT
FILE *f;
AFILE *af;
config_setting_t *cfg_root = NULL;
/* Via stdin */
if (!strcmp("-", uri)) {
info("Reading configuration from stdin");
af = NULL;
f = stdin;
info("Reading configuration from stdin");
}
else {
/* Local file? */
if (access(uri, F_OK) != -1) {
/* Setup libconfig include path.
* This is only supported for local files */
char *uri_cpy = strdup(uri);
char *include_dir = dirname(uri_cpy);
config_set_include_dir(&sn->cfg, include_dir);
free(uri_cpy);
info("Reading configuration from local file: %s", uri);
}
else
info("Reading configuration from URI: %s", uri);
info("Reading configuration from URI: %s", uri);
af = afopen(uri, "r");
f = af ? af->file : NULL;
if (!af)
error("Failed to open configuration from: %s", uri);
f = af->file;
}
/* Check if file could be loaded / opened */
if (!f)
error("Failed to open configuration");
config_init(&sn->cfg);
config_set_destructor(&sn->cfg, config_dtor);
config_set_auto_convert(&sn->cfg, 1);
/* Parse config */
ret = config_read(&sn->cfg, f);
if (ret != CONFIG_TRUE) {
#ifdef WITH_JSON
/* This does not seem to be a valid libconfig configuration.
* Lets try to parse it as JSON instead. */
json_error_t err;
json_t *json;
sn->cfg = json_loadf(f, 0, &err);
if (sn->cfg == NULL) {
#ifdef WITH_LIBCONFIG
int ret;
json = json_loadf(f, 0, &err);
if (json) {
ret = json_to_config(json, cfg_root);
if (ret)
error("Failed t convert JSON to configuration file");
config_t cfg;
config_setting_t *cfg_root = NULL;
warn("Failed to parse JSON configuration. Re-trying with old libconfig format.");
{ INDENT
warn("Please consider migrating to the new format using the 'conf2json' command.");
}
else {
error("Failed to parse configuration");
config_init(&cfg);
config_set_auto_convert(&cfg, 1);
/* Setup libconfig include path.
* This is only supported for local files */
if (access(uri, F_OK) != -1) {
char *cpy = strdup(uri);
config_set_include_dir(&cfg, dirname(cpy));
free(cpy);
}
if (af)
arewind(af);
else
rewind(f);
ret = config_read(&cfg, f);
if (ret != CONFIG_TRUE) {
{ INDENT
warn("conf: %s in %s:%d", config_error_text(&sn->cfg), uri, config_error_line(&sn->cfg));
warn("conf: %s in %s:%d", config_error_text(&cfg), uri, config_error_line(&cfg));
warn("json: %s in %s:%d:%d", err.text, err.source, err.line, err.column);
}
error("Failed to parse configuration");
}
#else
error("Failed to parse configuration");
{ INDENT
warn("%s in %s:%d", config_error_text(&sn->cfg), uri, config_error_line(&sn->cfg));
}
#endif
}
/* Little hack to properly report configuration filename in error messages
* We add the uri as a "hook" object to the root setting.
* See cerror() on how this info is used.
*/
cfg_root = config_root_setting(&sn->cfg);
config_setting_set_hook(cfg_root, strdup(uri));
cfg_root = config_root_setting(&cfg);
sn->cfg = config_to_json(cfg_root);
if (sn->cfg == NULL)
error("Failed to convert JSON to configuration file");
config_destroy(&cfg);
#else
jerror(&err, "Failed to parse configuration file");
#endif /* WITH_LIBCONFIG */
}
/* Close configuration file */
if (af)
@ -176,11 +155,7 @@ int super_node_parse_uri(struct super_node *sn, const char *uri)
else if (f != stdin)
fclose(f);
ret = super_node_parse(sn, cfg_root);
config_destroy(&sn->cfg);
return ret;
return super_node_parse_json(sn, sn->cfg);
}
else { INDENT
warn("No configuration file specified. Starting unconfigured. Use the API to configure this instance.");
@ -199,105 +174,120 @@ int super_node_parse_cli(struct super_node *sn, int argc, char *argv[])
return super_node_parse_uri(sn, uri);
}
int super_node_parse(struct super_node *sn, config_setting_t *cfg)
int super_node_parse_json(struct super_node *sn, json_t *cfg)
{
int ret;
const char *name = NULL;
assert(sn->state != STATE_STARTED);
assert(sn->state != STATE_DESTROYED);
config_setting_t *cfg_nodes, *cfg_paths, *cfg_plugins, *cfg_logging;
json_t *cfg_nodes = NULL;
json_t *cfg_paths = NULL;
json_t *cfg_plugins = NULL;
json_t *cfg_logging = NULL;
json_t *cfg_web = NULL;
super_node_parse_global(sn, cfg);
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o, s?: o, s?: o, s?: o, s?: i, s?: i, s?: i, s?: F, s?: s }",
"http", &cfg_web,
"logging", &cfg_logging,
"plugins", &cfg_plugins,
"nodes", &cfg_nodes,
"paths", &cfg_paths,
"hugepages", &sn->hugepages,
"affinity", &sn->affinity,
"priority", &sn->priority,
"stats", &sn->stats,
"name", &name
);
if (ret)
jerror(&err, "Failed to parse global configuration");
if (name)
strncpy(sn->name, name, 128);
#ifdef WITH_WEB
config_setting_t *cfg_web;
cfg_web = config_setting_get_member(cfg, "http");
if (cfg_web)
web_parse(&sn->web, cfg_web);
#endif /* WITH_WEB */
/* Parse logging settings */
cfg_logging = config_setting_get_member(cfg, "logging");
if (cfg_logging)
log_parse(&sn->log, cfg_logging);
/* Parse plugins */
cfg_plugins = config_setting_get_member(cfg, "plugins");
if (cfg_plugins) {
if (!config_setting_is_array(cfg_plugins))
cerror(cfg_plugins, "Setting 'plugins' must be a list of strings");
for (int i = 0; i < config_setting_length(cfg_plugins); i++) {
struct config_setting_t *cfg_plugin = config_setting_get_elem(cfg_plugins, i);
if (!json_is_array(cfg_plugins))
error("Setting 'plugins' must be a list of strings");
size_t index;
json_t *cfg_plugin;
json_array_foreach(cfg_plugins, index, cfg_plugin) {
struct plugin *p = alloc(sizeof(struct plugin));
ret = plugin_init(p);
if (ret)
cerror(cfg_plugin, "Failed to initialize plugin");
error("Failed to initialize plugin");
ret = plugin_parse(p, cfg_plugin);
if (ret)
cerror(cfg_plugin, "Failed to parse plugin");
error("Failed to parse plugin");
list_push(&sn->plugins, p);
}
}
/* Parse nodes */
cfg_nodes = config_setting_get_member(cfg, "nodes");
if (cfg_nodes) {
if (!config_setting_is_group(cfg_nodes))
warn("Setting 'nodes' must be a group with node name => group mappings.");
for (int i = 0; i < config_setting_length(cfg_nodes); i++) {
config_setting_t *cfg_node = config_setting_get_elem(cfg_nodes, i);
if (!json_is_object(cfg_nodes))
error("Setting 'nodes' must be a group with node name => group mappings.");
const char *name;
json_t *cfg_node;
json_object_foreach(cfg_nodes, name, cfg_node) {
struct plugin *p;
const char *type;
/* Required settings */
if (!config_setting_lookup_string(cfg_node, "type", &type))
cerror(cfg_node, "Missing node type");
ret = json_unpack_ex(cfg_node, &err, 0, "{ s: s }", "type", &type);
if (ret)
jerror(&err, "Failed to parse node");
p = plugin_lookup(PLUGIN_TYPE_NODE, type);
if (!p)
cerror(cfg_node, "Invalid node type: %s", type);
error("Invalid node type: %s", type);
struct node *n = alloc(sizeof(struct node));
ret = node_init(n, &p->node);
if (ret)
cerror(cfg_node, "Failed to initialize node");
error("Failed to initialize node");
ret = node_parse(n, cfg_node);
ret = node_parse(n, cfg_node, name);
if (ret)
cerror(cfg_node, "Failed to parse node");
error("Failed to parse node");
list_push(&sn->nodes, n);
}
}
/* Parse paths */
cfg_paths = config_setting_get_member(cfg, "paths");
if (cfg_paths) {
if (!config_setting_is_list(cfg_paths))
if (!json_is_array(cfg_paths))
warn("Setting 'paths' must be a list.");
for (int i = 0; i < config_setting_length(cfg_paths); i++) {
config_setting_t *cfg_path = config_setting_get_elem(cfg_paths, i);
size_t index;
json_t *cfg_path;
json_array_foreach(cfg_paths, index, cfg_path) {
struct path *p = alloc(sizeof(struct path));
ret = path_init(p, sn);
if (ret)
cerror(cfg_path, "Failed to init path");
error("Failed to initialize path");
ret = path_parse(p, cfg_path, &sn->nodes);
if (ret)
cerror(cfg_path, "Failed to parse path");
error("Failed to parse path");
list_push(&sn->paths, p);
@ -306,11 +296,11 @@ int super_node_parse(struct super_node *sn, config_setting_t *cfg)
ret = path_init(r, sn);
if (ret)
cerror(cfg_path, "Failed to init path");
error("Failed to init path");
ret = path_reverse(p, r);
if (ret)
cerror(cfg_path, "Failed to reverse path %s", path_name(p));
error("Failed to reverse path %s", path_name(p));
list_push(&sn->paths, r);
}
@ -455,12 +445,17 @@ int super_node_destroy(struct super_node *sn)
#ifdef WITH_WEB
web_destroy(&sn->web);
#endif
#endif /* WITH_WEB */
#ifdef WITH_API
api_destroy(&sn->api);
#endif
#endif /* WITH_API */
json_decref(sn->cfg);
log_destroy(&sn->log);
if (sn->name)
free(sn->name);
sn->state = STATE_DESTROYED;
return 0;

View file

@ -20,7 +20,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <libconfig.h>
#include <libwebsockets.h>
#include <string.h>
@ -28,6 +27,7 @@
#include "log.h"
#include "web.h"
#include "api/session.h"
#include "config_helper.h"
#include "nodes/websocket.h"
@ -168,30 +168,37 @@ int web_init(struct web *w, struct api *a)
return 0;
}
int web_parse(struct web *w, config_setting_t *cfg)
int web_parse(struct web *w, json_t *cfg)
{
int enabled = true;
const char *ssl_cert, *ssl_private_key, *htdocs;
int ret, enabled = 1;
const char *ssl_cert = NULL;
const char *ssl_private_key = NULL;
const char *htdocs = NULL;
json_error_t err;
if (!config_setting_is_group(cfg))
cerror(cfg, "Setting 'http' must be a group.");
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s?: i, s?: b }",
"ssl_cert", &ssl_cert,
"ssl_private_key", &ssl_private_key,
"htdocs", &htdocs,
"port", &w->port,
"enabled", &enabled
);
if (ret)
jerror(&err, "Failed to http section of configuration file");
if (config_setting_lookup_string(cfg, "ssl_cert", &ssl_cert))
if (ssl_cert)
w->ssl_cert = strdup(ssl_cert);
if (config_setting_lookup_string(cfg, "ssl_private_key", &ssl_private_key))
if (ssl_private_key)
w->ssl_private_key = strdup(ssl_private_key);
if (config_setting_lookup_string(cfg, "htdocs", &htdocs)) {
if (htdocs) {
if (w->htdocs)
free(w->htdocs);
w->htdocs = strdup(htdocs);
}
config_setting_lookup_int(cfg, "port", &w->port);
config_setting_lookup_bool(cfg, "enabled", &enabled);
if (!enabled)
w->port = CONTEXT_PORT_NO_LISTEN;
@ -247,7 +254,7 @@ int web_start(struct web *w)
int web_stop(struct web *w)
{
if (w->state == STATE_STARTED)
if (w->state != STATE_STARTED)
return 0;
info("Stopping Web sub-system");

View file

@ -98,7 +98,6 @@ int web_buffer_read(struct web_buffer *b, char *out, size_t len)
return 0;
}
#ifdef WITH_JSON
int web_buffer_read_json(struct web_buffer *b, json_t **req)
{
json_error_t e;
@ -116,7 +115,6 @@ int web_buffer_read_json(struct web_buffer *b, json_t **req)
return 1;
}
#endif /* WITH_JSON */
int web_buffer_append(struct web_buffer *b, const char *in, size_t len)
{
@ -140,7 +138,6 @@ int web_buffer_append(struct web_buffer *b, const char *in, size_t len)
return 0;
}
#ifdef WITH_JSON
int web_buffer_append_json(struct web_buffer *b, json_t *res)
{
size_t len;
@ -162,4 +159,3 @@ retry: len = json_dumpb(res, b->buffer + b->prefix + b->len, b->size - b->len, 0
return 0;
}
#endif /* WITH_JSON */

View file

@ -37,6 +37,7 @@
#include <villas/pool.h>
#include <villas/log.h>
#include <villas/plugin.h>
#include <config_helper.h>
#include <villas/kernel/rt.h>
@ -103,20 +104,34 @@ int main(int argc, char *argv[])
/* Default values */
cnt = 1;
char c;
while ((c = getopt(argc, argv, "hv:d:")) != -1) {
json_t *cfg_cli = json_object();
char c, *endptr;
while ((c = getopt(argc, argv, "hv:d:f:o:")) != -1) {
switch (c) {
break;
case 'v':
cnt = atoi(optarg);
break;
cnt = strtoul(optarg, &endptr, 0);
goto check;
case 'd':
l.level = atoi(optarg);
l.level = strtoul(optarg, &endptr, 0);
goto check;
case 'o':
ret = json_object_extend_str(cfg_cli, optarg);
if (ret)
error("Invalid option: %s", optarg);
break;
case 'h':
case '?':
case 'h':
usage();
exit(c == '?' ? EXIT_FAILURE : EXIT_SUCCESS);
}
continue;
check: if (optarg == endptr)
error("Failed to parse parse option argument '-%c %s'", c, optarg);
}
if (argc < optind + 1) {
@ -156,7 +171,7 @@ int main(int argc, char *argv[])
if (ret)
error("Failed to initialize hook");
ret = hook_parse_cli(&h, argc - optind - 1, &argv[optind + 1]);
ret = hook_parse(&h, cfg_cli);
if (ret)
error("Failed to parse hook config");

View file

@ -33,11 +33,11 @@
#include <villas/super_node.h>
#include <villas/utils.h>
#include <villas/node.h>
#include <villas/msg.h>
#include <villas/timing.h>
#include <villas/pool.h>
#include <villas/io.h>
#include <villas/kernel/rt.h>
#include <villas/config_helper.h>
#include <villas/nodes/websocket.h>

View file

@ -22,6 +22,8 @@
#include <criterion/criterion.h>
#ifdef WITH_LIBCONFIG
#include <jansson.h>
#include <libconfig.h>
@ -114,3 +116,5 @@ Test(utils, json_to_config)
json_decref(json);
}
#endif

View file

@ -40,7 +40,6 @@ static struct vfio_container vc;
static void init()
{
int ret;
config_setting_t *cfg_root;
ret = super_node_init(&sn);
cr_assert_eq(ret, 0, "Failed to initialize Supernode");
@ -51,9 +50,6 @@ static void init()
ret = super_node_check(&sn);
cr_assert_eq(ret, 0, "Failed to check configuration");
cfg_root = config_root_setting(&sn.cfg);
cr_assert_neq(cfg_root, NULL);
ret = pci_init(&pci);
cr_assert_eq(ret, 0, "Failed to initialize PCI sub-system");
@ -62,7 +58,7 @@ static void init()
/* Parse FPGA configuration */
list_init(&cards);
ret = fpga_card_parse_list(&cards, cfg_root);
ret = fpga_card_parse_list(&cards, sn.cfg);
cr_assert_eq(ret, 0, "Failed to parse FPGA config");
card = list_lookup(&cards, "vc707");
@ -120,7 +116,7 @@ Test(fpga, xsg, .description = "XSG: multiply_add")
double factor, err = 0;
struct fpga_ip *ip, *dma;
struct model_param *p;
struct model_parameter *p;
struct dma_mem mem;
ip = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { NULL, "sysgen", "xsg_multiply", NULL });
@ -135,7 +131,7 @@ Test(fpga, xsg, .description = "XSG: multiply_add")
if (!p)
error("Missing parameter 'factor' for model '%s'", ip->name);
ret = model_param_read(p, &factor);
ret = model_parameter_read(p, &factor);
cr_assert_eq(ret, 0, "Failed to read parameter 'factor' from model '%s'", ip->name);
info("Model param: factor = %f", factor);

99
tests/unit/json.c Normal file
View file

@ -0,0 +1,99 @@
/** Unit tests for libjansson helpers
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <criterion/criterion.h>
#include <criterion/parameterized.h>
#include "config_helper.h"
#include "utils.h"
struct param {
const char *desc;
const char *json;
char *argv[32];
};
ParameterizedTestParameters(json, json_load_cli)
{
static struct param params[] = {
// Combined long option
{
.argv = { "dummy", "--option=value", NULL },
.json = "{ \"option\" : \"value\" }"
},
// Separated long option
{
.argv = { "dummy", "--option", "value", NULL },
.json = "{ \"option\" : \"value\" }"
},
// All kinds of data types
{
.argv = { "dummy", "--integer", "1", "--real", "1.1", "--bool", "true", "--null", "null", "--string", "hello world", NULL },
.json = "{ \"integer\" : 1, \"real\" : 1.1, \"bool\" : true, \"null\" : null, \"string\" : \"hello world\" }"
},
// Array generation
{
.argv = { "dummy", "--bool", "true", "--bool", "false", NULL },
.json = "{ \"bool\" : [ true, false ] }"
},
// Dots in the option name generate sub objects
{
.argv = { "dummy", "--sub.option", "value", NULL },
.json = "{ \"sub\" : { \"option\" : \"value\" } }"
},
// Nesting is possible
{
.argv = { "dummy", "--sub.sub.option", "value", NULL },
.json = "{ \"sub\" : { \"sub\" : { \"option\" : \"value\" } } }"
},
// Multiple subgroups are merged
{
.argv = { "dummy", "--sub.sub.option", "value1", "--sub.option", "value2", NULL },
.json = "{ \"sub\" : { \"option\" : \"value2\", \"sub\" : { \"option\" : \"value1\" } } }"
}
};
return cr_make_param_array(struct param, params, ARRAY_LEN(params));
}
ParameterizedTest(struct param *p, json, json_load_cli)
{
json_error_t err;
json_t *json, *cli;
/* Calculate argc */
int argc = 0;
while (p->argv[argc])
argc++;
json = json_loads(p->json, 0, &err);
cr_assert_not_null(json);
cli = json_load_cli(argc, p->argv);
cr_assert_not_null(cli);
//json_dumpf(json, stdout, JSON_INDENT(2)); putc('\n', stdout);
//json_dumpf(cli, stdout, JSON_INDENT(2)); putc('\n', stdout);
cr_assert(json_equal(json, cli));
}