Implement simple packet loss simulation

This commit is contained in:
Matthias Schiffer 2013-07-29 21:00:11 +02:00
parent b15c16f12c
commit 1ff55d4c9a
7 changed files with 157 additions and 10 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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]; }

View file

@ -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) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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;