All of lore.kernel.org
 help / color / mirror / Atom feed
From: Fabio Ludovici <fabio.ludovici@yahoo.it>
To: netdev@vger.kernel.org
Subject: Re: [RESEND PATCH 1/3] netem/iproute2 solving correlated loss issue
Date: Tue, 29 Dec 2009 21:00:53 +0100	[thread overview]
Message-ID: <4B3A5FF5.30602@yahoo.it> (raw)
In-Reply-To: <4B3A5F84.4050603@yahoo.it>

enhances netem module as follows:

- add deterministic loss generation according to a pattern that can be 
specified in a file in the iproute2 command line
- new statistical models for generation of correlated loss (the existing 
model does not work), including loss models commonly used in literature 
(bernoulli, Gilbert, Gilbert Elliot) and the new GI (General and 
Intuitive model)
- enhanced logging functionality for loss events in dmesg

Signed-off-by: Stefano Salsano <stefano.salsano@uniroma2.it>
Signed-off-by: Fabio Ludovici <fabio.ludovici@yahoo.it>
---
  include/linux/pkt_sched.h |   33 ++++++
  net/sched/sch_netem.c     |  277 
+++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 310 insertions(+), 0 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index d51a2b3..b492fd3 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -466,6 +466,10 @@ enum
      TCA_NETEM_DELAY_DIST,
      TCA_NETEM_REORDER,
      TCA_NETEM_CORRUPT,
+    TCA_NETEM_LOSS_GI,
+    TCA_NETEM_LOSS_GILBELL,
+    TCA_NETEM_LOSS_PATTERN,
+    TCA_NETEM_LOGGING,
      __TCA_NETEM_MAX,
  };

@@ -500,6 +504,35 @@ struct tc_netem_corrupt
      __u32    correlation;
  };

