From 1ff55d4c9acb9e1688bf76f12ae5ae26027ce113 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 29 Jul 2013 21:00:11 +0200 Subject: Implement simple packet loss simulation --- mmss/config.cpp | 34 +++++++++++++++++++++++++++++++++- mmss/config.hpp | 5 +++++ mmss/config.l | 17 ++++++++++++++++- mmss/config.y | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- mmss/network.cpp | 24 +++++++++++++++++++++++- mmss/network.hpp | 31 ++++++++++++++++++++++++++++++- mmss/node.hpp | 3 --- 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(mmss, name, rand_seed++))).first->second; - networks.insert(std::make_pair(name, std::make_shared(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 default_proto; std::unordered_map> protos; + const std::shared_ptr *current_net; std::unordered_map> networks; const std::shared_ptr *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 @@ %} { -[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 ; } +{ +s { TOKEN(TOK_S); } +m { TOKEN(TOK_M); } +h { TOKEN(TOK_H); } +days { TOKEN(TOK_DAYS); } +} + { [;:\{\}] { 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 TOK_INTEGER +%token TOK_FLOAT %token TOK_STRING %token 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 %type maybe_default %type maybe_protocol +%type time +%type 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 &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 +#include + 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 &dest_iface) { - context_t *mmss = dest_iface->get_node()->get_context(); + if (drop_packet()) + return; std::shared_ptr packet = std::make_shared(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> 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 &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) { 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, public nocopy_t { private: - node_t(node_t const&) = delete; - node_t& operator=(node_t const&) = delete; - context_t *mmss; std::string name; -- cgit v1.2.3