diff mbox

[RFC] netem: correlated loss generation (v3)

Message ID 20100517205621.036a06e0@nehalam
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

stephen hemminger May 18, 2010, 3:56 a.m. UTC
Subject: netem - revised correlated loss generator

This is a patch originated with Stefano Salsano and Fabio Ludovici.
It provides several alternative loss models for use with netem.
There are two state machine based models and one table driven model.

To simplify the original code:
   * eliminated the debugging messages and statistics
   * reformatted for clarity
   * changed API to nested attribute relating to loss
   * changed the table to always loop across bits
   * only allocate parameters needed

Still untested, for comment only...
Should have tested version before 2.6.35 merge window closes.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
 include/linux/pkt_sched.h |   26 ++++
 net/sched/sch_netem.c     |  287 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 307 insertions(+), 6 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Eric Dumazet May 18, 2010, 5:19 a.m. UTC | #1
Le lundi 17 mai 2010 à 20:56 -0700, Stephen Hemminger a écrit :
> Subject: netem - revised correlated loss generator
> 
> This is a patch originated with Stefano Salsano and Fabio Ludovici.
> It provides several alternative loss models for use with netem.
> There are two state machine based models and one table driven model.
> 
> To simplify the original code:
>    * eliminated the debugging messages and statistics
>    * reformatted for clarity
>    * changed API to nested attribute relating to loss
>    * changed the table to always loop across bits
>    * only allocate parameters needed
> 
> Still untested, for comment only...
> Should have tested version before 2.6.35 merge window closes.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


> +	if (loss[NETEM_LOSS_SEQUENCE]) {
> +		struct dlgtable *dlg;
> +		size_t len = nla_len(loss[NETEM_LOSS_SEQUENCE]);
> +
> +		dlg = kmalloc(sizeof(*dlg) + len, GFP_KERNEL);

No overflow check here, len comes from userland.

> +		if (dlg)
> +			goto nomem;
> +
> +		dlg->length = len * BITS_PER_LONG;
> +		dlg->index = 0;
> +		memcpy(dlg->sequence, nla_data(loss[NETEM_LOSS_SEQUENCE]), len);
> +
> +		kfree(q->dlg);
> +		q->dlg = dlg;
> +	}
> +
> +	q->loss_model = model;
> +	sch_tree_unlock(sch);


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hagen Paul Pfeifer May 19, 2010, 9:42 p.m. UTC | #2
* Stephen Hemminger | 2010-05-17 20:56:21 [-0700]:

>Subject: netem - revised correlated loss generator
>
>This is a patch originated with Stefano Salsano and Fabio Ludovici.
>It provides several alternative loss models for use with netem.
>There are two state machine based models and one table driven model.
>
>To simplify the original code:
>   * eliminated the debugging messages and statistics
>   * reformatted for clarity
>   * changed API to nested attribute relating to loss
>   * changed the table to always loop across bits
>   * only allocate parameters needed
>
>Still untested, for comment only...
>Should have tested version before 2.6.35 merge window closes.

Why mainline? I questioning the advantage for the big audience, it looks like
a academic only piece of software - correct me if I'm wrong.

The authors pointed to some weak points in the implementation of the current
loss/correlation logic. But this "fix", add another - complicated component -
and let the broken components untouched ...

HGN
Stefano Salsano May 19, 2010, 10:52 p.m. UTC | #3
Hagen Paul Pfeifer wrote:
> * Stephen Hemminger | 2010-05-17 20:56:21 [-0700]:
> 
> Why mainline? I questioning the advantage for the big audience, it looks like
> a academic only piece of software - correct me if I'm wrong.
>

as an author, I can only give a "biased" point of view... anyway our 
work started from a cooperation with an industry which needed to test 
its solutions for fax/modem over IP under correlated loss.  When we put 
our first version on the netem list, we were asked by people from 
another industry to add the feature of loss patterns coming out from a 
deterministic table.

