Commit 3cad70bc authored by François Michel's avatar François Michel Committed by Jakub Kicinski
Browse files

netem: use seeded PRNG for correlated loss events



Use prandom_u32_state() instead of get_random_u32() to generate
the correlated loss events of netem.

Signed-off-by: default avatarFrançois Michel <francois.michel@uclouvain.be>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Acked-by: default avatarStephen Hemminger <stephen@networkplumber.org>
Link: https://lore.kernel.org/r/20230815092348.1449179-4-francois.michel@uclouvain.be


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 9c87b2ae
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -184,15 +184,16 @@ static void init_crandom(struct crndstate *state, unsigned long rho)
 * Next number depends on last value.
 * rho is scaled to avoid floating point.
 */
static u32 get_crandom(struct crndstate *state)
static u32 get_crandom(struct crndstate *state, struct prng *p)
{
	u64 value, rho;
	unsigned long answer;
	struct rnd_state *s = &p->prng_state;

	if (!state || state->rho == 0)	/* no correlation */
		return get_random_u32();
		return prandom_u32_state(s);

	value = get_random_u32();
	value = prandom_u32_state(s);
	rho = (u64)state->rho + 1;
	answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
	state->last = answer;
@@ -295,7 +296,7 @@ static bool loss_event(struct netem_sched_data *q)
	switch (q->loss_model) {
	case CLG_RANDOM:
		/* Random packet drop 0 => none, ~0 => all */
		return q->loss && q->loss >= get_crandom(&q->loss_cor);
		return q->loss && q->loss >= get_crandom(&q->loss_cor, &q->prng);

	case CLG_4_STATES:
		/* 4state loss model algorithm (used also for GI model)
@@ -324,6 +325,7 @@ static bool loss_event(struct netem_sched_data *q)
 */
static s64 tabledist(s64 mu, s32 sigma,
		     struct crndstate *state,
		     struct prng *prng,
		     const struct disttable *dist)
{
	s64 x;
@@ -333,7 +335,7 @@ static s64 tabledist(s64 mu, s32 sigma,
	if (sigma == 0)
		return mu;

	rnd = get_crandom(state);
	rnd = get_crandom(state, prng);

	/* default uniform distribution */
	if (dist == NULL)
@@ -455,7 +457,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
	skb->prev = NULL;

	/* Random duplication */
	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor, &q->prng))
		++count;

	/* Drop packet? */
@@ -498,7 +500,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
	 * If packet is going to be hardware checksummed, then
	 * do it now in software before we mangle it.
	 */
	if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
	if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor, &q->prng)) {
		if (skb_is_gso(skb)) {
			skb = netem_segment(skb, sch, to_free);
			if (!skb)
@@ -536,12 +538,12 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
	cb = netem_skb_cb(skb);
	if (q->gap == 0 ||		/* not doing reordering */
	    q->counter < q->gap - 1 ||	/* inside last reordering gap */
	    q->reorder < get_crandom(&q->reorder_cor)) {
	    q->reorder < get_crandom(&q->reorder_cor, &q->prng)) {
		u64 now;
		s64 delay;

		delay = tabledist(q->latency, q->jitter,
				  &q->delay_cor, q->delay_dist);
				  &q->delay_cor, &q->prng, q->delay_dist);

		now = ktime_get_ns();

@@ -645,7 +647,7 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)
	else
		next_delay = tabledist(q->slot_config.dist_delay,
				       (s32)(q->slot_config.dist_jitter),
				       NULL, q->slot_dist);
				       NULL, &q->prng, q->slot_dist);

	q->slot.slot_next = now + next_delay;
	q->slot.packets_left = q->slot_config.max_packets;