summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2013-07-29 21:00:11 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2013-07-29 21:00:11 +0200
commit1ff55d4c9acb9e1688bf76f12ae5ae26027ce113 (patch)
treef2181f8b1d558cd8dd34ccb1ad4306aae5391c01
parentb15c16f12ca6838e5ebefc80c11dcf7933bce8bc (diff)
downloadgmrf-1ff55d4c9acb9e1688bf76f12ae5ae26027ce113.tar
gmrf-1ff55d4c9acb9e1688bf76f12ae5ae26027ce113.zip
Implement simple packet loss simulation
-rw-r--r--mmss/config.cpp34
-rw-r--r--mmss/config.hpp5
-rw-r--r--mmss/config.l17
-rw-r--r--mmss/config.y51
-rw-r--r--mmss/network.cpp24
-rw-r--r--mmss/network.hpp31
-rw-r--r--mmss/node.hpp3
7 files changed, 156 insertions, 9 deletions
diff --git a/mmss/config.cpp b/mmss/config.cpp
index 0692d5f..475b1c5 100644
--- a/mmss/config.cpp
+++ b/mmss/config.cpp
@@ -66,12 +66,44 @@ bool config_t::add_network(const char *name) {
return false;
}
+ current_net = &networks.insert(std::make_pair(name, std::make_shared<network_t>(mmss, name, rand_seed++))).first->second;
- networks.insert(std::make_pair(name, std::make_shared<network_t>(name)));
+ 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);
diff --git a/mmss/config.hpp b/mmss/config.hpp
index 69ad6a0..dc21bff 100644
--- a/mmss/config.hpp
+++ b/mmss/config.hpp
@@ -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);
diff --git a/mmss/config.l b/mmss/config.l
index 4fdd346..33d9631 100644
--- a/mmss/config.l
+++ b/mmss/config.l
@@ -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]; }
diff --git a/mmss/config.y b/mmss/config.y
index 6eade61..09eff91 100644
--- a/mmss/config.y
+++ b/mmss/config.y
@@ -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; }
;
@@ -128,10 +168,17 @@ maybe_default: TOK_DEFAULT { $$ = true; }
| { $$ = false; }
;
-maybe_protocol: TOK_PROTOCOL TOK_STRING { $$ = $2; }
+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) {
diff --git a/mmss/network.cpp b/mmss/network.cpp
index 863f10b..ae1dc3c 100644
--- a/mmss/network.cpp
+++ b/mmss/network.cpp
@@ -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);
diff --git a/mmss/network.hpp b/mmss/network.hpp
index 323879c..8ae72f3 100644
--- a/mmss/network.hpp
+++ b/mmss/network.hpp
@@ -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;
}
diff --git a/mmss/node.hpp b/mmss/node.hpp
index 1243c14..feb20c2 100644
--- a/mmss/node.hpp
+++ b/mmss/node.hpp
@@ -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;