So my opinion is that the need to emulate "correlated" loss patterns is 
not academic, but it is a real need from industry... of course we can 
debate if it is a "niche" requirement or not

> The authors pointed to some weak points in the implementation of the current
> loss/correlation logic. But this "fix", add another - complicated component -
> and let the broken components untouched ...

Leaving or removing the broken component is an independent issue.

May be we should allow to use the old syntax like this:

tc qdisc change dev wlan0 root netem loss 2

because it was working OK, and we should disallow to use the old model 
in this way:

tc qdisc change dev wlan0 root netem loss 2 10

because this produces broken results...

BR,
Stefano

> 
> HGN
>
Hagen Paul Pfeifer May 19, 2010, 11:04 p.m. UTC | #4
* Stefano Salsano | 2010-05-20 00:52:00 [+0200]:

>So my opinion is that the need to emulate "correlated" loss patterns
>is not academic, but it is a real need from industry... of course we
>can debate if it is a "niche" requirement or not

netem is not in the processing hot path, so there is no issue to add an
additional component. If there are some[TM] users and it is usable, I am
fine with this patch!

>tc qdisc change dev wlan0 root netem loss 2 10
>
>because this produces broken results...

How to model this specific network characteristic (2% loss, correlation 10%)
with your modifications? Can you give us an example?

Cheers, Hagen
stephen hemminger May 20, 2010, 12:17 a.m. UTC | #5
On Thu, 20 May 2010 01:04:33 +0200
Hagen Paul Pfeifer <hagen@jauu.net> wrote:

> * Stefano Salsano | 2010-05-20 00:52:00 [+0200]:
> 
> >So my opinion is that the need to emulate "correlated" loss patterns
> >is not academic, but it is a real need from industry... of course we
> >can debate if it is a "niche" requirement or not
> 
> netem is not in the processing hot path, so there is no issue to add an
> additional component. If there are some[TM] users and it is usable, I am
> fine with this patch!
> 
> >tc qdisc change dev wlan0 root netem loss 2 10
> >
> >because this produces broken results...
> 
> How to model this specific network characteristic (2% loss, correlation 10%)
> with your modifications? Can you give us an example?

The old model was useful, but it really didn't do correlated loss.
For legacy, the old syntax will go through the same code and generate
the same result.

iproute2 syntax is not finalized but, plan is simplified version of
the NetemCLG paper.

tc qdisc change dev eth0 root netem 
      loss 2 10                              # compat syntax
      loss random 2 10                       # same as above
      loss deterministic file                # loss model based on bitmap
      loss state p13 [p31 [p32 [p23 [p14]]]] # 4 state 
      loss model  p [r [1-h [1-k]]]          # gilbert elliot model

Any suggestions for better syntax are appreciated.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stefano Salsano May 20, 2010, 12:22 a.m. UTC | #6
Hagen Paul Pfeifer wrote:
> * Stefano Salsano | 2010-05-20 00:52:00 [+0200]:
> 
>> So my opinion is that the need to emulate "correlated" loss patterns
>> is not academic, but it is a real need from industry... of course we
>> can debate if it is a "niche" requirement or not
> 
> netem is not in the processing hot path, so there is no issue to add an
> additional component. If there are some[TM] users and it is usable, I am
> fine with this patch!
> 
>> tc qdisc change dev wlan0 root netem loss 2 10
>>
>> because this produces broken results...
> 
> How to model this specific network characteristic (2% loss, correlation 10%)
> with your modifications? Can you give us an example?
> 

The definition of "correlation" for the correlated loss was 
intrinsically broken.

We can now use two models to introduce correlated loss events.

One is called GI (General and Intuitive), where the "burst lenght" of 
consecutive loss events is used to measure correlation, so the second 
(optional) parameter is not the "correlation" but the burst lenght:

tc qdisc add dev wlan0 root netem loss_GI ploss burst_length

for example if ploss = 2% then the burst lenght for uncorrelated loss 
will be 1/(1-ploss) = 1 / 0.98 ~= 1.02

