summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2019-10-22 10:57:46 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-23 23:13:22 -0400
commit55667441c84fa5e0911a0aac44fb059c15ba6da2 (patch)
tree83d3fb8a5acbfbb3f9766f30a1e2343f0f19a90b
parent6c5d9c2a6bedbb3c3c14253776320c0ee564f064 (diff)
net/flow_dissector: switch to siphash
UDP IPv6 packets auto flowlabels are using a 32bit secret (static u32 hashrnd in net/core/flow_dissector.c) and apply jhash() over fields known by the receivers. Attackers can easily infer the 32bit secret and use this information to identify a device and/or user, since this 32bit secret is only set at boot time. Really, using jhash() to generate cookies sent on the wire is a serious security concern. Trying to change the rol32(hash, 16) in ip6_make_flowlabel() would be a dead end. Trying to periodically change the secret (like in sch_sfq.c) could change paths taken in the network for long lived flows. Let's switch to siphash, as we did in commit df453700e8d8 ("inet: switch IP ID generator to siphash") Using a cryptographically strong pseudo random function will solve this privacy issue and more generally remove other weak points in the stack. Packet schedulers using skb_get_hash_perturb() benefit from this change. Fixes: b56774163f99 ("ipv6: Enable auto flow labels by default") Fixes: 42240901f7c4 ("ipv6: Implement different admin modes for automatic flow labels") Fixes: 67800f9b1f4e ("ipv6: Call skb_get_hash_flowi6 to get skb->hash in ip6_make_flowlabel") Fixes: cb1ce2ef387b ("ipv6: Implement automatic flow label generation on transmit") Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Jonathan Berger <jonathann1@walla.com> Reported-by: Amit Klein <aksecurity@gmail.com> Reported-by: Benny Pinkas <benny@pinkas.net> Cc: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h3
-rw-r--r--include/net/flow_dissector.h3
-rw-r--r--include/net/fq.h2
-rw-r--r--include/net/fq_impl.h4
-rw-r--r--net/core/flow_dissector.c38
-rw-r--r--net/sched/sch_hhf.c8
-rw-r--r--net/sched/sch_sfb.c13
-rw-r--r--net/sched/sch_sfq.c14
8 files changed, 42 insertions, 43 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7914fdaf4226..a391147c03d4 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1354,7 +1354,8 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6
1354 return skb->hash; 1354 return skb->hash;
1355} 1355}
1356 1356
1357__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb); 1357__u32 skb_get_hash_perturb(const struct sk_buff *skb,
1358 const siphash_key_t *perturb);
1358 1359
1359static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) 1360static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
1360{ 1361{
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index 90bd210be060..5cd12276ae21 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -4,6 +4,7 @@
4 4
5#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/in6.h> 6#include <linux/in6.h>
7#include <linux/siphash.h>
7#include <uapi/linux/if_ether.h> 8#include <uapi/linux/if_ether.h>
8 9
9/** 10/**
@@ -276,7 +277,7 @@ struct flow_keys_basic {
276struct flow_keys { 277struct flow_keys {
277 struct flow_dissector_key_control control; 278 struct flow_dissector_key_control control;
278#define FLOW_KEYS_HASH_START_FIELD basic 279#define FLOW_KEYS_HASH_START_FIELD basic
279 struct flow_dissector_key_basic basic; 280 struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT);
280 struct flow_dissector_key_tags tags; 281 struct flow_dissector_key_tags tags;
281 struct flow_dissector_key_vlan vlan; 282 struct flow_dissector_key_vlan vlan;
282 struct flow_dissector_key_vlan cvlan; 283 struct flow_dissector_key_vlan cvlan;
diff --git a/include/net/fq.h b/include/net/fq.h
index d126b5d20261..2ad85e683041 100644
--- a/include/net/fq.h
+++ b/include/net/fq.h
@@ -69,7 +69,7 @@ struct fq {
69 struct list_head backlogs; 69 struct list_head backlogs;
70 spinlock_t lock; 70 spinlock_t lock;
71 u32 flows_cnt; 71 u32 flows_cnt;
72 u32 perturbation; 72 siphash_key_t perturbation;
73 u32 limit; 73 u32 limit;
74 u32 memory_limit; 74 u32 memory_limit;
75 u32 memory_usage; 75 u32 memory_usage;
diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h
index be40a4b327e3..107c0d700ed6 100644
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -108,7 +108,7 @@ begin:
108 108
109static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) 109static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb)
110{ 110{
111 u32 hash = skb_get_hash_perturb(skb, fq->perturbation); 111 u32 hash = skb_get_hash_perturb(skb, &fq->perturbation);
112 112
113 return reciprocal_scale(hash, fq->flows_cnt); 113 return reciprocal_scale(hash, fq->flows_cnt);
114} 114}
@@ -308,7 +308,7 @@ static int fq_init(struct fq *fq, int flows_cnt)
308 INIT_LIST_HEAD(&fq->backlogs); 308 INIT_LIST_HEAD(&fq->backlogs);
309 spin_lock_init(&fq->lock); 309 spin_lock_init(&fq->lock);
310 fq->flows_cnt = max_t(u32, flows_cnt, 1); 310 fq->flows_cnt = max_t(u32, flows_cnt, 1);
311 fq->perturbation = prandom_u32(); 311 get_random_bytes(&fq->perturbation, sizeof(fq->perturbation));
312 fq->quantum = 300; 312 fq->quantum = 300;
313 fq->limit = 8192; 313 fq->limit = 8192;
314 fq->memory_limit = 16 << 20; /* 16 MBytes */ 314 fq->memory_limit = 16 << 20; /* 16 MBytes */
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 7c09d87d3269..68eda10d0680 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -1350,30 +1350,21 @@ out_bad:
1350} 1350}
1351EXPORT_SYMBOL(__skb_flow_dissect); 1351EXPORT_SYMBOL(__skb_flow_dissect);
1352 1352
1353static u32 hashrnd __read_mostly; 1353static siphash_key_t hashrnd __read_mostly;
1354static __always_inline void __flow_hash_secret_init(void) 1354static __always_inline void __flow_hash_secret_init(void)
1355{ 1355{
1356 net_get_random_once(&hashrnd, sizeof(hashrnd)); 1356 net_get_random_once(&hashrnd, sizeof(hashrnd));
1357} 1357}
1358 1358
1359static __always_inline u32 __flow_hash_words(const u32 *words, u32 length, 1359static const void *flow_keys_hash_start(const struct flow_keys *flow)
1360 u32 keyval)
1361{ 1360{
1362 return jhash2(words, length, keyval); 1361 BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT);
1363} 1362 return &flow->FLOW_KEYS_HASH_START_FIELD;
1364
1365static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow)
1366{
1367 const void *p = flow;
1368
1369 BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
1370 return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET);
1371} 1363}
1372 1364
1373static inline size_t flow_keys_hash_length(const struct flow_keys *flow) 1365static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
1374{ 1366{
1375 size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); 1367 size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs);
1376 BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
1377 BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != 1368 BUILD_BUG_ON(offsetof(typeof(*flow), addrs) !=
1378 sizeof(*flow) - sizeof(flow->addrs)); 1369 sizeof(*flow) - sizeof(flow->addrs));
1379 1370
@@ -1388,7 +1379,7 @@ static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
1388 diff -= sizeof(flow->addrs.tipckey); 1379 diff -= sizeof(flow->addrs.tipckey);
1389 break; 1380 break;
1390 } 1381 }
1391 return (sizeof(*flow) - diff) / sizeof(u32); 1382 return sizeof(*flow) - diff;
1392} 1383}
1393 1384
1394__be32 flow_get_u32_src(const struct flow_keys *flow) 1385__be32 flow_get_u32_src(const struct flow_keys *flow)
@@ -1454,14 +1445,15 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)
1454 } 1445 }
1455} 1446}
1456 1447
1457static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) 1448static inline u32 __flow_hash_from_keys(struct flow_keys *keys,
1449 const siphash_key_t *keyval)
1458{ 1450{
1459 u32 hash; 1451 u32 hash;
1460 1452
1461 __flow_hash_consistentify(keys); 1453 __flow_hash_consistentify(keys);
1462 1454
1463 hash = __flow_hash_words(flow_keys_hash_start(keys), 1455 hash = siphash(flow_keys_hash_start(keys),
1464 flow_keys_hash_length(keys), keyval); 1456 flow_keys_hash_length(keys), keyval);
1465 if (!hash) 1457 if (!hash)
1466 hash = 1; 1458 hash = 1;
1467 1459
@@ -1471,12 +1463,13 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
1471u32 flow_hash_from_keys(struct flow_keys *keys) 1463u32 flow_hash_from_keys(struct flow_keys *keys)
1472{ 1464{
1473 __flow_hash_secret_init(); 1465 __flow_hash_secret_init();
1474 return __flow_hash_from_keys(keys, hashrnd); 1466 return __flow_hash_from_keys(keys, &hashrnd);
1475} 1467}
1476EXPORT_SYMBOL(flow_hash_from_keys); 1468EXPORT_SYMBOL(flow_hash_from_keys);
1477 1469
1478static inline u32 ___skb_get_hash(const struct sk_buff *skb, 1470static inline u32 ___skb_get_hash(const struct sk_buff *skb,
1479 struct flow_keys *keys, u32 keyval) 1471 struct flow_keys *keys,
1472 const siphash_key_t *keyval)
1480{ 1473{
1481 skb_flow_dissect_flow_keys(skb, keys, 1474 skb_flow_dissect_flow_keys(skb, keys,
1482 FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); 1475 FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
@@ -1524,7 +1517,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
1524 &keys, NULL, 0, 0, 0, 1517 &keys, NULL, 0, 0, 0,
1525 FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); 1518 FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
1526 1519
1527 return __flow_hash_from_keys(&keys, hashrnd); 1520 return __flow_hash_from_keys(&keys, &hashrnd);
1528} 1521}
1529EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); 1522EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
1530 1523
@@ -1544,13 +1537,14 @@ void __skb_get_hash(struct sk_buff *skb)
1544 1537
1545 __flow_hash_secret_init(); 1538 __flow_hash_secret_init();
1546 1539
1547 hash = ___skb_get_hash(skb, &keys, hashrnd); 1540 hash = ___skb_get_hash(skb, &keys, &hashrnd);
1548 1541
1549 __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); 1542 __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
1550} 1543}
1551EXPORT_SYMBOL(__skb_get_hash); 1544EXPORT_SYMBOL(__skb_get_hash);
1552 1545
1553__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) 1546__u32 skb_get_hash_perturb(const struct sk_buff *skb,
1547 const siphash_key_t *perturb)
1554{ 1548{
1555 struct flow_keys keys; 1549 struct flow_keys keys;
1556 1550
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index 23cd1c873a2c..be35f03b657b 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -5,11 +5,11 @@
5 * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com> 5 * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com>
6 */ 6 */
7 7
8#include <linux/jhash.h>
9#include <linux/jiffies.h> 8#include <linux/jiffies.h>
10#include <linux/module.h> 9#include <linux/module.h>
11#include <linux/skbuff.h> 10#include <linux/skbuff.h>
12#include <linux/vmalloc.h> 11#include <linux/vmalloc.h>
12#include <linux/siphash.h>
13#include <net/pkt_sched.h> 13#include <net/pkt_sched.h>
14#include <net/sock.h> 14#include <net/sock.h>
15 15
@@ -126,7 +126,7 @@ struct wdrr_bucket {
126 126
127struct hhf_sched_data { 127struct hhf_sched_data {
128 struct wdrr_bucket buckets[WDRR_BUCKET_CNT]; 128 struct wdrr_bucket buckets[WDRR_BUCKET_CNT];
129 u32 perturbation; /* hash perturbation */ 129 siphash_key_t perturbation; /* hash perturbation */
130 u32 quantum; /* psched_mtu(qdisc_dev(sch)); */ 130 u32 quantum; /* psched_mtu(qdisc_dev(sch)); */
131 u32 drop_overlimit; /* number of times max qdisc packet 131 u32 drop_overlimit; /* number of times max qdisc packet
132 * limit was hit 132 * limit was hit
@@ -264,7 +264,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)
264 } 264 }
265 265
266 /* Get hashed flow-id of the skb. */ 266 /* Get hashed flow-id of the skb. */
267 hash = skb_get_hash_perturb(skb, q->perturbation); 267 hash = skb_get_hash_perturb(skb, &q->perturbation);
268 268
269 /* Check if this packet belongs to an already established HH flow. */ 269 /* Check if this packet belongs to an already established HH flow. */
270 flow_pos = hash & HHF_BIT_MASK; 270 flow_pos = hash & HHF_BIT_MASK;
@@ -582,7 +582,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt,
582 582
583 sch->limit = 1000; 583 sch->limit = 1000;
584 q->quantum = psched_mtu(qdisc_dev(sch)); 584 q->quantum = psched_mtu(qdisc_dev(sch));
585 q->perturbation = prandom_u32(); 585 get_random_bytes(&q->perturbation, sizeof(q->perturbation));
586 INIT_LIST_HEAD(&q->new_buckets); 586 INIT_LIST_HEAD(&q->new_buckets);
587 INIT_LIST_HEAD(&q->old_buckets); 587 INIT_LIST_HEAD(&q->old_buckets);
588 588
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index d448fe3068e5..4074c50ac3d7 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -18,7 +18,7 @@
18#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/skbuff.h> 19#include <linux/skbuff.h>
20#include <linux/random.h> 20#include <linux/random.h>
21#include <linux/jhash.h> 21#include <linux/siphash.h>
22#include <net/ip.h> 22#include <net/ip.h>
23#include <net/pkt_sched.h> 23#include <net/pkt_sched.h>
24#include <net/pkt_cls.h> 24#include <net/pkt_cls.h>
@@ -45,7 +45,7 @@ struct sfb_bucket {
45 * (Section 4.4 of SFB reference : moving hash functions) 45 * (Section 4.4 of SFB reference : moving hash functions)
46 */ 46 */
47struct sfb_bins { 47struct sfb_bins {
48 u32 perturbation; /* jhash perturbation */ 48 siphash_key_t perturbation; /* siphash key */
49 struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS]; 49 struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS];
50}; 50};
51 51
@@ -217,7 +217,8 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da
217 217
218static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q) 218static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q)
219{ 219{
220 q->bins[slot].perturbation = prandom_u32(); 220 get_random_bytes(&q->bins[slot].perturbation,
221 sizeof(q->bins[slot].perturbation));
221} 222}
222 223
223static void sfb_swap_slot(struct sfb_sched_data *q) 224static void sfb_swap_slot(struct sfb_sched_data *q)
@@ -314,9 +315,9 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
314 /* If using external classifiers, get result and record it. */ 315 /* If using external classifiers, get result and record it. */
315 if (!sfb_classify(skb, fl, &ret, &salt)) 316 if (!sfb_classify(skb, fl, &ret, &salt))
316 goto other_drop; 317 goto other_drop;
317 sfbhash = jhash_1word(salt, q->bins[slot].perturbation); 318 sfbhash = siphash_1u32(salt, &q->bins[slot].perturbation);
318 } else { 319 } else {
319 sfbhash = skb_get_hash_perturb(skb, q->bins[slot].perturbation); 320 sfbhash = skb_get_hash_perturb(skb, &q->bins[slot].perturbation);
320 } 321 }
321 322
322 323
@@ -352,7 +353,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
352 /* Inelastic flow */ 353 /* Inelastic flow */
353 if (q->double_buffering) { 354 if (q->double_buffering) {
354 sfbhash = skb_get_hash_perturb(skb, 355 sfbhash = skb_get_hash_perturb(skb,
355 q->bins[slot].perturbation); 356 &q->bins[slot].perturbation);
356 if (!sfbhash) 357 if (!sfbhash)
357 sfbhash = 1; 358 sfbhash = 1;
358 sfb_skb_cb(skb)->hashes[slot] = sfbhash; 359 sfb_skb_cb(skb)->hashes[slot] = sfbhash;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 68404a9d2ce4..c787d4d46017 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -14,7 +14,7 @@
14#include <linux/errno.h> 14#include <linux/errno.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/skbuff.h> 16#include <linux/skbuff.h>
17#include <linux/jhash.h> 17#include <linux/siphash.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/vmalloc.h> 19#include <linux/vmalloc.h>
20#include <net/netlink.h> 20#include <net/netlink.h>
@@ -117,7 +117,7 @@ struct sfq_sched_data {
117 u8 headdrop; 117 u8 headdrop;
118 u8 maxdepth; /* limit of packets per flow */ 118 u8 maxdepth; /* limit of packets per flow */
119 119
120 u32 perturbation; 120 siphash_key_t perturbation;
121 u8 cur_depth; /* depth of longest slot */ 121 u8 cur_depth; /* depth of longest slot */
122 u8 flags; 122 u8 flags;
123 unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */ 123 unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
@@ -157,7 +157,7 @@ static inline struct sfq_head *sfq_dep_head(struct sfq_sched_data *q, sfq_index
157static unsigned int sfq_hash(const struct sfq_sched_data *q, 157static unsigned int sfq_hash(const struct sfq_sched_data *q,
158 const struct sk_buff *skb) 158 const struct sk_buff *skb)
159{ 159{
160 return skb_get_hash_perturb(skb, q->perturbation) & (q->divisor - 1); 160 return skb_get_hash_perturb(skb, &q->perturbation) & (q->divisor - 1);
161} 161}
162 162
163static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch, 163static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
@@ -607,9 +607,11 @@ static void sfq_perturbation(struct timer_list *t)
607 struct sfq_sched_data *q = from_timer(q, t, perturb_timer); 607 struct sfq_sched_data *q = from_timer(q, t, perturb_timer);
608 struct Qdisc *sch = q->sch; 608 struct Qdisc *sch = q->sch;
609 spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); 609 spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
610 siphash_key_t nkey;
610 611
612 get_random_bytes(&nkey, sizeof(nkey));
611 spin_lock(root_lock); 613 spin_lock(root_lock);
612 q->perturbation = prandom_u32(); 614 q->perturbation = nkey;
613 if (!q->filter_list && q->tail) 615 if (!q->filter_list && q->tail)
614 sfq_rehash(sch); 616 sfq_rehash(sch);
615 spin_unlock(root_lock); 617 spin_unlock(root_lock);
@@ -688,7 +690,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
688 del_timer(&q->perturb_timer); 690 del_timer(&q->perturb_timer);
689 if (q->perturb_period) { 691 if (q->perturb_period) {
690 mod_timer(&q->perturb_timer, jiffies + q->perturb_period); 692 mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
691 q->perturbation = prandom_u32(); 693 get_random_bytes(&q->perturbation, sizeof(q->perturbation));
692 } 694 }
693 sch_tree_unlock(sch); 695 sch_tree_unlock(sch);
694 kfree(p); 696 kfree(p);
@@ -745,7 +747,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt,
745 q->quantum = psched_mtu(qdisc_dev(sch)); 747 q->quantum = psched_mtu(qdisc_dev(sch));
746 q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); 748 q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
747 q->perturb_period = 0; 749 q->perturb_period = 0;
748 q->perturbation = prandom_u32(); 750 get_random_bytes(&q->perturbation, sizeof(q->perturbation));
749 751
750 if (opt) { 752 if (opt) {
751 int err = sfq_change(sch, opt); 753 int err = sfq_change(sch, opt);