VPP police
源码:https://docs.fd.io/vpp/20.01/d1/d66/police_8h_source.html
#ifndef __POLICE_H__ #define __POLICE_H__ typedef enum { POLICE_CONFORM = 0, POLICE_EXCEED = 1, POLICE_VIOLATE = 2, } policer_result_e; #define POLICER_TICKS_PER_PERIOD_SHIFT 17 #define POLICER_TICKS_PER_PERIOD (1 << POLICER_TICKS_PER_PERIOD_SHIFT) typedef struct { u32 lock; // for exclusive access to the struct u32 single_rate; // 1 = single rate policer, 0 = two rate policer u32 color_aware; // for hierarchical policing u32 scale; // power-of-2 shift amount for lower rates u8 action[3]; u8 mark_dscp[3]; u8 pad[2]; // Fields are marked as 2R if they are only used for a 2-rate policer, // and MOD if they are modified as part of the update operation. // 1 token = 1 byte. u32 cir_tokens_per_period; // # of tokens for each period u32 pir_tokens_per_period; // 2R u32 current_limit; u32 current_bucket; // MOD u32 extended_limit; u32 extended_bucket; // MOD u64 last_update_time; // MOD u64 pad64; } policer_read_response_type_st; static inline policer_result_e vnet_police_packet (policer_read_response_type_st * policer, u32 packet_length, policer_result_e packet_color, u64 time) { u64 n_periods; u64 current_tokens, extended_tokens; policer_result_e result; // Scale packet length to support a wide range of speeds packet_length = packet_length << policer->scale; // Compute the number of policer periods that have passed since the last // operation. n_periods = time - policer->last_update_time; policer->last_update_time = time; if (policer->single_rate){ // Compute number of tokens for this time period current_tokens = policer->current_bucket + n_periods * policer->cir_tokens_per_period; if (current_tokens > policer->current_limit) { current_tokens = policer->current_limit; } extended_tokens = policer->extended_bucket + n_periods * policer->cir_tokens_per_period; if (extended_tokens > policer->extended_limit) { extended_tokens = policer->extended_limit; } // Determine color if ((!policer->color_aware || (packet_color == POLICE_CONFORM)) && (current_tokens >= packet_length)) { policer->current_bucket = current_tokens - packet_length; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_CONFORM; } else if ((!policer->color_aware || (packet_color != POLICE_VIOLATE)) && (extended_tokens >= packet_length)) { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_EXCEED; } else { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens; result = POLICE_VIOLATE; } } else { // Two-rate policer // Compute number of tokens for this time period current_tokens = policer->current_bucket + n_periods * policer->cir_tokens_per_period; extended_tokens =policer->extended_bucket + n_periods * policer->pir_tokens_per_period; if (current_tokens > policer->current_limit) { current_tokens = policer->current_limit; } if (extended_tokens > policer->extended_limit) { extended_tokens = policer->extended_limit; } // Determine color if ((policer->color_aware && (packet_color == POLICE_VIOLATE)) || (extended_tokens < packet_length)) { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens; result = POLICE_VIOLATE; } else if ((policer->color_aware && (packet_color == POLICE_EXCEED)) || (current_tokens < packet_length)) { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_EXCEED; } else { policer->current_bucket = current_tokens - packet_length; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_CONFORM; } } return result; } #endif // __POLICE_H__ |
根据限速规则的设置,主要操作就是计算保证速率和峰值速率当前获得的令牌数,剩下就是根据配置的策略,来判断当前报文的决策。
// Compute the number of policer periods that have passed since the last operation. n_periods = time - policer->last_update_time; policer->last_update_time = time; // Compute number of tokens for this time period current_tokens = policer->current_bucket + n_periods * policer->cir_tokens_per_period; if (current_tokens > policer->current_limit){ current_tokens = policer->current_limit; } extended_tokens = policer->extended_bucket + n_periods * policer->cir_tokens_per_period; if (extended_tokens > policer->extended_limit){ extended_tokens = policer->extended_limit; } |
RateLimiter
源码:https://github.com/mfycheng/ratelimiter
std::chrono::microseconds RateLimiter::claim_next(double permits) { using namespace std::chrono; std::lock_guard<std::mutex> lock(mut_); unsigned long long now = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count(); // Make sure we're synced sync(now); // Since we synced before hand, this will always be >= 0. unsigned long long wait = next_free_ - now; // Determine how many stored and freh permits to consume double stored = std::min(permits, stored_permits_); double fresh = permits - stored; // In the general RateLimiter, stored permits have no wait time, // and thus we only have to wait for however many fresh permits we consume long next_free = (long)(fresh * interval_); next_free_ += next_free; stored_permits_ -= stored; return microseconds(wait); } |
相比上面的代码,核心思想也是利用令牌桶,但使用起来更简单。