summaryrefslogtreecommitdiff
path: root/shaping/src/shaper_aqm.cpp
blob: e7b00e56c738513ea550b83025aaa99ba0f9664d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include <cstdlib>
#include <time.h>

#include "shaper.h"
#include "shaper_aqm.h"


/**************************blue******************************/
#define PROBABILITY_MAX 100
#define INCREMENT 10
#define DECREMENT 1
#define FREEZE_TIME 3 //unit:s

static int shaper_aqm_blue_need_drop(int profile_id, struct shaper_aqm_blue_para *para)
{
    time_t curr_time;
    if (time(&curr_time) - para->update_time >= FREEZE_TIME) {
        para->update_time = curr_time;
        if (para->queue_len >= para->queue_len_max) {
            para->probability = (para->probability + INCREMENT) > PROBABILITY_MAX ? PROBABILITY_MAX : (para->probability + INCREMENT);
        } else if (para->queue_len == 0) {
            para->probability = (para->probability - DECREMENT) >= 0 ? (para->probability - DECREMENT) : 0;
        }
    }

    if (rand() / PROBABILITY_MAX < para->probability) {
        return 1;
    }

    return 0;
}
/**************************blue*****************************/

#if 0
/**************************stochastic fair blue*****************************/
/*
 * SFB uses two B[l][n] : L x N arrays of bins (L levels, N bins per level)
 * This implementation uses L = 8 and N = 16
 * This permits us to split one 32bit hash (provided per packet by rxhash or
 * external classifier) into 8 subhashes of 4 bits.
 */
#define SFB_BUCKET_SHIFT 4
#define SFB_NUMBUCKETS	(1 << SFB_BUCKET_SHIFT) /* N bins per Level */
#define SFB_BUCKET_MASK (SFB_NUMBUCKETS - 1)
#define SFB_LEVELS	(32 / SFB_BUCKET_SHIFT) /* L */

struct sfb_bucket {
	int	queue_len;
	int probability;
};
struct shaper_aqm_sfb_para {
    struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS];
};
/**************************stochastic fair blue*****************************/
#endif


#if 0
/**************************codel*****************************/
#define CODEL_MAX_LATENCY 1500000 //unit:us

#define REC_INV_SQRT_BITS (8 * sizeof(unsigned short)) /* or sizeof_in_bits(rec_inv_sqrt) */
/* needed shift to get a Q0.32 number from rec_inv_sqrt */
#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)

static void shaper_aqm_codel_enqueue()
{
    return;
}

static void shaper_aqm_codel_Newton_step(struct codel_vars *vars)
{
	unsigned int invsqrt = ((unsigned int)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
	unsigned int invsqrt2 = ((unsigned long long)invsqrt * invsqrt) >> 32;
	unsigned long long val = (3LL << 32) - ((unsigned long long)vars->count * invsqrt2);

	val >>= 2; /* avoid overflow in following multiply */
	val = (val * invsqrt) >> (32 - 2 + 1);

	vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
}

static inline unsigned int reciprocal_scale(unsigned int val, unsigned int ep_ro)
{
	return (unsigned int)(((unsigned long long) val * ep_ro) >> 32);
}

static unsigned long long shaper_aqm_codel_control_law(unsigned long long t,
				      unsigned long long interval,
				      unsigned int rec_inv_sqrt)
{
	return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
}

static int shaper_aqm_codel_need_drop(struct shaper_aqm_codel_para *para, struct shaping_profile_info *profile)
{
    struct timespec time;
    unsigned long long curr_time;

    clock_gettime(CLOCK_MONOTONIC, &time);
    curr_time = time.tv_sec * MICRO_SECONDS_PER_SEC + time.tv_nsec / NANO_SECONDS_PER_MICRO_SEC;

    if (curr_time - profile->enqueue_time_us < CODEL_MAX_LATENCY) {
        //TODO:swarmkv set first above time to 0
        return 0;
    }

    if (first_above_time_us == 0) {
        first_above_time_us = curr_time + para->interval;//set in swarmkv
        return 0;
    } else if (curr_time > first_above_time_us) {
        return 1;
    }
}

static int shaper_aqm_codel_dequeue_action()
{
    int need_drop = shaper_aqm_codel_need_drop();

    if (dropping_state) {
        if (!need_drop) {
            dropping_state = 0;
        } else if (curr_time > drop_next) {
            drop_count++;
            shaper_aqm_codel_Newton_step();
            drop_next = shaper_aqm_codel_control_law();
        }
    } else if (need_drop) {
        dropping_state = 1;
        delta = drop_count - last_drop_count;
        if (delta > 1 && (curr_time - drop_next) < 16 * interval) {
            drop_count = delta;
            shaper_aqm_codel_Newton_step();
        } else {
            drop_count = 1;
            rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
        }

        last_drop_count = drop_count;
        drop_next = shaper_aqm_codel_control_law();
    }
}
/**************************codel*****************************/
#endif


int shaper_aqm_enqueue(struct shaping_profile_info *profile)
{
    switch (profile->aqm_type) {
        case AQM_TYPE_BLUE:
            if (shaper_aqm_blue_need_drop(profile->id, &profile->aqm_para.blue_para)) {
                return AQM_ACTION_DROP;
            } else {
                return AQM_ACTION_PASS;
            }
        case AQM_TYPE_CODEL:
        default:
            return AQM_ACTION_PASS;
    }
}

int shaper_aqm_dequeue()
{
    return AQM_ACTION_PASS;
}

int shaper_aqm_need_drop(struct shaping_profile_info *profile, struct shaping_packet_wrapper *pkt_wrapper)
{
    switch (profile->aqm_type) {
        case AQM_TYPE_BLUE:
            
        case AQM_TYPE_CODEL:
            
        default:
            return 0;
    }
}