+struct tc_netem_loss_GI
+{
+    __u32    p13;
+    __u32    p31;
+    __u32    p32;
+    __u32    p23;
+    __u32   p14;
+};
+
+struct tc_netem_loss_gilbell
+{
+    __u32    p;
+    __u32    r;
+    __u32    h;
+    __u32    k;
+};
+
+struct tc_netem_loss_pattern
+{
+    __u16   pattern_length;
+    __u32   pattern_repetitions;
+    __u16   *user_pattern;
+};
+
+struct tc_netem_logging
+{
+    __u8 level;
+};
+
  #define NETEM_DIST_SCALE    8192

  /* DRR */
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 2b88295..c897ce3 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -62,6 +62,29 @@ struct netem_sched_data {
      u32 duplicate;
      u32 reorder;
      u32 corrupt;
+        // GI loss model transition probabilities
+    u32 p13;
+    u32 p31;
+    u32 p23;
+    u32 p32;
+    u32 p14;
+    // Gilbert and Gilbert-Elliot loss models parameters
+    u32 p;
+    u32 r;
+    u32 h;
+    u32 k;
+    // Markov chain state for GI, Gilbert and Gilbert-Elliot models
+    u8 chain_state;
+    // Deterministic pattern parameters
+    u16 pattern_length;        //deterministic loss length
+    u32 pattern_repetitions;    //deterministic loss pattern repetitions
+    u32 *kernel_pattern;         //deterministic loss pattern
+    // Logging parameters and variables
+    u8 logging_level;
+    u32 num_of_drops;        //number of dropped packets
+    u32 num_of_transmissions;   //number of correctly transmitted packets
+    u32 pattern_counter;        //deterministic loss counter
+    u32 repetitions_done;        //deterministic loss repetitions counter

      struct crndstate {
          u32 last;
@@ -159,6 +182,9 @@ static int netem_enqueue(struct sk_buff *skb, struct 
Qdisc *sch)
      struct sk_buff *skb2;
      int ret;
      int count = 1;
+
+    u32 GI_random;              //GI loss model random number
+    u32 gilbell_random;          //Gilbert-Elliot loss model random number

      pr_debug("netem_enqueue skb=%p\n", skb);

@@ -170,6 +196,159 @@ static int netem_enqueue(struct sk_buff *skb, 
struct Qdisc *sch)
      if (q->loss && q->loss >= get_crandom(&q->loss_cor))
          --count;

+    /* General and Intuitive loss generator, Gilbert-Elliot generator, 
deterministic pattern
+    ====================================
+
+    Sources: [1] S. Salsano, F. Ludovici, A. Ordine: "Definition of a 
general and
+    intuitive loss model for packet networks and its implementation in 
the Netem
+    module in the Linux kernel" available at
+ 
http://netgroup.uniroma2.it/twiki/bin/view.cgi/Main/NetEm2#TechnicalReports
+
+     ----------------------------------------------------------------
+
+     This code generates packet losses according to the 4-state Markov 
chain adopted
+         in the GI (General and Intuitive) loss model. To decide if a 
packet will be lost
+     a random value GI_random is compared to the transition 
probabilities outgoing from
+     the current state. The four states correspond to: successfully 
transmitted packets
+     within a gap period (State 1), isolated losses within a gap period 
(State 4),
+     lost packets within a burst period (State 3), successfully 
transmitted packets
+     within a burst period (State 2).
+        */
+
+        if (q->p13) {
+
+    GI_random=net_random();
+
+        switch (q->chain_state) {
+       case 1:
+        q->num_of_transmissions++;
+        if((0<GI_random)&&(GI_random<q->p13))    {
+            q->chain_state=3;
+            break;
+        }
+        else if((q->p13<GI_random)&&(GI_random<(4294967295u-q->p14)))    {
+            q->chain_state=1;
+            break;
+        }
+        else if(((4294967295u-q->p14)<GI_random) && 
(GI_random<4294967295u))    {
+            q->chain_state=4;
+            break;
+        }
+      case 2:
+               q->num_of_transmissions++;
+               if(GI_random<q->p23)    {
+            q->chain_state=3;
+            break;
+        }
+        else      {
+            q->chain_state=2;
+            break;
+        }
+        case 3:
+               --count;
+        q->num_of_drops++;
+        if (q->logging_level==1)
+            printk("netem loss event GI burst %d RFPLE %d\n",
+                q->num_of_drops, q->num_of_transmissions);
+        q->num_of_transmissions=0;
+            if((0<GI_random)&&(GI_random<q->p32)){
+            q->chain_state=2;
+            break;
+        }
+        else if((q->p32<GI_random) && (GI_random<(q->p31+q->p32))){
+        q->chain_state=1;
+        break;
+        }
+        else if(((q->p31+q->p32)<GI_random) && (GI_random<4294967295u)){
+        q->chain_state=3;
+        break;
+        }
+     case 4:
+            --count;
+             q->num_of_drops++;
+             q->chain_state=1;
+             if (q->logging_level==1)
+            printk("netem loss event GI isolated %d RFPLE %d\n",
+            q->num_of_drops, q->num_of_transmissions);
+        break;
+    }
+    }
+
+    /* Gilbert-Elliot loss generator algorithm
+    This code generates packet losses according to the Gilbert-Elliot loss
+    model and its special cases  (like the Gilbert or the Simple Gilbert)
+    */
+
+    if (q->p) {
+
+    switch(q->chain_state) {
+    case 1:
+        gilbell_random=net_random();
+        if(gilbell_random<4294967295u-q->k){
+        --count;
+        q->num_of_drops++;
+        if (q->logging_level==1)
+            printk("netem loss event gilbell %d RFPLE %d\n",
+            q->num_of_drops, q->num_of_transmissions);
+        q->num_of_transmissions=0;
+        }
+        else    {
+        q->num_of_transmissions++;
+        }
+          gilbell_random=net_random();
+        if(gilbell_random<q->p){
+        q->chain_state=2;
+        }
+        break;
+
+    case 2:
+        gilbell_random=net_random();
+        if(gilbell_random<4294967295u-q->h){
+        --count;
+        q->num_of_drops++;
+        if (q->logging_level==1)
+            printk("netem loss event gilbell %d RFPLE %d\n",
+                q->num_of_drops, q->num_of_transmissions);
+        q->num_of_transmissions=0;
+        }
+        else    {
+        q->num_of_transmissions++;
+        }
+        gilbell_random=net_random();
+        if(gilbell_random<q->r)    {
+            q->chain_state=1;
+        }
+        break;
+    }
+    }
+
+    /* Deterministic loss pattern algorithm
+    This code generates packet losses according to a deterministic 
sequence
+    of 0 and 1 where 0 represents a transmitted packet and 1 represents a
+    loss event. The pattern can be repeated for a fixed number of times or
+    indefinitely (if pattern_repetitions=0).
+    */
+
+    if ((0<q->pattern_length) & ((q->pattern_repetitions==0)||
+        (q->repetitions_done<q->pattern_repetitions)) &
+        (q->pattern_counter<q->pattern_length)){
+
+        if (0<q->kernel_pattern[q->pattern_counter-1]){
+        --count;
+        q->num_of_drops++;
+            if (q->logging_level==1)
+            printk("netem loss event deterministic %d RFPLE %d\n",
+                q->num_of_drops, q->num_of_transmissions);
+        q->num_of_transmissions=0;
+                }
+        else q->num_of_transmissions++;
+        q->pattern_counter++;
+        if (q->pattern_counter==q->pattern_length-1){
+        q->repetitions_done++;
+        q->pattern_counter=1;
+        }
+        }
+
      if (count == 0) {
          sch->qstats.drops++;
          kfree_skb(skb);
@@ -369,10 +548,72 @@ static void get_corrupt(struct Qdisc *sch, const 
struct nlattr *attr)
      init_crandom(&q->corrupt_cor, r->correlation);
  }

+static void get_loss_GI(struct Qdisc *sch, const struct nlattr *attr)
+{
+    struct netem_sched_data *q = qdisc_priv(sch);
+    const struct tc_netem_loss_GI *GI = nla_data(attr);
+
+    q->p13 = GI->p13;
+    q->p31 = GI->p31;
+    q->p32 = GI->p32;
+    q->p23 = GI->p23;
+    q->p14 = GI->p14;
+    q->num_of_drops=0;
+    q->num_of_transmissions=0;
+    q->chain_state=1;
+}
+
+static void get_loss_gilbell(struct Qdisc *sch, const struct nlattr *attr)
+{
+    struct netem_sched_data *q = qdisc_priv(sch);
+    const struct tc_netem_loss_gilbell *ge = nla_data(attr);
+
+    q->p = ge->p;
+    q->r = ge->r;
+    q->h = ge->h;
+    q->k = ge->k;
+    q->num_of_drops=0;
+    q->num_of_transmissions=0;
+    q->chain_state=1;
+}
+
+static void get_loss_pattern(struct Qdisc *sch, const struct nlattr *attr)
+{
+    struct netem_sched_data *q = qdisc_priv(sch);
+    const struct tc_netem_loss_pattern *pt = nla_data(attr);
+    int pattern_element;
+    q->pattern_length = pt->pattern_length;
+     q->pattern_repetitions = pt->pattern_repetitions;
+     q->kernel_pattern=kmalloc(q->pattern_length*sizeof(size_t),
+        GFP_KERNEL);
+
+    for (pattern_element=1; pattern_element<q->pattern_length;
+            pattern_element++)    {
+        q->kernel_pattern[pattern_element-1] =
+        pt->user_pattern[pattern_element-1];
+                            }
+    q->num_of_drops=0;
+    q->num_of_transmissions=0;
+    q->pattern_counter=1;
+    q->repetitions_done=0;
+}
+
+static void get_logging(struct Qdisc *sch, const struct nlattr *attr)
+{
+    struct netem_sched_data *q = qdisc_priv(sch);
+    const struct tc_netem_logging *lo = nla_data(attr);
+
+    q->logging_level = lo->level;
+}
+
  static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
      [TCA_NETEM_CORR]    = { .len = sizeof(struct tc_netem_corr) },
      [TCA_NETEM_REORDER]    = { .len = sizeof(struct tc_netem_reorder) },
      [TCA_NETEM_CORRUPT]    = { .len = sizeof(struct tc_netem_corrupt) },
+    [TCA_NETEM_LOSS_GI]    = { .len = sizeof(struct tc_netem_loss_GI) },
+    [TCA_NETEM_LOSS_GILBELL]= { .len = sizeof(struct 
tc_netem_loss_gilbell) },
+    [TCA_NETEM_LOSS_PATTERN]= { .len = sizeof(struct 
tc_netem_loss_pattern) },
+    [TCA_NETEM_LOGGING]    = { .len = sizeof(struct tc_netem_logging) },
  };

  static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr 
*nla,
@@ -440,6 +681,18 @@ static int netem_change(struct Qdisc *sch, struct 
nlattr *opt)
      if (tb[TCA_NETEM_CORRUPT])
          get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);

