DPDK  2.1.0
rte_red.h
Go to the documentation of this file.
1 /*-
2  * BSD LICENSE
3  *
4  * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  * * Neither the name of Intel Corporation nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef __RTE_RED_H_INCLUDED__
35 #define __RTE_RED_H_INCLUDED__
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
48 #include <stdint.h>
49 #include <limits.h>
50 #include <rte_common.h>
51 #include <rte_debug.h>
52 #include <rte_cycles.h>
53 #include <rte_branch_prediction.h>
54 
55 #define RTE_RED_SCALING 10
56 #define RTE_RED_S (1 << 22)
57 #define RTE_RED_MAX_TH_MAX 1023
58 #define RTE_RED_WQ_LOG2_MIN 1
59 #define RTE_RED_WQ_LOG2_MAX 12
60 #define RTE_RED_MAXP_INV_MIN 1
61 #define RTE_RED_MAXP_INV_MAX 255
62 #define RTE_RED_2POW16 (1<<16)
63 #define RTE_RED_INT16_NBITS (sizeof(uint16_t) * CHAR_BIT)
64 #define RTE_RED_WQ_LOG2_NUM (RTE_RED_WQ_LOG2_MAX - RTE_RED_WQ_LOG2_MIN + 1)
65 
66 #ifdef RTE_RED_DEBUG
67 
68 #define RTE_RED_ASSERT(exp) \
69 if (!(exp)) { \
70  rte_panic("line%d\tassert \"" #exp "\" failed\n", __LINE__); \
71 }
72 
73 #else
74 
75 #define RTE_RED_ASSERT(exp) do { } while(0)
76 
77 #endif /* RTE_RED_DEBUG */
78 
83 extern uint32_t rte_red_rand_val;
84 extern uint32_t rte_red_rand_seed;
85 extern uint16_t rte_red_log2_1_minus_Wq[RTE_RED_WQ_LOG2_NUM];
86 extern uint16_t rte_red_pow2_frac_inv[16];
87 
93  uint16_t min_th;
94  uint16_t max_th;
95  uint16_t maxp_inv;
96  uint16_t wq_log2;
97 };
98 
103  uint32_t min_th;
104  uint32_t max_th;
105  uint32_t pa_const;
106  uint8_t maxp_inv;
107  uint8_t wq_log2;
108 };
109 
113 struct rte_red {
114  uint32_t avg;
115  uint32_t count;
116  uint64_t q_time;
117 };
118 
128 int
129 rte_red_rt_data_init(struct rte_red *red);
130 
145 int
146 rte_red_config_init(struct rte_red_config *red_cfg,
147  const uint16_t wq_log2,
148  const uint16_t min_th,
149  const uint16_t max_th,
150  const uint16_t maxp_inv);
151 
162 static inline uint32_t
164 {
165  rte_red_rand_seed = (214013 * rte_red_rand_seed) + 2531011;
166  return (rte_red_rand_seed >> 10);
167 }
168 
179 static inline uint16_t
180 __rte_red_calc_qempty_factor(uint8_t wq_log2, uint16_t m)
181 {
182  uint32_t n = 0;
183  uint32_t f = 0;
184 
205  n = m * rte_red_log2_1_minus_Wq[wq_log2 - RTE_RED_WQ_LOG2_MIN];
206 
219  f = (n >> 6) & 0xf;
220  n >>= 10;
221 
222  if (n < RTE_RED_SCALING)
223  return (uint16_t) ((rte_red_pow2_frac_inv[f] + (1 << (n - 1))) >> n);
224 
225  return 0;
226 }
227 
242 static inline int
243 rte_red_enqueue_empty(const struct rte_red_config *red_cfg,
244  struct rte_red *red,
245  const uint64_t time)
246 {
247  uint64_t time_diff = 0, m = 0;
248 
249  RTE_RED_ASSERT(red_cfg != NULL);
250  RTE_RED_ASSERT(red != NULL);
251 
252  red->count ++;
253 
258  time_diff = time - red->q_time;
259 
266  m = time_diff / RTE_RED_S;
267 
271  if (m >= RTE_RED_2POW16) {
272  red->avg = 0;
273  } else {
274  red->avg = (red->avg >> RTE_RED_SCALING) * __rte_red_calc_qempty_factor(red_cfg->wq_log2, (uint16_t) m);
275  }
276 
277  return 0;
278 }
279 
320 static inline int
321 __rte_red_drop(const struct rte_red_config *red_cfg, struct rte_red *red)
322 {
323  uint32_t pa_num = 0; /* numerator of drop-probability */
324  uint32_t pa_den = 0; /* denominator of drop-probability */
325  uint32_t pa_num_count = 0;
326 
327  pa_num = (red->avg - red_cfg->min_th) >> (red_cfg->wq_log2);
328 
329  pa_num_count = red->count * pa_num;
330 
331  if (red_cfg->pa_const <= pa_num_count)
332  return 1;
333 
334  pa_den = red_cfg->pa_const - pa_num_count;
335 
336  /* If drop, generate and save random number to be used next time */
337  if (unlikely((rte_red_rand_val % pa_den) < pa_num)) {
338  rte_red_rand_val = rte_fast_rand();
339 
340  return 1;
341  }
342 
343  /* No drop */
344  return 0;
345 }
346 
359 static inline int
361  struct rte_red *red,
362  const unsigned q)
363 {
364  RTE_RED_ASSERT(red_cfg != NULL);
365  RTE_RED_ASSERT(red != NULL);
366 
380  /* avg update */
381  red->avg += (q << RTE_RED_SCALING) - (red->avg >> red_cfg->wq_log2);
382 
383  /* avg < min_th: do not mark the packet */
384  if (red->avg < red_cfg->min_th) {
385  red->count ++;
386  return 0;
387  }
388 
389  /* min_th <= avg < max_th: mark the packet with pa probability */
390  if (red->avg < red_cfg->max_th) {
391  if (!__rte_red_drop(red_cfg, red)) {
392  red->count ++;
393  return 0;
394  }
395 
396  red->count = 0;
397  return 2;
398  }
399 
400  /* max_th <= avg: always mark the packet */
401  red->count = 0;
402  return 1;
403 }
404 
421 static inline int
422 rte_red_enqueue(const struct rte_red_config *red_cfg,
423  struct rte_red *red,
424  const unsigned q,
425  const uint64_t time)
426 {
427  RTE_RED_ASSERT(red_cfg != NULL);
428  RTE_RED_ASSERT(red != NULL);
429 
430  if (q != 0) {
431  return rte_red_enqueue_nonempty(red_cfg, red, q);
432  } else {
433  return rte_red_enqueue_empty(red_cfg, red, time);
434  }
435 }
436 
443 static inline void
444 rte_red_mark_queue_empty(struct rte_red *red, const uint64_t time)
445 {
446  red->q_time = time;
447 }
448 
449 #ifdef __cplusplus
450 }
451 #endif
452 
453 #endif /* __RTE_RED_H_INCLUDED__ */