Implement simple packet loss simulation
This commit is contained in:
parent
b15c16f12c
commit
1ff55d4c9a
7 changed files with 157 additions and 10 deletions
|
@ -66,12 +66,44 @@ bool config_t::add_network(const char *name) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
networks.insert(std::make_pair(name, std::make_shared<network_t>(name)));
|
||||
current_net = &networks.insert(std::make_pair(name, std::make_shared<network_t>(mmss, name, rand_seed++))).first->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool config_t::set_packet_loss(float etx) {
|
||||
if (etx < 1) {
|
||||
mmss->logf(LOG_ERR, "config error: network `%s': ETX must be at least 1.0", (*current_net)->get_name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
(*current_net)->set_packet_loss(etx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool config_t::set_packet_loss(float etx_min, float etx_max, float period, float phase) {
|
||||
if (etx_min < 1) {
|
||||
mmss->logf(LOG_ERR, "config error: network `%s': ETX must be at least 1.0", (*current_net)->get_name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (etx_max < etx_min) {
|
||||
mmss->logf(LOG_ERR, "config error: network `%s': max ETX smaller than min ETX", (*current_net)->get_name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (period <= 0) {
|
||||
mmss->logf(LOG_ERR, "config error: network `%s': zero or negative period", (*current_net)->get_name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
(*current_net)->set_packet_loss(etx_min, etx_max, period, phase);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool config_t::add_node(const char *name, const char *proto) {
|
||||
if (nodes.find(name) != nodes.end()) {
|
||||
mmss->logf(LOG_ERR, "config error: duplicate node `%s'", name);
|
||||
|
|
|
@ -44,6 +44,7 @@ private:
|
|||
std::shared_ptr<const protocol_t> default_proto;
|
||||
std::unordered_map<std::string, std::shared_ptr<const protocol_t>> protos;
|
||||
|
||||
const std::shared_ptr<network_t> *current_net;
|
||||
std::unordered_map<std::string, std::shared_ptr<network_t>> networks;
|
||||
|
||||
const std::shared_ptr<node_t> *current_node;
|
||||
|
@ -57,7 +58,11 @@ public:
|
|||
}
|
||||
|
||||
bool load_proto(const char *name, const char *module, bool def);
|
||||
|
||||
bool add_network(const char *name);
|
||||
bool set_packet_loss(float etx);
|
||||
bool set_packet_loss(float etx_min, float etx_max, float period, float phase);
|
||||
|
||||
bool add_node(const char *name, const char *proto);
|
||||
bool add_iface(const char *name, const char *net, const gmrf_addr_t *addr);
|
||||
|
||||
|
|
|
@ -57,7 +57,8 @@
|
|||
%}
|
||||
|
||||
<INITIAL>{
|
||||
[0-9]+ { UPDATE_LOCATION; yylval->num = atoi(yytext); BEGIN(NEEDSPACE); return TOK_INTEGER; }
|
||||
[0-9]+ { UPDATE_LOCATION; yylval->num = std::atoi(yytext); BEGIN(NEEDSPACE); return TOK_INTEGER; }
|
||||
[0-9]*\.[0-9]+ { UPDATE_LOCATION; yylval->fnum = float(std::atof(yytext)); BEGIN(NEEDSPACE); return TOK_FLOAT; }
|
||||
|
||||
yes { TOKEN(TOK_YES); }
|
||||
no { TOKEN(TOK_NO); }
|
||||
|
@ -68,6 +69,13 @@ load { TOKEN(TOK_LOAD); }
|
|||
default { TOKEN(TOK_DEFAULT); }
|
||||
interface { TOKEN(TOK_INTERFACE); }
|
||||
address { TOKEN(TOK_ADDRESS); }
|
||||
etx { TOKEN(TOK_ETX); }
|
||||
const { TOKEN(TOK_CONST); }
|
||||
min { TOKEN(TOK_MIN); }
|
||||
max { TOKEN(TOK_MAX); }
|
||||
sine { TOKEN(TOK_SINE); }
|
||||
period { TOKEN(TOK_PERIOD); }
|
||||
phase { TOKEN(TOK_PHASE); }
|
||||
|
||||
([[:xdigit:]]{2}:){7}[[:xdigit:]]{2} {
|
||||
UPDATE_LOCATION;
|
||||
|
@ -86,6 +94,13 @@ address { TOKEN(TOK_ADDRESS); }
|
|||
\r ;
|
||||
}
|
||||
|
||||
<INITIAL,NEEDSPACE>{
|
||||
s { TOKEN(TOK_S); }
|
||||
m { TOKEN(TOK_M); }
|
||||
h { TOKEN(TOK_H); }
|
||||
days { TOKEN(TOK_DAYS); }
|
||||
}
|
||||
|
||||
<NEEDSPACE>{
|
||||
[;:\{\}] { UPDATE_LOCATION; BEGIN(INITIAL); return yytext[0]; }
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
%union {
|
||||
int num;
|
||||
float fnum;
|
||||
bool boolean;
|
||||
char *str;
|
||||
gmrf_addr_t addr;
|
||||
|
@ -49,6 +50,7 @@
|
|||
}
|
||||
|
||||
%token <num> TOK_INTEGER
|
||||
%token <fnum> TOK_FLOAT
|
||||
%token <str> TOK_STRING
|
||||
%token <addr> TOK_GMRF_ADDRESS
|
||||
|
||||
|
@ -61,6 +63,18 @@
|
|||
%token TOK_DEFAULT
|
||||
%token TOK_INTERFACE
|
||||
%token TOK_ADDRESS
|
||||
%token TOK_ETX
|
||||
%token TOK_CONST
|
||||
%token TOK_MIN
|
||||
%token TOK_MAX
|
||||
%token TOK_SINE
|
||||
%token TOK_PERIOD
|
||||
%token TOK_PHASE
|
||||
|
||||
%token TOK_S
|
||||
%token TOK_M
|
||||
%token TOK_H
|
||||
%token TOK_DAYS
|
||||
|
||||
|
||||
%code {
|
||||
|
@ -71,6 +85,8 @@
|
|||
%type <boolean> boolean
|
||||
%type <boolean> maybe_default
|
||||
%type <str> maybe_protocol
|
||||
%type <num> time
|
||||
%type <fnum> float
|
||||
|
||||
%%
|
||||
|
||||
|
@ -92,7 +108,27 @@ network: TOK_STRING {
|
|||
}
|
||||
;
|
||||
|
||||
network_config:
|
||||
network_config: network_config network_statement
|
||||
|
|
||||
;
|
||||
|
||||
network_statement:
|
||||
TOK_ETX network_etx ';'
|
||||
;
|
||||
|
||||
network_etx:
|
||||
TOK_CONST float {
|
||||
if (!conf->set_packet_loss($2))
|
||||
YYERROR;
|
||||
}
|
||||
| TOK_MIN float TOK_MAX float TOK_SINE TOK_PERIOD time {
|
||||
if (!conf->set_packet_loss($2, $4, $7, 0))
|
||||
YYERROR;
|
||||
}
|
||||
| TOK_MIN float TOK_MAX float TOK_SINE TOK_PERIOD time TOK_PHASE time {
|
||||
if (!conf->set_packet_loss($2, $4, $7, $9))
|
||||
YYERROR;
|
||||
}
|
||||
;
|
||||
|
||||
protocol: TOK_STRING TOK_LOAD TOK_STRING maybe_default {
|
||||
|
@ -120,6 +156,10 @@ node_interface: TOK_STRING TOK_NETWORK TOK_STRING TOK_ADDRESS TOK_GMRF_ADDRESS {
|
|||
}
|
||||
;
|
||||
|
||||
float: TOK_FLOAT { $$ = $1; }
|
||||
| TOK_INTEGER { $$ = $1; }
|
||||
;
|
||||
|
||||
boolean: TOK_YES { $$ = true; }
|
||||
| TOK_NO { $$ = false; }
|
||||
;
|
||||
|
@ -132,6 +172,13 @@ maybe_protocol: TOK_PROTOCOL TOK_STRING { $$ = $2; }
|
|||
| { $$ = nullptr; }
|
||||
;
|
||||
|
||||
time: TOK_INTEGER TOK_DAYS { $$ = $1*86400; }
|
||||
| TOK_INTEGER TOK_H { $$ = $1*3600; }
|
||||
| TOK_INTEGER TOK_M { $$ = $1*60; }
|
||||
| TOK_INTEGER TOK_S { $$ = $1; }
|
||||
| TOK_INTEGER { $$ = $1; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void mmss_config_error(YYLTYPE *loc, const std::shared_ptr<config_t> &conf, const char *filename, const char *s) {
|
||||
|
|
|
@ -28,11 +28,33 @@
|
|||
#include "context.hpp"
|
||||
#include "node.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
namespace MMSS {
|
||||
|
||||
float network_t::get_etx() const {
|
||||
if (etx_min == etx_max)
|
||||
return etx_min;
|
||||
|
||||
float val = float(std::sin(2*M_PI * (mmss->now()/1000.0 - phase)/period));
|
||||
float diff = etx_max - etx_min;
|
||||
|
||||
mmss->logf(LOG_DEBUG, "ETX: %.3f", etx_min + diff * (val+1)/2);
|
||||
|
||||
return etx_min + diff * (val+1)/2;
|
||||
}
|
||||
|
||||
bool network_t::drop_packet() {
|
||||
int r = rand_r(&rand_seed);
|
||||
|
||||
return (r > (RAND_MAX/get_etx()));
|
||||
}
|
||||
|
||||
void network_t::enqueue(const void *data, size_t len, const iface_t *src_iface, const std::shared_ptr<iface_t> &dest_iface) {
|
||||
context_t *mmss = dest_iface->get_node()->get_context();
|
||||
if (drop_packet())
|
||||
return;
|
||||
|
||||
std::shared_ptr<packet_t> packet = std::make_shared<packet_t>(src_iface->get_address(), dest_iface, data, len);
|
||||
mmss->queue_event(std::move(packet), mmss->now()+1);
|
||||
|
|
|
@ -36,20 +36,49 @@ namespace MMSS {
|
|||
|
||||
class network_t : public nocopy_t {
|
||||
private:
|
||||
context_t *mmss;
|
||||
|
||||
std::string name;
|
||||
size_t mtu;
|
||||
|
||||
unsigned rand_seed;
|
||||
|
||||
// packet loss
|
||||
float etx_min;
|
||||
float etx_max;
|
||||
float period;
|
||||
float phase;
|
||||
|
||||
std::unordered_set<std::shared_ptr<iface_t>> interfaces;
|
||||
|
||||
float get_etx() const;
|
||||
|
||||
bool drop_packet();
|
||||
void enqueue(const void *data, size_t len, const iface_t *src_iface, const std::shared_ptr<iface_t> &dest_iface);
|
||||
|
||||
public:
|
||||
network_t(const std::string &name0) : name(name0), mtu(1500) {}
|
||||
network_t(context_t *mmss0, const std::string &name0, unsigned rand_seed0)
|
||||
: mmss(mmss0), name(name0), mtu(1500), rand_seed(rand_seed0), etx_min(1), etx_max(1) {}
|
||||
|
||||
void set_packet_loss(float etx) {
|
||||
etx_min = etx_max = etx;
|
||||
}
|
||||
|
||||
void set_packet_loss(float etx_min0, float etx_max0, float period0, float phase0) {
|
||||
etx_min = etx_min0;
|
||||
etx_max = etx_max0;
|
||||
period = period0;
|
||||
phase = phase0;
|
||||
}
|
||||
|
||||
void add_iface(const std::shared_ptr<iface_t> &iface) {
|
||||
interfaces.insert(iface);
|
||||
}
|
||||
|
||||
context_t* get_context() const {
|
||||
return mmss;
|
||||
}
|
||||
|
||||
const std::string& get_name() const {
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -38,9 +38,6 @@ namespace MMSS {
|
|||
|
||||
class node_t : public ::gmrf, public std::enable_shared_from_this<node_t>, public nocopy_t {
|
||||
private:
|
||||
node_t(node_t const&) = delete;
|
||||
node_t& operator=(node_t const&) = delete;
|
||||
|
||||
context_t *mmss;
|
||||
|
||||
std::string name;
|
||||
|
|
Reference in a new issue