+    if (tb[TCA_NETEM_LOSS_GI])
+        get_loss_GI(sch, tb[TCA_NETEM_LOSS_GI]);
+
+    if (tb[TCA_NETEM_LOSS_GILBELL])
+        get_loss_gilbell(sch, tb[TCA_NETEM_LOSS_GILBELL]);
+
+    if (tb[TCA_NETEM_LOSS_PATTERN])
+        get_loss_pattern(sch, tb[TCA_NETEM_LOSS_PATTERN]);
+
+    if (tb[TCA_NETEM_LOGGING])
+        get_logging(sch, tb[TCA_NETEM_LOGGING]);
+
      return 0;
  }

@@ -571,6 +824,10 @@ static int netem_dump(struct Qdisc *sch, struct 
sk_buff *skb)
      struct tc_netem_corr cor;
      struct tc_netem_reorder reorder;
      struct tc_netem_corrupt corrupt;
+    struct tc_netem_loss_GI GI;
+    struct tc_netem_loss_gilbell gilbell;
+    struct tc_netem_loss_pattern pattern;
+    struct tc_netem_logging logging;

      qopt.latency = q->latency;
      qopt.jitter = q->jitter;
@@ -593,6 +850,26 @@ static int netem_dump(struct Qdisc *sch, struct 
sk_buff *skb)
      corrupt.correlation = q->corrupt_cor.rho;
      NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);

