流量管理的实现

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);

}

 

相比上面的代码,核心思想也是利用令牌桶,但使用起来更简单。

 

posted on 2020-03-14 11:11  SunnyPoem  阅读(455)  评论(0编辑  收藏  举报