#include #include #include "log.h" #include "shaper.h" #include "shaper_aqm.h" thread_local unsigned int seed = 0; int shaper_aqm_blue_need_drop(uuid_t profile_uuid, struct shaper_aqm_blue_para *para, int curr_queue_len) { time_t curr_time; if (time(&curr_time) - para->update_time >= BLUE_FREEZE_TIME) { para->update_time = curr_time; if (curr_queue_len >= BLUE_QUEUE_LEN_MAX) { para->probability = (para->probability + BLUE_INCREMENT) > BLUE_PROBABILITY_MAX ? BLUE_PROBABILITY_MAX : (para->probability + BLUE_INCREMENT); } else if (curr_queue_len == 0) { para->probability = (para->probability - BLUE_DECREMENT) >= 0 ? (para->probability - BLUE_DECREMENT) : 0; } LOG_INFO("%s: profile id: %s blue probability update to %d", LOG_TAG_SHAPING, uuid_print_str(profile_uuid), para->probability); } if (rand_r(&seed) % BLUE_PROBABILITY_MAX < para->probability) { return 1; } return 0; } int shaper_aqm_codel_need_drop(uuid_t profile_uuid, struct shaper_aqm_codel_para *para, unsigned long long curr_time_ms, unsigned long long latency_ms) { if (latency_ms < CODEL_MAX_LATENCY) { if (para->state != CODEL_STATE_NORMAL) { para->state = CODEL_STATE_NORMAL; LOG_INFO("%s: profile id: %s codel enter state CODEL_STATE_NORMAL, last DROPPING_PHASE drop count %d", LOG_TAG_SHAPING, uuid_print_str(profile_uuid), para->drop_count); } return 0; } int ret = 0; switch (para->state) { case CODEL_STATE_NORMAL: para->start_drop_time_ms = curr_time_ms + CODEL_DROP_INTERVAL; para->state = CODEL_STATE_DROPPING_TIMER; LOG_INFO("%s: profile id: %s codel enter state CODEL_STATE_DROPPING_TIMER", LOG_TAG_SHAPING, uuid_print_str(profile_uuid)); break; case CODEL_STATE_DROPPING_TIMER: if (curr_time_ms >= para->start_drop_time_ms) { para->state = CODEL_STATE_DROPPING_PHASE; para->drop_count = 1; para->next_drop_time_ms = curr_time_ms + CODEL_DROP_INTERVAL / sqrt(para->drop_count); ret = 1; LOG_INFO("%s: profile id: %s codel enter state CODEL_STATE_DROPPING_PHASE", LOG_TAG_SHAPING, uuid_print_str(profile_uuid)); } break; case CODEL_STATE_DROPPING_PHASE: if (curr_time_ms >= para->next_drop_time_ms) { para->drop_count++; para->next_drop_time_ms = curr_time_ms + CODEL_DROP_INTERVAL / sqrt(para->drop_count); ret = 1; } break; default: break; } return ret; } static int shaper_aqm_have_processed(struct shaping_packet_wrapper *pkt_wrapper, uuid_t profile_uuid) { int i = 0; for (i = 0; i < SHAPING_REF_PROFILE_NUM_MAX; i++) { if (uuid_compare(profile_uuid, pkt_wrapper->aqm_processed_pf_uuids[i]) == 0) { return 1; } else if (uuid_is_null(pkt_wrapper->aqm_processed_pf_uuids[i])) { break; } } return 0; } static void shaper_aqm_mark_processed(struct shaping_packet_wrapper *pkt_wrapper, uuid_t profile_uuid) { int i = 0; for (i = 0; i < SHAPING_REF_PROFILE_NUM_MAX; i++) { if (uuid_is_null(pkt_wrapper->aqm_processed_pf_uuids[i])) { uuid_copy(pkt_wrapper->aqm_processed_pf_uuids[i], profile_uuid); break; } } } int shaper_aqm_need_drop(struct shaping_profile_info *profile, struct shaping_packet_wrapper *pkt_wrapper, enum shaping_packet_dir dir, struct timespec *curr_time, unsigned long long latency_us) { int ret = 0; unsigned long long curr_time_ms; if (profile->hash_node->aqm_type == AQM_TYPE_NONE) { return 0; } if (shaper_aqm_have_processed(pkt_wrapper, profile->uuid)) { return 0; } switch (profile->hash_node->aqm_type) { case AQM_TYPE_BLUE: ret = shaper_aqm_blue_need_drop(profile->uuid, &profile->hash_node->aqm_blue_para, profile->hash_node->queue_len[profile->priority][dir]); break; case AQM_TYPE_CODEL: curr_time_ms = curr_time->tv_sec * MILLI_SECONDS_PER_SEC + curr_time->tv_nsec / NANO_SECONDS_PER_MILLI_SEC; ret = shaper_aqm_codel_need_drop(profile->uuid, &profile->hash_node->aqm_codel_para, curr_time_ms, latency_us / 1000); break; default: break; } shaper_aqm_mark_processed(pkt_wrapper, profile->uuid); return ret; }