From: François Michel <[email protected]>
In order to reproduce bugs or performance evaluation of
network protocols and applications, it is useful to have
reproducible test suites and tools. This patch adds
a way to specify a PRNG seed for generating netem
loss and corruption events. Initializing the qdisc
with the same seed leads to the exact same loss
and corruption patterns. If no seed is specified, the
qdisc adopts the classical behaviour, i.e. using the
unseeded get_random_u32() for generating these events.
This patch can be and has been tested using tc from
the following iproute2-next fork:
[email protected]:francoismichel/iproute2-next.git
For instance, setting the seed 42424242 on the loopback
with a loss rate of 10% will systematically drop the 5th,
12th and 24th packet when sending 25 packets.
François Michel (3):
netem: add prng attribute to netem_sched_data
netem: allow using a seeded PRNG for generating random losses
netem: allow using seeded PRNG for correlated loss events
include/uapi/linux/pkt_sched.h | 1 +
net/sched/sch_netem.c | 62 ++++++++++++++++++++++++++--------
2 files changed, 48 insertions(+), 15 deletions(-)
base-commit: f614a29d6ca6962139b0eb36b985e3dda80258a6
--
2.41.0
From: François Michel <[email protected]>
Add the netem_get_random_u32 function to sch_netem.c
and use it to generate the random loss events of netem.
If no seed was specified by the application through
setting TCA_NETEM_PRNG_SEED, the default behaviour
is the same as before, i.e. it relies on the unseeded
get_random_u32() function. If a seed was provided,
it relies on the seeded prng attribute of
struct netem_sched_data.
Signed-off-by: François Michel <[email protected]>
---
net/sched/sch_netem.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index d73596d0e912..1190782ef79d 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -154,6 +154,19 @@ struct netem_sched_data {
struct disttable *slot_dist;
};
+/* netem_get_random_u32 - polls a new random 32-bits integer from
+ * the prng.
+ * Uses a deterministic seeded prng if p->deterministic_rng is true.
+ * Uses get_random_u32() underneath if p is NULL or if p->deterministic_rng
+ * is false.
+ */
+static u32 netem_get_random_u32(struct prng *p)
+{
+ if (p && p->deterministic_rng)
+ return prandom_u32_state(&p->prng_state);
+ return get_random_u32();
+}
+
/* Time stamp put into socket buffer control block
* Only valid when skbs are in our internal t(ime)fifo queue.
*
@@ -207,7 +220,7 @@ static u32 get_crandom(struct crndstate *state)
static bool loss_4state(struct netem_sched_data *q)
{
struct clgstate *clg = &q->clg;
- u32 rnd = get_random_u32();
+ u32 rnd = netem_get_random_u32(&q->prng);
/*
* Makes a comparison between rnd and the transition
@@ -272,18 +285,19 @@ static bool loss_4state(struct netem_sched_data *q)
static bool loss_gilb_ell(struct netem_sched_data *q)
{
struct clgstate *clg = &q->clg;
+ struct prng *p = &q->prng;
switch (clg->state) {
case GOOD_STATE:
- if (get_random_u32() < clg->a1)
+ if (netem_get_random_u32(p) < clg->a1)
clg->state = BAD_STATE;
- if (get_random_u32() < clg->a4)
+ if (netem_get_random_u32(p) < clg->a4)
return true;
break;
case BAD_STATE:
- if (get_random_u32() < clg->a2)
+ if (netem_get_random_u32(p) < clg->a2)
clg->state = GOOD_STATE;
- if (get_random_u32() > clg->a3)
+ if (netem_get_random_u32(p) > clg->a3)
return true;
}
--
2.41.0
On Mon, 14 Aug 2023 04:31:39 +0200
Francois Michel <[email protected]> wrote:
> +/* netem_get_random_u32 - polls a new random 32-bits integer from
> + * the prng.
> + * Uses a deterministic seeded prng if p->deterministic_rng is true.
> + * Uses get_random_u32() underneath if p is NULL or if p->deterministic_rng
> + * is false.
> + */
> +static u32 netem_get_random_u32(struct prng *p)
Overall I am fine with this patch, but the function name is getting excessively
long. It is a local function, so no need for netem_ prefix.
Checking for p == NULL is redundant, all callers are passing a valid pointer.
For logical consistency, put the new wrapper before init_crandom() and after netem_skb_cb().
Since this is not security related, the change could also be simplified to just
always prandom_u32_state() and initialize the state on first use with either
get_random or provided seed. This would also simplify the code around storing
original seed and boolean.
Reminds me of the quote attributed to Mark Twain:
“I apologize for such a long letter - I didn't have time to write a short one.”