this means that you will have almost always isolated loss events if 
burst_lengh is 1.02

everything greater than 1.02 for burst_lenght will add a correlation in 
the loss patterns, for example:

tc qdisc add dev wlan0 root netem loss_GI 2 3

will mean that the loss events will be grouped in bursts of average 
lenght 3 (to keep the 2% loss this will result in less frequent loss 
bursts, but with more consecutive losses per bursts)

The second model is called Gilbert-Elliot model, you have to input two 
parameters p and r:

tc qdisc add dev eth0 root netem loss_gilb_ell p r

p and r are related to ploss and burst_length in the following way:
ploss = p/(p+r)
burst_length = 1/r

Cheers,
Stefano

PS Thank you for your question! It was important to clarify with such an 
example the new approach. We will soon add this discussion to the 
documentation available at 
http://netgroup.uniroma2.it/twiki/bin/view.cgi/Main/NetemCLG


> Cheers, Hagen
>
Hagen Paul Pfeifer May 20, 2010, 12:43 a.m. UTC | #7
* Stephen Hemminger | 2010-05-19 17:17:33 [-0700]:

>The old model was useful, but it really didn't do correlated loss.
>For legacy, the old syntax will go through the same code and generate
>the same result.

Is this really necessary? The right thing is to fix the broken behavior! If
the new patch provides this, great.  Imaging a network analysis for a PhD
dissertation based on a broken correlation algorithm - the whole results are
misleading and wrong. No one deserves this ... ;-)

If the current algorithm is broken then the mechanism must be fixed. Preserve
compatibility is counterproductive in this case.

>tc qdisc change dev eth0 root netem 
>      loss 2 10                              # compat syntax
>      loss random 2 10                       # same as above
>      loss deterministic file                # loss model based on bitmap
>      loss state p13 [p31 [p32 [p23 [p14]]]] # 4 state 
>      loss model  p [r [1-h [1-k]]]          # gilbert elliot model
>
>Any suggestions for better syntax are appreciated.

Not at the moment, looks clear and understandable.


Cheers, Hagen
diff mbox

Patch

--- a/net/sched/sch_netem.c	2010-05-17 20:51:43.753304581 -0700
+++ b/net/sched/sch_netem.c	2010-05-17 20:51:46.423325162 -0700
@@ -47,6 +47,21 @@ 
 	 layering other disciplines.  It does not need to do bandwidth
 	 control either since that can be handled by using token
 	 bucket or other rate control.
