2014-07-14 11:49:44 +00:00
|
|
|
/** Nodes.
|
2014-06-05 09:34:29 +00:00
|
|
|
*
|
2022-12-14 17:41:58 +01:00
|
|
|
* @author Steffen Vogel <post@steffenvogel.de>
|
2022-03-15 09:28:57 -04:00
|
|
|
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
|
2022-07-04 18:20:03 +02:00
|
|
|
* @license Apache 2.0
|
2015-06-02 21:53:04 +02:00
|
|
|
*********************************************************************************/
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2020-08-25 20:24:46 +02:00
|
|
|
#include <regex>
|
2019-06-23 16:57:00 +02:00
|
|
|
#include <cstring>
|
|
|
|
#include <cctype>
|
2019-10-30 02:38:56 +01:00
|
|
|
#include <openssl/md5.h>
|
2016-11-20 12:59:37 -05:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
#ifdef __linux__
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <villas/node/config.hpp>
|
2019-06-23 16:13:23 +02:00
|
|
|
#include <villas/hook.hpp>
|
2019-04-23 13:12:04 +02:00
|
|
|
#include <villas/hook_list.hpp>
|
2021-08-10 10:12:48 -04:00
|
|
|
#include <villas/sample.hpp>
|
|
|
|
#include <villas/node.hpp>
|
2021-06-21 16:12:47 -04:00
|
|
|
#include <villas/node_list.hpp>
|
2021-08-10 10:12:48 -04:00
|
|
|
#include <villas/path.hpp>
|
2019-04-23 13:09:50 +02:00
|
|
|
#include <villas/utils.hpp>
|
2021-09-19 19:26:03 +02:00
|
|
|
#include <villas/uuid.hpp>
|
2019-04-23 13:11:08 +02:00
|
|
|
#include <villas/colors.hpp>
|
2021-08-10 10:12:48 -04:00
|
|
|
#include <villas/mapping.hpp>
|
|
|
|
#include <villas/timing.hpp>
|
|
|
|
#include <villas/signal.hpp>
|
|
|
|
#include <villas/node/memory.hpp>
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2019-01-21 22:14:41 +01:00
|
|
|
#ifdef WITH_NETEM
|
2020-09-13 11:01:20 +02:00
|
|
|
#include <villas/kernel/if.hpp>
|
|
|
|
#include <villas/kernel/nl.hpp>
|
|
|
|
#include <villas/kernel/tc.hpp>
|
|
|
|
#include <villas/kernel/tc_netem.hpp>
|
2019-01-21 22:14:41 +01:00
|
|
|
#endif /* WITH_NETEM */
|
|
|
|
|
2019-06-23 13:35:42 +02:00
|
|
|
using namespace villas;
|
2021-06-21 16:12:47 -04:00
|
|
|
using namespace villas::node;
|
2019-06-04 16:55:38 +02:00
|
|
|
using namespace villas::utils;
|
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
Node::Node(const uuid_t &id, const std::string &name) :
|
2021-08-10 10:12:48 -04:00
|
|
|
logger(logging.get("node")),
|
|
|
|
sequence_init(0),
|
|
|
|
sequence(0),
|
|
|
|
in(NodeDirection::Direction::IN, this),
|
|
|
|
out(NodeDirection::Direction::OUT, this),
|
2019-02-15 09:46:26 +01:00
|
|
|
#ifdef __linux__
|
2021-08-10 10:12:48 -04:00
|
|
|
fwmark(-1),
|
2019-02-15 11:18:32 +01:00
|
|
|
#endif /* __linux__ */
|
2019-01-21 15:50:18 +01:00
|
|
|
#ifdef WITH_NETEM
|
2021-08-10 10:12:48 -04:00
|
|
|
tc_qdisc(nullptr),
|
|
|
|
tc_classifier(nullptr),
|
2019-01-21 15:50:18 +01:00
|
|
|
#endif /* WITH_NETEM */
|
2021-08-10 10:12:48 -04:00
|
|
|
state(State::INITIALIZED),
|
|
|
|
enabled(true),
|
|
|
|
config(nullptr),
|
2023-06-30 10:51:01 +02:00
|
|
|
name_short(name),
|
2021-08-10 10:12:48 -04:00
|
|
|
affinity(-1), /* all cores */
|
|
|
|
factory(nullptr)
|
|
|
|
{
|
2023-06-30 10:51:01 +02:00
|
|
|
if (uuid_is_null(id)) {
|
|
|
|
uuid_generate_random(uuid);
|
|
|
|
} else {
|
|
|
|
uuid_copy(uuid, id);
|
|
|
|
}
|
2019-01-21 15:50:18 +01:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
if (!name_short.empty()) {
|
|
|
|
name_long = fmt::format(CLR_RED("{}"), name_short);
|
|
|
|
}
|
|
|
|
else if (name_short.empty()) {
|
|
|
|
name_short = "<none>";
|
|
|
|
name_long = CLR_RED("<none>");
|
|
|
|
}
|
2021-08-10 10:12:48 -04:00
|
|
|
}
|
2018-05-24 09:04:41 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
Node::~Node()
|
|
|
|
{
|
|
|
|
#ifdef WITH_NETEM
|
|
|
|
rtnl_qdisc_put(tc_qdisc);
|
|
|
|
rtnl_cls_put(tc_classifier);
|
|
|
|
#endif /* WITH_NETEM */
|
2018-05-24 09:04:41 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
factory->instances.remove(this);
|
2018-05-24 09:04:41 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::prepare()
|
2018-08-20 18:31:27 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = in.prepare();
|
2019-03-15 17:19:28 +01:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = out.prepare();
|
2018-08-20 18:31:27 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
state = State::PREPARED;
|
2019-02-24 11:13:28 +01:00
|
|
|
|
2018-08-20 18:31:27 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
int Node::parse(json_t *json)
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
assert(state == State::INITIALIZED ||
|
|
|
|
state == State::PARSED ||
|
|
|
|
state == State::CHECKED);
|
|
|
|
|
|
|
|
int ret, en = enabled, init_seq = -1;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
json_error_t err;
|
2019-04-08 08:59:08 +02:00
|
|
|
json_t *json_netem = nullptr;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
ret = json_unpack_ex(json, &err, 0, "{ s?: b, s?: i }",
|
2021-08-10 10:12:48 -04:00
|
|
|
"enabled", &en,
|
|
|
|
"initial_sequenceno", &init_seq
|
2019-02-15 09:46:26 +01:00
|
|
|
);
|
|
|
|
if (ret)
|
2019-03-26 15:36:24 +01:00
|
|
|
return ret;
|
2019-02-15 09:46:26 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
if (init_seq >= 0)
|
|
|
|
sequence_init = init_seq;
|
|
|
|
|
2019-02-15 09:46:26 +01:00
|
|
|
#ifdef __linux__
|
2019-02-15 11:18:32 +01:00
|
|
|
ret = json_unpack_ex(json, &err, 0, "{ s?: { s?: o, s?: i } }",
|
2019-01-21 15:50:18 +01:00
|
|
|
"out",
|
2019-02-15 09:42:53 +01:00
|
|
|
"netem", &json_netem,
|
2021-08-10 10:12:48 -04:00
|
|
|
"fwmark", &fwmark
|
2017-08-03 00:19:27 +02:00
|
|
|
);
|
|
|
|
if (ret)
|
2019-03-26 15:36:24 +01:00
|
|
|
return ret;
|
2019-02-15 09:46:26 +01:00
|
|
|
#endif /* __linux__ */
|
2016-06-08 22:38:21 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
enabled = en;
|
2020-10-16 11:08:40 +02:00
|
|
|
|
2019-01-21 15:50:18 +01:00
|
|
|
if (json_netem) {
|
|
|
|
#ifdef WITH_NETEM
|
|
|
|
int enabled = 1;
|
|
|
|
|
|
|
|
ret = json_unpack_ex(json_netem, &err, 0, "{ s?: b }", "enabled", &enabled);
|
|
|
|
if (ret)
|
2019-03-26 15:36:24 +01:00
|
|
|
return ret;
|
2019-01-21 15:50:18 +01:00
|
|
|
|
|
|
|
if (enabled)
|
2021-08-10 10:12:48 -04:00
|
|
|
kernel::tc::netem_parse(&tc_qdisc, json_netem);
|
2019-01-21 15:50:18 +01:00
|
|
|
else
|
2021-08-10 10:12:48 -04:00
|
|
|
tc_qdisc = nullptr;
|
2019-01-21 15:50:18 +01:00
|
|
|
#endif /* WITH_NETEM */
|
|
|
|
}
|
|
|
|
|
2018-06-12 20:45:03 +02:00
|
|
|
struct {
|
|
|
|
const char *str;
|
2021-08-10 10:12:48 -04:00
|
|
|
struct NodeDirection *dir;
|
2018-06-12 20:45:03 +02:00
|
|
|
} dirs[] = {
|
2021-08-10 10:12:48 -04:00
|
|
|
{ "in", &in },
|
|
|
|
{ "out", &out }
|
2018-06-12 20:45:03 +02:00
|
|
|
};
|
2018-05-26 01:10:33 +02:00
|
|
|
|
2019-02-06 13:11:57 +01:00
|
|
|
const char *fields[] = { "signals", "builtin", "vectorize", "hooks" };
|
2018-06-12 20:45:03 +02:00
|
|
|
|
2019-04-07 15:13:40 +02:00
|
|
|
for (unsigned j = 0; j < ARRAY_LEN(dirs); j++) {
|
2018-08-20 18:31:27 +02:00
|
|
|
json_t *json_dir = json_object_get(json, dirs[j].str);
|
2018-06-12 20:45:03 +02:00
|
|
|
|
2019-03-26 07:09:55 +01:00
|
|
|
/* Skip if direction is unused */
|
2021-08-10 10:12:48 -04:00
|
|
|
if (!json_dir) {
|
2018-06-15 14:36:00 +02:00
|
|
|
json_dir = json_pack("{ s: b }", "enabled", 0);
|
2021-08-10 10:12:48 -04:00
|
|
|
}
|
2018-06-12 20:45:03 +02:00
|
|
|
|
2019-03-26 07:09:55 +01:00
|
|
|
/* Copy missing fields from main node config to direction config */
|
2019-04-07 15:13:40 +02:00
|
|
|
for (unsigned i = 0; i < ARRAY_LEN(fields); i++) {
|
2018-06-12 20:45:03 +02:00
|
|
|
json_t *json_field_dir = json_object_get(json_dir, fields[i]);
|
|
|
|
json_t *json_field_node = json_object_get(json, fields[i]);
|
|
|
|
|
|
|
|
if (json_field_node && !json_field_dir)
|
|
|
|
json_object_set(json_dir, fields[i], json_field_node);
|
|
|
|
}
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = dirs[j].dir->parse(json_dir);
|
2018-03-21 16:59:19 +01:00
|
|
|
if (ret)
|
2019-03-26 15:36:24 +01:00
|
|
|
return ret;
|
2018-03-21 16:59:19 +01:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
config = json;
|
2016-06-08 22:38:21 +02:00
|
|
|
|
2019-03-26 15:36:24 +01:00
|
|
|
return 0;
|
2015-03-31 13:54:04 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::check()
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
assert(state == State::CHECKED ||
|
|
|
|
state == State::PARSED ||
|
|
|
|
state == State::INITIALIZED);
|
2017-03-11 23:50:30 -03:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
in.check();
|
|
|
|
out.check();
|
2018-07-02 10:59:45 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
state = State::CHECKED;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
|
|
|
return 0;
|
2015-03-31 13:54:04 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::start()
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2015-11-16 10:51:00 +01:00
|
|
|
int ret;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
assert(state == State::PREPARED);
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->info("Starting node {}", getNameFull());
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = in.start();
|
2018-08-20 18:31:27 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2017-03-13 23:51:38 -03:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = out.start();
|
2018-08-20 18:31:27 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2019-01-21 15:50:18 +01:00
|
|
|
#ifdef __linux__
|
|
|
|
/* Set fwmark for outgoing packets if netem is enabled for this node */
|
2021-08-10 10:12:48 -04:00
|
|
|
if (fwmark >= 0) {
|
2022-02-25 09:51:38 -05:00
|
|
|
for (int fd : getNetemFDs()) {
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = setsockopt(fd, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark));
|
2019-01-21 15:50:18 +01:00
|
|
|
if (ret)
|
2020-09-11 14:57:05 +02:00
|
|
|
throw RuntimeError("Failed to set FW mark for outgoing packets");
|
2019-01-21 15:50:18 +01:00
|
|
|
else
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->debug("Set FW mark for socket (sd={}) to {}", fd, fwmark);
|
2019-01-21 15:50:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* __linux__ */
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
state = State::STARTED;
|
|
|
|
sequence = sequence_init;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2020-09-11 14:57:05 +02:00
|
|
|
return 0;
|
2014-12-05 12:39:52 +01:00
|
|
|
}
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::stop()
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2015-11-16 10:51:00 +01:00
|
|
|
int ret;
|
|
|
|
|
2022-03-14 15:32:20 -04:00
|
|
|
if (state != State::STOPPING &&
|
|
|
|
state != State::STARTED &&
|
|
|
|
state != State::CONNECTED &&
|
|
|
|
state != State::PENDING_CONNECT)
|
2017-03-29 04:25:30 +02:00
|
|
|
return 0;
|
2015-11-29 22:45:46 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->info("Stopping node");
|
2022-03-14 15:32:20 -04:00
|
|
|
setState(State::STOPPING);
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = in.stop();
|
2018-11-22 09:56:40 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = out.stop();
|
2018-11-22 09:56:40 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2018-11-22 09:56:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::restart()
|
2017-03-11 23:50:30 -03:00
|
|
|
{
|
2018-05-24 09:04:41 +02:00
|
|
|
int ret;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
assert(state == State::STARTED);
|
2018-05-24 09:04:41 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->info("Restarting node");
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = stop();
|
2020-09-10 11:20:35 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
ret = start();
|
2020-09-10 11:20:35 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::read(struct Sample * smps[], unsigned cnt)
|
2017-03-11 23:50:30 -03:00
|
|
|
{
|
2020-09-03 15:03:18 +02:00
|
|
|
int toread, readd, nread = 0;
|
|
|
|
unsigned vect;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
if (state == State::PAUSED || state == State::PENDING_CONNECT)
|
2019-02-11 16:39:30 +01:00
|
|
|
return 0;
|
2021-08-10 10:12:48 -04:00
|
|
|
else if (state != State::STARTED && state != State::CONNECTED)
|
2019-02-11 16:39:30 +01:00
|
|
|
return -1;
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
vect = factory->getVectorize();
|
2020-08-28 09:43:34 +02:00
|
|
|
if (!vect)
|
|
|
|
vect = cnt;
|
2017-09-02 14:20:38 +02:00
|
|
|
|
2020-08-28 09:43:34 +02:00
|
|
|
while (cnt - nread > 0) {
|
2020-09-03 15:03:18 +02:00
|
|
|
toread = MIN(cnt - nread, vect);
|
2021-08-10 10:12:48 -04:00
|
|
|
readd = _read(&smps[nread], toread);
|
2020-08-28 09:43:34 +02:00
|
|
|
if (readd < 0)
|
|
|
|
return readd;
|
|
|
|
|
|
|
|
nread += readd;
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-12-09 02:23:29 +08:00
|
|
|
#ifdef WITH_HOOKS
|
2017-09-04 14:28:55 +02:00
|
|
|
/* Run read hooks */
|
2021-08-10 10:12:48 -04:00
|
|
|
int rread = in.hooks.process(smps, nread);
|
2021-02-22 23:16:53 +01:00
|
|
|
if (rread < 0)
|
|
|
|
return rread;
|
|
|
|
|
2018-05-23 02:25:27 +02:00
|
|
|
int skipped = nread - rread;
|
2021-02-22 23:16:53 +01:00
|
|
|
if (skipped > 0) {
|
2021-08-10 10:12:48 -04:00
|
|
|
if (stats != nullptr)
|
|
|
|
stats->update(Stats::Metric::SMPS_SKIPPED, skipped);
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->debug("Received {} samples of which {} have been skipped", nread, skipped);
|
2017-09-02 14:27:58 +02:00
|
|
|
}
|
2021-02-22 23:16:53 +01:00
|
|
|
else
|
2022-02-25 09:56:15 -05:00
|
|
|
logger->debug("Received {} samples", nread);
|
2018-05-23 02:25:27 +02:00
|
|
|
|
2017-09-02 14:27:58 +02:00
|
|
|
return rread;
|
2017-12-09 02:23:29 +08:00
|
|
|
#else
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->debug("Received {} samples", nread);
|
2018-05-23 02:25:27 +02:00
|
|
|
|
2017-12-09 02:23:29 +08:00
|
|
|
return nread;
|
|
|
|
#endif /* WITH_HOOKS */
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int Node::write(struct Sample * smps[], unsigned cnt)
|
2017-03-11 23:50:30 -03:00
|
|
|
{
|
2020-09-03 15:03:18 +02:00
|
|
|
int tosend, sent, nsent = 0;
|
|
|
|
unsigned vect;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
if (state == State::PAUSED || state == State::PENDING_CONNECT)
|
2019-02-11 16:39:30 +01:00
|
|
|
return 0;
|
2021-08-10 10:12:48 -04:00
|
|
|
else if (state != State::STARTED && state != State::CONNECTED)
|
2019-02-11 16:39:30 +01:00
|
|
|
return -1;
|
|
|
|
|
2017-12-09 02:23:29 +08:00
|
|
|
#ifdef WITH_HOOKS
|
2017-09-16 15:04:59 +02:00
|
|
|
/* Run write hooks */
|
2021-08-10 10:12:48 -04:00
|
|
|
cnt = out.hooks.process(smps, cnt);
|
2017-09-02 14:27:58 +02:00
|
|
|
if (cnt <= 0)
|
|
|
|
return cnt;
|
2017-12-09 02:23:29 +08:00
|
|
|
#endif /* WITH_HOOKS */
|
2017-09-02 14:27:58 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
vect = getFactory()->getVectorize();
|
2020-08-28 09:43:34 +02:00
|
|
|
if (!vect)
|
|
|
|
vect = cnt;
|
2017-08-22 12:31:12 +02:00
|
|
|
|
2020-08-28 09:43:34 +02:00
|
|
|
while (cnt - nsent > 0) {
|
2020-09-03 15:03:18 +02:00
|
|
|
tosend = MIN(cnt - nsent, vect);
|
2021-08-10 10:12:48 -04:00
|
|
|
sent = _write(&smps[nsent], tosend);
|
2020-08-28 09:43:34 +02:00
|
|
|
if (sent < 0)
|
|
|
|
return sent;
|
2017-08-22 12:31:12 +02:00
|
|
|
|
2020-08-28 09:43:34 +02:00
|
|
|
nsent += sent;
|
2021-08-10 10:12:48 -04:00
|
|
|
logger->debug("Sent {} samples", sent);
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
return nsent;
|
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
const std::string & Node::getNameFull()
|
2015-10-17 19:05:15 +02:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
if (name_full.empty()) {
|
|
|
|
name_full = fmt::format("{}: uuid={}, #in.signals={}/{}, #in.hooks={}, #out.hooks={}, in.vectorize={}, out.vectorize={}",
|
2023-06-30 13:00:01 +02:00
|
|
|
getName(), uuid::toString(uuid).c_str(),
|
2021-08-10 10:12:48 -04:00
|
|
|
getInputSignals(false)->size(),
|
|
|
|
getInputSignals(true)->size(),
|
|
|
|
in.hooks.size(), out.hooks.size(),
|
|
|
|
in.vectorize, out.vectorize
|
2020-07-04 17:15:54 +02:00
|
|
|
);
|
2018-05-24 09:04:41 +02:00
|
|
|
|
2019-01-30 00:42:35 +01:00
|
|
|
#ifdef WITH_NETEM
|
2021-08-10 10:12:48 -04:00
|
|
|
name_full += fmt::format(", out.netem={}", tc_qdisc ? "yes" : "no");
|
2019-01-30 00:42:35 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
if (tc_qdisc)
|
|
|
|
name_full += fmt::format(", fwmark={}", fwmark);
|
2019-01-30 00:42:35 +01:00
|
|
|
#endif /* WITH_NETEM */
|
2019-01-21 23:00:16 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
if (out.path) {
|
|
|
|
name_full += fmt::format(", #out.signals={}/{}",
|
|
|
|
getOutputSignals(false) ? getOutputSignals(false)->size() : 0,
|
|
|
|
getOutputSignals() ? getOutputSignals()->size() : 0);
|
2020-07-04 17:15:54 +02:00
|
|
|
|
2023-01-10 15:25:27 +01:00
|
|
|
name_full += fmt::format(", out.path={}", out.path->toString());
|
2015-12-11 18:19:35 +01:00
|
|
|
}
|
2021-08-10 10:12:48 -04:00
|
|
|
|
|
|
|
/* Append node-type specific details */
|
|
|
|
auto details = getDetails();
|
|
|
|
if (!details.empty())
|
|
|
|
name_full += fmt::format(", {}", details);
|
2015-12-11 18:19:35 +01:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
return name_full;
|
2015-10-17 19:05:15 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
SignalList::Ptr Node::getInputSignals(bool after_hooks) const
|
2015-12-13 02:02:29 +01:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
return in.getSignals(after_hooks);
|
2015-12-13 02:02:29 +01:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
SignalList::Ptr Node::getOutputSignals(bool after_hooks) const
|
2015-03-18 16:18:10 +01:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
if (out.path)
|
|
|
|
return out.path->getOutputSignals();
|
2015-03-21 15:23:57 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
return nullptr;
|
2019-01-21 15:47:34 +01:00
|
|
|
}
|
2019-01-21 15:50:18 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
unsigned Node::getInputSignalsMaxCount() const
|
2017-08-30 00:22:58 +02:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
return in.getSignalsMaxCount();
|
2017-08-30 00:22:58 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
unsigned Node::getOutputSignalsMaxCount() const
|
2018-06-29 17:32:07 +02:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
if (out.path)
|
|
|
|
return out.path->getOutputSignalsMaxCount();
|
|
|
|
|
|
|
|
return 0;
|
2018-06-29 17:32:07 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
bool Node::isValidName(const std::string &name)
|
2015-03-21 15:23:57 +01:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
std::regex re(RE_NODE_NAME);
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
return std::regex_match(name, re);
|
|
|
|
}
|
2021-02-16 14:15:14 +01:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
json_t * Node::toJson() const
|
|
|
|
{
|
|
|
|
json_t *json_node;
|
|
|
|
json_t *json_signals_in = nullptr;
|
|
|
|
json_t *json_signals_out = nullptr;
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
json_signals_in = getInputSignals()->toJson();
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
auto output_signals = getOutputSignals();
|
|
|
|
if (output_signals)
|
|
|
|
json_signals_out = output_signals->toJson();
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
json_node = json_pack("{ s: s, s: s, s: s, s: i, s: { s: i, s: o? }, s: { s: i, s: o? } }",
|
|
|
|
"name", getNameShort().c_str(),
|
2023-06-30 13:00:01 +02:00
|
|
|
"uuid", uuid::toString(uuid).c_str(),
|
2021-08-10 10:12:48 -04:00
|
|
|
"state", stateToString(state).c_str(),
|
|
|
|
"affinity", affinity,
|
|
|
|
"in",
|
|
|
|
"vectorize", in.vectorize,
|
|
|
|
"signals", json_signals_in,
|
|
|
|
"out",
|
|
|
|
"vectorize", out.vectorize,
|
|
|
|
"signals", json_signals_out
|
|
|
|
);
|
2016-11-20 12:59:37 -05:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
if (stats)
|
|
|
|
json_object_set_new(json_node, "stats", stats->toJson());
|
2016-11-20 12:59:37 -05:00
|
|
|
|
2023-06-30 11:52:14 +02:00
|
|
|
auto *status = _readStatus();
|
|
|
|
if (status)
|
|
|
|
json_object_set_new(json_node, "status", status);
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
/* Add all additional fields of node here.
|
|
|
|
* This can be used for metadata */
|
|
|
|
json_object_update(json_node, config);
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
return json_node;
|
|
|
|
}
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
void Node::swapSignals() {
|
|
|
|
SWAP(in.signals, out.signals);
|
|
|
|
}
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
Node * NodeFactory::make(json_t *json, const uuid_t &id, const std::string &name)
|
2021-08-10 10:12:48 -04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
std::string type;
|
|
|
|
Node *n;
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
if (json_is_object(json))
|
|
|
|
throw ConfigError(json, "node-config-node", "Node configuration must be an object");
|
2017-08-03 00:19:27 +02:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
json_t *json_type = json_object_get(json, "type");
|
2019-02-12 17:54:08 +01:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
type = json_string_value(json_type);
|
2019-02-24 11:10:44 +01:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
n = NodeFactory::make(type, id, name);
|
|
|
|
if (!n)
|
|
|
|
return nullptr;
|
2019-02-24 11:08:15 +01:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
ret = n->parse(json);
|
|
|
|
if (ret) {
|
|
|
|
delete n;
|
|
|
|
return nullptr;
|
2021-08-10 10:12:48 -04:00
|
|
|
}
|
2023-06-30 10:51:01 +02:00
|
|
|
|
|
|
|
return n;
|
2020-10-21 20:56:51 +02:00
|
|
|
}
|
2019-03-08 15:21:01 +01:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
Node * NodeFactory::make(const std::string &type, const uuid_t &id, const std::string &name)
|
2020-10-21 20:56:51 +02:00
|
|
|
{
|
2022-02-25 09:55:43 -05:00
|
|
|
NodeFactory *nf = plugin::registry->lookup<NodeFactory>(type);
|
2021-08-10 10:12:48 -04:00
|
|
|
if (!nf)
|
|
|
|
throw RuntimeError("Unknown node-type: {}", type);
|
2020-10-21 20:56:51 +02:00
|
|
|
|
2023-06-30 10:51:01 +02:00
|
|
|
return nf->make(id, name);
|
2019-02-12 17:54:08 +01:00
|
|
|
}
|
2020-08-25 20:24:18 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int NodeFactory::start(SuperNode *sn)
|
2021-07-01 22:26:44 +02:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
getLogger()->info("Initialized node type which is used by {} nodes", instances.size());
|
2021-07-01 22:26:44 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
state = State::STARTED;
|
2021-07-01 22:26:44 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
int NodeFactory::stop()
|
2020-08-25 20:24:18 +02:00
|
|
|
{
|
2021-08-10 10:12:48 -04:00
|
|
|
getLogger()->info("De-initialized node type");
|
2020-08-25 20:24:18 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
state = State::STOPPED;
|
2020-08-25 20:24:18 +02:00
|
|
|
|
2021-08-10 10:12:48 -04:00
|
|
|
return 0;
|
2020-08-28 09:43:34 +02:00
|
|
|
}
|