+    GI.p13=q->p13;
+    GI.p31=q->p31;
+    GI.p23=q->p23;
+    GI.p32=q->p32;
+    GI.p14=q->p14;
+    NLA_PUT(skb, TCA_NETEM_LOSS_GI, sizeof(GI), &GI);
+
+    gilbell.p=q->p;
+    gilbell.r=q->r;
+    gilbell.h=q->h;
+    gilbell.k=q->k;
+    NLA_PUT(skb, TCA_NETEM_LOSS_GILBELL, sizeof(gilbell), &gilbell);
+
+    pattern.pattern_length = q->pattern_length;
+    pattern.pattern_repetitions = q->pattern_repetitions;
+
+    NLA_PUT(skb, TCA_NETEM_LOSS_PATTERN, sizeof(pattern), &pattern);
+    logging.level=q->logging_level;
+    NLA_PUT(skb, TCA_NETEM_LOGGING, sizeof(logging), &logging);
+
      nla->nla_len = skb_tail_pointer(skb) - b;

      return skb->len;
-- 
1.6.3.3

-- 
Fabio Ludovici


  reply	other threads:[~2009-12-29 20:01 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-29 19:59 [RESEND PATCH 0/3] netem/iproute2 solving correlated loss issue Fabio Ludovici
2009-12-29 20:00 ` Fabio Ludovici [this message]
2010-01-04  5:50   ` [RESEND PATCH 1/3] " David Miller
2009-12-29 20:01 ` [RESEND PATCH 2/3] " Fabio Ludovici
2009-12-29 20:02 ` [RESEND PATCH 3/3] " Fabio Ludovici

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B3A5FF5.30602@yahoo.it \
    --to=fabio.ludovici@yahoo.it \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.