+
+     Correlated Loss Generator models
+
+	Added generation of correlated loss according to the
+	"Gilbert-Elliot" model, a 4-state markov model and to a deterministic
+	loss pattern that can be given as input.
+
+	References:
+	[1] NetemCLG Home http://netgroup.uniroma2.it/NetemCLG
+	[2] 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 in [1]
+
+	Authors: Stefano Salsano <stefano.salsano at uniroma2.it
+		 Fabio Ludovici <fabio.ludovici at yahoo.it>
 */
 
 struct netem_sched_data {
@@ -64,6 +79,28 @@  struct netem_sched_data {
 	u32 reorder;
 	u32 corrupt;
 
+	enum netem_clg_model loss_model;
+
+	/* data for Correlated Loss Generation models */
+	struct clgstate {
+		/* state of the Markov chain */
+		u8 state;
+
+		/* 4-states and Gilbert-Elliot models */
+		u32 a1;	/* p13 for 4-states or p for GE */
+		u32 a2;	/* p31 for 4-states or r for GE */
+		u32 a3;	/* p32 for 4-states or h for GE */
+		u32 a4;	/* p14 for 4-states or 1-k for GE */
+		u32 a5; /* p23 used only in 4-states */
+	} *clg;
+
+	/* Deterministic loss generator */
+	struct dlgtable {
+		u32 index;	/* current place in sequence */
+		u32 length;	/* length of the sequence (in bits) */
+		unsigned long sequence[0];
+	} *dlg;
+
 	struct crndstate {
 		u32 last;
 		u32 rho;
@@ -115,6 +152,139 @@  static u32 get_crandom(struct crndstate 
 	return answer;
 }
 
+/* get_loss_pattern_element - deterministic loss generator
+ * Extracts an element (1 means loss event, 0 means transmission)
+ * from the current loss pattern.
+ */
+static int get_loss_pattern_element(struct netem_sched_data *q)
+{
+	struct dlgtable *dlg = q->dlg;
+	u32 val = dlg->sequence[BIT_WORD(dlg->index)] & BIT_MASK(dlg->index);
+
+	if (++dlg->index >= dlg->length)
+		dlg->index = 0;
+
+	return val != 0;
+}
+
+/* get_loss_4state_element - 4-state model loss generator
+ * Generates losses according to the 4-state Markov chain adopted in
+ * the GI (General and Intuitive) loss model.
+ * returns 1 the next packet will be lost,
+ *         0 it will be transmitted.
+ */
+static int get_loss_4state_element(struct netem_sched_data *q)
+{
+	struct clgstate *clg = q->clg;
+	u32 rnd = net_random();
+
+	/*
+	 * Makes a comparison between rnd and the transition
+	 * probabilities outgoing from the current state, then decides the
+	 * next state and if the next packet has to be transmitted or lost.
+	 * The four states correspond to:
+	 *   1 => successfully transmitted packets within a gap period
+	 *   4 => isolated losses within a gap period
+	 *   3 => lost packets within a burst period
+	 *   2 => successfully transmitted packets within a burst period
+	 */
+	switch (clg->state) {
+	case 1:
+		if (rnd < clg->a4) {
+			clg->state = 4;
+			return 1;
+		} else if (clg->a4 < rnd && rnd < clg->a1) {
+			clg->state = 3;
+			return 1;
+		} else if (clg->a1 < rnd)
+			clg->state = 1;
+
+		break;
+	case 2:
+		if (rnd < clg->a5) {
+			clg->state = 3;
+			return 1;
+		} else
+			clg->state = 2;
+
+		break;
+	case 3:
+		if (rnd < clg->a3)
+			clg->state = 2;
+		else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
+			clg->state = 1;
+			return 1;
+		} else if (clg->a2 + clg->a3 < rnd) {
+			clg->state = 3;
+			return 1;
+		}
+		break;
+	case 4:
+		clg->state = 1;
+		break;
+	}
+
+	return 0;
+}
+
+/* get_loss_gilb_ell_element - Gilbert-Elliot model loss generator
+ * Generates losses according to the Gilbert-Elliot loss model or
+ * its special cases  (Gilbert or Simple Gilbert)
+ *
+ * Makes a comparison between random_gilb_ell and the transition
+ * probabilities outgoing from the current state, then decides the
+ * next state. A second random number is extracted and the comparison
+ * with the loss probability of the current state decides if the next
+ * packet will be transmitted or lost.
+ */
+static int get_loss_gilb_ell_element(struct netem_sched_data *q)
+{
+	struct clgstate *clg = q->clg;
+
+	switch (clg->state) {
+	case 1:
+		if (net_random() < clg->a1)
+			clg->state = 2;
+		if (net_random() < clg->a4)
+			return 1;
+	case 2:
+		if (net_random() < clg->a2)
+			clg->state = 1;
+		if (clg->a3 > net_random())
+			return 1;
+	}
+
+	return 0;
+}
+
+static int get_loss_event(struct netem_sched_data *q)
+{
+	switch (q->loss_model) {
+	case CLG_DETERMIN:
+		return get_loss_pattern_element(q);
+
+	case CLG_4_STATES:
+		/* 4state loss model algorithm (used also for GI model)
+		* Extracts a value from the markov 4 state loss generator,
+		* if it is 1 drops a packet and if needed writes the event in
+		* the kernel logs
+		*/
+		return get_loss_4state_element(q);
+
+	case CLG_GILB_ELL:
+		/* Gilbert-Elliot loss model algorithm
+		* Extracts a value from the Gilbert-Elliot loss generator,
+		* if it is 1 drops a packet and if needed writes the event in
+		* the kernel logs
+		*/
+		return get_loss_gilb_ell_element(q);
+
+	default:
+		return 0;
+	}
+}
+
+
 /* tabledist - return a pseudo-randomly distributed value with mean mu and
  * std deviation sigma.  Uses table lookup to approximate the desired
  * distribution, and a uniformly-distributed pseudo-random source.
@@ -171,6 +341,10 @@  static int netem_enqueue(struct sk_buff 
 	if (q->loss && q->loss >= get_crandom(&q->loss_cor))
 		--count;
 
+	/* Deterministic loss pattern algorithm */
+	if (q->loss_model != CLG_NONE && get_loss_event(q))
+		--count;
+
 	if (count == 0) {
 		sch->qstats.drops++;
 		kfree_skb(skb);
@@ -370,10 +544,91 @@  static void get_corrupt(struct Qdisc *sc
 	init_crandom(&q->corrupt_cor, r->correlation);
 }
 
+
+static const struct nla_policy netem_loss_nest[NETEM_LOSS_MAX + 1] = {
+	[NETEM_LOSS_MODEL]	= { .type = NLA_U8, },
+	[NETEM_LOSS_STATE]	= { .len = sizeof(struct tc_netem_loss_state) },
+};
+
+static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
+{
+	struct netem_sched_data *q = qdisc_priv(sch);
+	struct nlattr *loss[NETEM_LOSS_MAX + 1];
+	enum netem_clg_model model;
+	int ret;
+
+	ret = nla_parse_nested(loss, NETEM_LOSS_MAX,
+			       attr, netem_loss_nest);
+	if (ret)
+		return ret;
+
+	if (!loss[NETEM_LOSS_MODEL]) {
+		pr_info("netem: missing loss model\n");
+		return -EINVAL;
+	}
+
+	model = nla_get_u8(loss[NETEM_LOSS_MODEL]);
+	switch (model) {
+	case CLG_GILB_ELL:
+	case CLG_4_STATES:
+		if (!loss[NETEM_LOSS_STATE]) {
+			pr_info("netem: missing state information for loss model\n");
+			return -EINVAL;
+		}
+		break;
+	case CLG_DETERMIN:
+		if (!loss[NETEM_LOSS_SEQUENCE]) {
+			pr_info("netem: missing sequence information for loss model\n");
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		pr_info("netem: unknown loss model: %u\n",
+			(unsigned) model);
+		return -EINVAL;
+	}
+
+	sch_tree_lock(sch);
+	if (loss[NETEM_LOSS_STATE]) {
+		if (!q->clg) {
+			q->clg = kmalloc(sizeof(struct clgstate), GFP_KERNEL);
+			if (!q->clg)
+				goto nomem;
+		}
+		memcpy(q->clg, nla_data(loss[NETEM_LOSS_STATE]),
+		       sizeof(struct clgstate));
+	}
+	if (loss[NETEM_LOSS_SEQUENCE]) {
+		struct dlgtable *dlg;
+		size_t len = nla_len(loss[NETEM_LOSS_SEQUENCE]);
+
+		dlg = kmalloc(sizeof(*dlg) + len, GFP_KERNEL);
+		if (dlg)
+			goto nomem;
+
+		dlg->length = len * BITS_PER_LONG;
+		dlg->index = 0;
+		memcpy(dlg->sequence, nla_data(loss[NETEM_LOSS_SEQUENCE]), len);
+
+		kfree(q->dlg);
+		q->dlg = dlg;
+	}
+
+	q->loss_model = model;
+	sch_tree_unlock(sch);
+
+	return 0;
+ nomem:
+	sch_tree_unlock(sch);
+	return -ENOMEM;
+}
+
 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]	= { .type = NLA_NESTED },
 };
 
 static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
@@ -441,6 +696,9 @@  static int netem_change(struct Qdisc *sc
 	if (tb[TCA_NETEM_CORRUPT])
 		get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
 
+	if (tb[TCA_NETEM_LOSS])
+		get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
+
 	return 0;
 }
 
@@ -538,6 +796,7 @@  static int netem_init(struct Qdisc *sch,
 
 	qdisc_watchdog_init(&q->watchdog, sch);
 
+	q->loss_model = CLG_NONE;
 	q->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
 				     &tfifo_qdisc_ops,
 				     TC_H_MAKE(sch->handle, 1));
@@ -561,13 +820,14 @@  static void netem_destroy(struct Qdisc *
 	qdisc_watchdog_cancel(&q->watchdog);
 	qdisc_destroy(q->qdisc);
 	kfree(q->delay_dist);
+	kfree(q->clg);
+	kfree(q->dlg);
 }
 
 static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	const struct netem_sched_data *q = qdisc_priv(sch);
-	unsigned char *b = skb_tail_pointer(skb);
-	struct nlattr *nla = (struct nlattr *) b;
+	struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb);
 	struct tc_netem_qopt qopt;
 	struct tc_netem_corr cor;
 	struct tc_netem_reorder reorder;
@@ -594,13 +854,28 @@  static int netem_dump(struct Qdisc *sch,
 	corrupt.correlation = q->corrupt_cor.rho;
 	NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
 
-	nla->nla_len = skb_tail_pointer(skb) - b;
+	if (q->loss_model != CLG_NONE) {
+		struct nlattr *nest = nla_nest_start(skb, NETEM_LOSS_MAX);
+
+		if (nest == NULL)
+			goto nla_put_failure;
+
+		NLA_PUT_U8(skb, NETEM_LOSS_MODEL, q->loss_model);
+		if (q->clg)
+			NLA_PUT(skb, NETEM_LOSS_STATE,
+				sizeof(struct tc_netem_loss_state), q->clg);
+		/*
+		 * Don't bother dumping loss sequence map since it can be large
+		 * and hard to display
+		 */
+		nla_nest_end(skb, nest);
+	}
 
 	return skb->len;
 
 nla_put_failure:
-	nlmsg_trim(skb, b);
-	return -1;
+	nlmsg_trim(skb, nla);
+	return -EMSGSIZE;
 }
 
 static struct Qdisc_ops netem_qdisc_ops __read_mostly = {
--- a/include/linux/pkt_sched.h	2010-05-17 20:51:43.763328095 -0700
+++ b/include/linux/pkt_sched.h	2010-05-17 20:52:10.263123961 -0700
@@ -435,6 +435,7 @@  enum {
 	TCA_NETEM_DELAY_DIST,
 	TCA_NETEM_REORDER,
 	TCA_NETEM_CORRUPT,
+	TCA_NETEM_LOSS,
 	__TCA_NETEM_MAX,
 };
 
@@ -465,6 +466,31 @@  struct tc_netem_corrupt {
 	__u32	correlation;
 };
 
+enum {
+	NETEM_LOSS_MODEL,
+	NETEM_LOSS_STATE,
+	NETEM_LOSS_SEQUENCE,
+	__NETEM_LOSS_MAX
+};
+#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1)
+
+/* definition of models for Correlated Loss Generation */
+enum netem_clg_model {
+	CLG_NONE = 0,
+	CLG_GILB_ELL,
+	CLG_4_STATES,
+	CLG_DETERMIN,
+};
+
+/* Correlated Loss Model parameters - GI and Gilbert-Elliot models */
+struct tc_netem_loss_state {
+	__u32	a1;	/* p13 for GI or p for Gilbert-Elliot */
+	__u32	a2;	/* p31 for GI or r for Gilbert-Elliot */
+	__u32	a3;	/* p32 for GI or h for Gilbert-Elliot */
+	__u32	a4;	/* p14 for GI or 1-k for Gilbert-Elliot */
+	__u32	a5;	/* p23 used only in GI */
+};
+
 #define NETEM_DIST_SCALE	8192
 
 /* DRR */