mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
added parser for netem settings and several functions to apply them
git-svn-id: https://zerberus.eonerc.rwth-aachen.de:8443/svn/s2ss/trunk@79 8ec27952-4edc-4aab-86aa-e87bb2611832
This commit is contained in:
parent
b8faadfe59
commit
bd60c4424b
6 changed files with 219 additions and 13 deletions
|
@ -19,7 +19,18 @@ nodes = {
|
|||
id = 2,
|
||||
type = "rtds",
|
||||
local = "127.0.0.1:10202",
|
||||
remote = "127.0.0.1:10203"
|
||||
remote = "127.0.0.1:10203",
|
||||
|
||||
# Network emulation for single nodes
|
||||
netem = {
|
||||
limit = 99999, # Limit network emulation to a certain amount of packets
|
||||
delay = 100000, # Additional latency in uS
|
||||
jitter = 30000, # Jitter in uS
|
||||
distribution = "normal",# Distribution of delay (uniform, normal, pareto, paretonormal)
|
||||
loss = 10 # Loss in percentage
|
||||
duplicate = 10, # Duplication in percentage
|
||||
corrupt = 10, # Corruption in percentage
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -29,16 +40,5 @@ paths = (
|
|||
reverse = true, # Setup a path in the reverse direction too
|
||||
in = "acs", # Name of the node we listen to (see above)
|
||||
out = "sintef", # Name of the node we send to
|
||||
|
||||
# TODO: Some 'netem' settings might arrive here in the future...
|
||||
# netem = {
|
||||
# delay = (10, 10, # Time, jitter in milliseconds
|
||||
# 10, # Correlation in percentage
|
||||
# "normal") # Distribution: uniform, normal, pareto or paretonormal
|
||||
# loss = (10, 25), # Loss in percentage
|
||||
# duplicate = (10, 25), # Duplication in percentage
|
||||
# corrupt = (10, 25), # Corruption in percentage
|
||||
# reorder = (10, 25) # Reorder in percentage
|
||||
# }
|
||||
}
|
||||
);
|
||||
|
|
|
@ -14,6 +14,8 @@ struct node;
|
|||
struct path;
|
||||
struct interface;
|
||||
|
||||
struct netem;
|
||||
|
||||
/** Global configuration */
|
||||
struct settings {
|
||||
/** Name of this node */
|
||||
|
@ -79,9 +81,15 @@ int config_parse_path(config_setting_t *cfg,
|
|||
*/
|
||||
int config_parse_node(config_setting_t *cfg,
|
||||
struct node **nodes, struct interface **interfaces);
|
||||
|
||||
/** Parse network emulator (netem) settings
|
||||
*
|
||||
* @param cfg A libconfig object containing the settings
|
||||
* @param em A pointer to the settings
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - otherwise an error occured
|
||||
*/
|
||||
int config_parse_netem(config_setting_t *cfg, struct netem *em);
|
||||
|
||||
#endif /* _CFG_H_ */
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <netinet/in.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "tc.h"
|
||||
|
||||
/** The type of a node.
|
||||
*
|
||||
* This type is used to determine the message format of the remote node
|
||||
|
@ -58,6 +60,9 @@ struct node
|
|||
/** The egress interface */
|
||||
struct interface *interface;
|
||||
|
||||
/** Network emulator settings */
|
||||
struct netem *netem;
|
||||
|
||||
/** Socket mark for netem, routing and filtering */
|
||||
int mark;
|
||||
|
||||
|
|
80
include/tc.h
Normal file
80
include/tc.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* Setup interface queuing desciplines for network emulation
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
|
||||
*/
|
||||
|
||||
#ifndef _TC_H_
|
||||
#define _TC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Some helper for TC handles */
|
||||
typedef uint32_t tc_hdl_t;
|
||||
|
||||
#define TC_HDL(maj, min) ((maj & 0xFFFF) << 16 | (min & 0xFFFF))
|
||||
#define TC_HDL_MAJ(h) ((h >> 16) & 0xFFFF)
|
||||
#define TC_HDL_MIN(h) ((h >> 0) & 0xFFFF)
|
||||
#define TC_HDL_ROOT (0xFFFFFFFFU)
|
||||
|
||||
/* Bitfield for valid fields in struct netem */
|
||||
#define TC_NETEM_LIMIT (1 << 0)
|
||||
#define TC_NETEM_DELAY (1 << 1)
|
||||
#define TC_NETEM_JITTER (1 << 2)
|
||||
#define TC_NETEM_DISTR (1 << 3)
|
||||
#define TC_NETEM_LOSS (1 << 4)
|
||||
#define TC_NETEM_CORRUPT (1 << 5)
|
||||
#define TC_NETEM_DUPL (1 << 6)
|
||||
|
||||
struct interface;
|
||||
|
||||
struct netem {
|
||||
/** Which fields of this struct contain valid data (TC_NETEM_*). */
|
||||
char valid;
|
||||
|
||||
/** Delay distribution: uniform, normal, pareto, paretonormal */
|
||||
const char *distribution;
|
||||
/** Fifo limit (packets) */
|
||||
int limit;
|
||||
/** Added delay (uS) */
|
||||
int delay;
|
||||
/** Delay jitter (uS) */
|
||||
int jitter;
|
||||
/** Random loss probability (%) */
|
||||
int loss;
|
||||
/** Packet corruption probability (%) */
|
||||
int corrupt;
|
||||
/** Packet duplication probability (%) */
|
||||
int duplicate;
|
||||
};
|
||||
|
||||
/** Remove all queuing disciplines and filters
|
||||
*
|
||||
* @param i The interface
|
||||
*/
|
||||
int tc_reset(struct interface *i);
|
||||
|
||||
/** Create a prio queueing discipline
|
||||
*
|
||||
* @param i The interface
|
||||
* @param parent
|
||||
* @param handle
|
||||
* @param bands
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - otherwise an error occured
|
||||
*/
|
||||
int tc_prio(struct interface *i, tc_hdl_t handle, int bands);
|
||||
|
||||
/** Add a new network emulator discipline
|
||||
*
|
||||
* @param i The interface
|
||||
* @param parent Make this
|
||||
*/
|
||||
int tc_netem(struct interface *i, tc_hdl_t parent, struct netem *em);
|
||||
|
||||
/** Add a new fwmark filter */
|
||||
int tc_mark(struct interface *i, tc_hdl_t flowid, int mark);
|
||||
|
||||
#endif /* _TC_H_ */
|
34
src/cfg.c
34
src/cfg.c
|
@ -13,6 +13,7 @@
|
|||
#include <pwd.h>
|
||||
|
||||
#include "if.h"
|
||||
#include "tc.h"
|
||||
#include "cfg.h"
|
||||
#include "node.h"
|
||||
#include "path.h"
|
||||
|
@ -147,7 +148,7 @@ int config_parse_path(config_setting_t *cfg,
|
|||
|
||||
path_rev->in = path->out; /* Swap in/out */
|
||||
path_rev->out = path->in;
|
||||
|
||||
|
||||
list_add(*paths, path_rev);
|
||||
}
|
||||
}
|
||||
|
@ -202,6 +203,13 @@ int config_parse_node(config_setting_t *cfg,
|
|||
if (resolve_addr(remote_str, &node->remote, 0))
|
||||
cerror(cfg, "Failed to resolve remote address '%s' of node '%s'", remote_str, node->name);
|
||||
|
||||
/* Optional settings */
|
||||
config_setting_t *cfg_netem = config_setting_get_member(cfg, "netem");
|
||||
if (cfg_netem) {
|
||||
node->netem = (struct netem *) malloc(sizeof(struct netem));
|
||||
config_parse_netem(cfg_netem, node->netem);
|
||||
}
|
||||
|
||||
/* Determine outgoing interface */
|
||||
int index = if_getegress(&node->remote);
|
||||
struct interface *i = if_lookup_index(index, *interfaces);
|
||||
|
@ -225,3 +233,27 @@ int config_parse_node(config_setting_t *cfg,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_netem(config_setting_t *cfg, struct netem *em)
|
||||
{
|
||||
em->valid = 0;
|
||||
|
||||
if (config_setting_lookup_string(cfg, "distribution", &em->distribution))
|
||||
em->valid |= TC_NETEM_DISTR;
|
||||
if (config_setting_lookup_int(cfg, "limit", &em->limit))
|
||||
em->valid |= TC_NETEM_LIMIT;
|
||||
if (config_setting_lookup_int(cfg, "delay", &em->delay))
|
||||
em->valid |= TC_NETEM_DELAY;
|
||||
if (config_setting_lookup_int(cfg, "jitter", &em->jitter))
|
||||
em->valid |= TC_NETEM_JITTER;
|
||||
if (config_setting_lookup_int(cfg, "loss", &em->loss))
|
||||
em->valid |= TC_NETEM_LOSS;
|
||||
if (config_setting_lookup_int(cfg, "duplicate", &em->duplicate))
|
||||
em->valid |= TC_NETEM_DUPL;
|
||||
if (config_setting_lookup_int(cfg, "corrupt", &em->corrupt))
|
||||
em->valid |= TC_NETEM_CORRUPT;
|
||||
|
||||
// TODO: check values
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
81
src/tc.c
Normal file
81
src/tc.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Traffic control: setup interface queuing desciplines
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "if.h"
|
||||
#include "tc.h"
|
||||
|
||||
int tc_reset(struct interface *i)
|
||||
{
|
||||
char cmd[128];
|
||||
snprintf(cmd, sizeof(cmd), "tc qdisc del dev %s root", i->name);
|
||||
|
||||
debug(6, "system: %s", cmd);
|
||||
return system(cmd);
|
||||
}
|
||||
|
||||
int tc_prio(struct interface *i, tc_hdl_t handle, int bands)
|
||||
{
|
||||
char cmd[128];
|
||||
int len = 0;
|
||||
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len,
|
||||
"tc qdisc add dev %s root handle %u prio bands %u priomap",
|
||||
i->name, TC_HDL_MAJ(handle), bands);
|
||||
|
||||
for (int i = 0; i < bands; i++)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " 0");
|
||||
|
||||
debug(6, "system: %s", cmd);
|
||||
return system(cmd);
|
||||
}
|
||||
|
||||
int tc_netem(struct interface *i, tc_hdl_t parent, struct netem *em)
|
||||
{
|
||||
int len = 0;
|
||||
char cmd[256];
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len,
|
||||
"tc qdisc add dev %s parent %u:%u netem",
|
||||
i->name, TC_HDL_MAJ(parent), TC_HDL_MIN(parent));
|
||||
|
||||
if (em->valid & TC_NETEM_LIMIT)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " limit %u", em->limit);
|
||||
if (em->valid & TC_NETEM_DELAY) {
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " delay %u", em->delay);
|
||||
|
||||
if (em->valid & TC_NETEM_JITTER)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " %u", em->jitter);
|
||||
if (em->valid & TC_NETEM_DISTR)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " distribution %s", em->distribution);
|
||||
}
|
||||
|
||||
if (em->valid & TC_NETEM_LOSS)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " loss random %u", em->loss);
|
||||
if (em->valid & TC_NETEM_DUPL)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " duplicate %u", em->duplicate);
|
||||
if (em->valid & TC_NETEM_CORRUPT)
|
||||
len += snprintf(cmd+len, sizeof(cmd)-len, " corrupt %u", em->corrupt);
|
||||
|
||||
debug(6, "system: %s", cmd);
|
||||
return system(cmd);
|
||||
}
|
||||
|
||||
int tc_mark(struct interface *i, tc_hdl_t flowid, int mark)
|
||||
{
|
||||
char cmd[128];
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"tc filter add dev %s protocol ip handle %u fw flowid %u:%u",
|
||||
i->name, mark, TC_HDL_MAJ(flowid), TC_HDL_MIN(flowid));
|
||||
|
||||
debug(6, "system: %s", cmd);
|
||||
return system(cmd);
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue