📄 madwifirate.cc
字号:
/* * madwifirate.{cc,hh} -- sets wifi txrate annotation on a packet * John Bicket * * Copyright (c) 2003 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <click/confparse.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/packet_anno.hh>#include <click/straccum.hh>#include <clicknet/ether.h>#include <clicknet/wifi.h>#include <elements/wifi/availablerates.hh>#include "madwifirate.hh"CLICK_DECLS#define max(a, b) ((a) > (b) ? (a) : (b))#define min(a, b) ((a) < (b) ? (a) : (b))#define CREDITS_FOR_RAISE 10#define STEPUP_RETRY_THRESHOLD 10MadwifiRate::MadwifiRate() : Element(2, 1), _max_tries(4), // wenjun mods _stepup(0), _stepdown(0), _offset(0), _timer(this), _packet_size_threshold(0){ /* bleh */ static unsigned char bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; _bcast = EtherAddress(bcast_addr);}voidMadwifiRate::run_timer(){ _timer.schedule_after_ms(_period); adjust_all();}MadwifiRate::~MadwifiRate(){}voidMadwifiRate::notify_noutputs(int n){ set_noutputs(n <= 2 ? n : 1);}int MadwifiRate::initialize(ErrorHandler *) { _timer.initialize(this); _timer.schedule_now(); return 0;}intMadwifiRate::configure(Vector<String> &conf, ErrorHandler *errh){ _alt_rate = false; _active = true; _period = 1000; int ret = cp_va_parse(conf, this, errh, cpKeywords, "OFFSET", cpUnsigned, "offset", &_offset, "RT", cpElement, "availablerates", &_rtable, "THRESHOLD", cpUnsigned, "xxx", &_packet_size_threshold, "ALT_RATE", cpBool, "xxx", &_alt_rate, "ACTIVE", cpBool, "xxx", &_active, "PERIOD", cpUnsigned, "xxx", &_period, "MAXTRIES", cpUnsigned, "xxx", &_max_tries, // wenjun mods 0); return ret;}void MadwifiRate::adjust_all(){ Vector<EtherAddress> n; for (NIter iter = _neighbors.begin(); iter; iter++) { DstInfo nfo = iter.value(); n.push_back(nfo._eth); } for (int x =0; x < n.size(); x++) { adjust(n[x]); }}void MadwifiRate::adjust(EtherAddress dst) { DstInfo *nfo = _neighbors.findp(dst); bool stepup = false; bool stepdown = false; if (nfo->_failures > 0 && nfo->_successes == 0) { stepdown = true; } bool enough = (nfo->_successes + nfo->_failures) > 10; /* all packets need retry in average */ if (enough && nfo->_successes < nfo->_retries) stepdown = true; /* no error and less than 10% of packets need retry */ if (enough && nfo->_failures == 0 && nfo->_retries < (nfo->_successes * STEPUP_RETRY_THRESHOLD) / 100) stepup = true; if (stepdown) { if (_debug && max(nfo->_current_index - 1, 0) != nfo->_current_index) { click_chatter("%{element} stepping down for %s from %d to %d\n", this, nfo->_eth.s().cc(), nfo->_rates[nfo->_current_index], nfo->_rates[max(0, nfo->_current_index - 1)]); } nfo->_current_index = max(nfo->_current_index - 1, 0); nfo->_credits = 0; } else if (stepup) { nfo->_credits++; if (nfo->_credits >= CREDITS_FOR_RAISE) { if (_debug) { click_chatter("%{element} steping up for %s from %d to %d\n", this, nfo->_eth.s().cc(), nfo->_rates[nfo->_current_index], nfo->_rates[min(nfo->_rates.size() - 1, nfo->_current_index + 1)]); } nfo->_current_index = min(nfo->_current_index + 1, nfo->_rates.size() - 1); nfo->_credits = 0; } } else { if (enough && nfo->_credits > 0) { nfo->_credits--; } } nfo->_successes = 0; nfo->_failures = 0; nfo->_retries = 0;}voidMadwifiRate::process_feedback(Packet *p_in){ if (!p_in) { click_chatter("%{element} bad packet %s\n", this, __func__); return; } uint8_t *dst_ptr = (uint8_t *) p_in->data() + _offset; EtherAddress dst = EtherAddress(dst_ptr); struct click_wifi_extra *ceh = (struct click_wifi_extra *) p_in->all_user_anno(); bool success = !(ceh->flags & WIFI_EXTRA_TX_FAIL); bool used_alt_rate = ceh->flags & WIFI_EXTRA_TX_USED_ALT_RATE; struct timeval now; click_gettimeofday(&now); // wenjun mods String flag = (used_alt_rate)?"true":"false"; click_chatter("%s: processing feedback, rate %u, alted rate %s, retries %u", id().cc(), ceh->rate, flag.cc(), ceh->retries); if (dst.is_group() || !ceh->rate || (success && p_in->length() < _packet_size_threshold)) { return; } DstInfo *nfo = _neighbors.findp(dst); if (!nfo || nfo->pick_rate() != ceh->rate) { return; } if (!success && _debug) { click_chatter("%{element} packet failed %s success %d rate %d alt %d\n", this, dst.s().cc(), success, ceh->rate, ceh->rate1 ); } if (success && (!_alt_rate || !used_alt_rate)) { nfo->_successes++; nfo->_retries += ceh->retries; } else { nfo->_failures++; nfo->_retries += _max_tries; } return;}voidMadwifiRate::assign_rate(Packet *p_in){ if (!p_in) { click_chatter("%{element} ah, !p_in\n", this); return; } uint8_t *dst_ptr = (uint8_t *) p_in->data() + _offset; EtherAddress dst = EtherAddress(dst_ptr); struct click_wifi_extra *ceh = (struct click_wifi_extra *) p_in->all_user_anno(); if (dst.is_group()) { Vector<int> rates = _rtable->lookup(_bcast); if (rates.size()) { ceh->rate = rates[0]; } else { ceh->rate = 2; } return; } DstInfo *nfo = _neighbors.findp(dst); if (!nfo || !nfo->_rates.size()) { Vector<int> rates = _rtable->lookup(dst); if (!rates.size()) { return; } _neighbors.insert(dst, DstInfo(dst)); nfo = _neighbors.findp(dst); nfo->_rates = rates; nfo->_successes = 0; nfo->_retries = 0; nfo->_failures = 0; /* initial to 24 in g/a, 11 in b */ int ndx = nfo->rate_index(48); ndx = ndx > 0 ? ndx : nfo->rate_index(22); ndx = max(ndx, 0); nfo->_current_index = ndx; nfo->_credits = 0; if (_debug) { click_chatter("%{element} initial rate for %s is %d\n", this, nfo->_eth.s().cc(), nfo->_rates[nfo->_current_index]); } } ceh->magic = WIFI_EXTRA_MAGIC; int ndx = nfo->_current_index; ceh->rate = nfo->_rates[ndx]; ceh->rate1 = (ndx - 1 >= 0) ? nfo->_rates[max(ndx - 1, 0)] : 0; ceh->rate2 = (ndx - 2 >= 0) ? nfo->_rates[max(ndx - 2, 0)] : 0; ceh->rate3 = (ndx - 3 >= 0) ? nfo->_rates[max(ndx - 3, 0)] : 0; ceh->max_tries = _max_tries; ceh->max_tries1 = (ndx - 1 >= 0) ? 2 : 0; ceh->max_tries2 = (ndx - 2 >= 0) ? 2 : 0; ceh->max_tries3 = (ndx - 3 >= 0) ? 2 : 0; // wenjun mods click_chatter("%s: assigning rate, rate %u, tries %u", id().cc(), ceh->rate, ceh->max_tries); return; }Packet *MadwifiRate::pull(int port){ Packet *p = input(port).pull(); if (p && _active) { assign_rate(p); } return p;}voidMadwifiRate::push(int port, Packet *p_in){ if (!p_in) { return; } if (_active) { if (port != 0) { process_feedback(p_in); } else { assign_rate(p_in); } } checked_output_push(port, p_in);}StringMadwifiRate::print_rates() { StringAccum sa; for (NIter iter = _neighbors.begin(); iter; iter++) { DstInfo nfo = iter.value(); sa << nfo._eth << " "; if (nfo._rates.size()) { sa << nfo._rates[nfo._current_index]; sa << " successes " << nfo._successes; sa << " failures " << nfo._failures; sa << " retries " << nfo._retries; sa << " credits " << nfo._credits; } sa << "\n"; } return sa.take_string();}enum {H_DEBUG, H_STEPUP, H_STEPDOWN, H_THRESHOLD, H_RATES, H_RESET, H_OFFSET, H_ACTIVE, H_PERIOD, H_ALT_RATE, H_MAXTRIES // wenjun mods};static StringMadwifiRate_read_param(Element *e, void *thunk){ MadwifiRate *td = (MadwifiRate *)e; switch ((uintptr_t) thunk) { case H_DEBUG: return String(td->_debug) + "\n"; case H_STEPDOWN: return String(td->_stepdown) + "\n"; case H_STEPUP: return String(td->_stepup) + "\n"; case H_THRESHOLD: return String(td->_packet_size_threshold) + "\n"; case H_OFFSET: return String(td->_offset) + "\n"; case H_ALT_RATE: return String(td->_alt_rate) + "\n"; case H_RATES: { return td->print_rates(); } case H_ACTIVE: return String(td->_active) + "\n"; case H_PERIOD: return String(td->_period) + "\n"; case H_MAXTRIES: // wenjun mods return String(td->_max_tries) + "\n"; // wenjun mods default: return String(); }}static int MadwifiRate_write_param(const String &in_s, Element *e, void *vparam, ErrorHandler *errh){ MadwifiRate *f = (MadwifiRate *)e; String s = cp_uncomment(in_s); switch((int)vparam) { case H_DEBUG: { bool debug; if (!cp_bool(s, &debug)) return errh->error("debug parameter must be boolean"); f->_debug = debug; break; } case H_ALT_RATE: { bool alt_rate; if (!cp_bool(s, &alt_rate)) return errh->error("alt_rate parameter must be boolean"); f->_alt_rate = alt_rate; break; } case H_STEPUP: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("stepup parameter must be unsigned"); f->_stepup = m; break; } case H_STEPDOWN: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("stepdown parameter must be unsigned"); f->_stepdown = m; break; } case H_THRESHOLD: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("threshold parameter must be unsigned"); f->_packet_size_threshold = m; break; } case H_OFFSET: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("offset parameter must be unsigned"); f->_offset = m; break; } case H_PERIOD: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("period parameter must be unsigned"); f->_period = m; break; } case H_RESET: f->_neighbors.clear(); break; case H_ACTIVE: { bool active; if (!cp_bool(s, &active)) return errh->error("active must be boolean"); f->_active = active; break; } // wenjun mods case H_MAXTRIES: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("max_tries parameter must be unsigned"); f->_max_tries = m; break; } // ------------ } return 0;}voidMadwifiRate::add_handlers(){ add_default_handlers(true); add_read_handler("debug", MadwifiRate_read_param, (void *) H_DEBUG); add_read_handler("rates", MadwifiRate_read_param, (void *) H_RATES); add_read_handler("threshold", MadwifiRate_read_param, (void *) H_THRESHOLD); add_read_handler("stepup", MadwifiRate_read_param, (void *) H_STEPUP); add_read_handler("stepdown", MadwifiRate_read_param, (void *) H_STEPDOWN); add_read_handler("offset", MadwifiRate_read_param, (void *) H_OFFSET); add_read_handler("active", MadwifiRate_read_param, (void *) H_ACTIVE); add_read_handler("alt_rate", MadwifiRate_read_param, (void *) H_ALT_RATE); add_read_handler("max_tries", MadwifiRate_read_param, (void *) H_MAXTRIES); // wenjun mods add_write_handler("debug", MadwifiRate_write_param, (void *) H_DEBUG); add_write_handler("threshold", MadwifiRate_write_param, (void *) H_THRESHOLD); add_write_handler("stepup", MadwifiRate_write_param, (void *) H_STEPUP); add_write_handler("stepdown", MadwifiRate_write_param, (void *) H_STEPDOWN); add_write_handler("offset", MadwifiRate_write_param, (void *) H_OFFSET); add_write_handler("reset", MadwifiRate_write_param, (void *) H_RESET); add_write_handler("active", MadwifiRate_write_param, (void *) H_ACTIVE); add_write_handler("alt_rate", MadwifiRate_write_param, (void *) H_ALT_RATE); add_write_handler("max_tries", MadwifiRate_write_param, (void *) H_MAXTRIES); // wenjun mods}// generate Vector template instance#include <click/bighashmap.cc>#include <click/dequeue.cc>#include <click/vector.cc>#if EXPLICIT_TEMPLATE_INSTANCEStemplate class HashMap<EtherAddress, MadwifiRate::DstInfo>;template class DEQueue<MadwifiRate::tx_result>;template class Vector<EtherAddress>;#endifCLICK_ENDDECLSEXPORT_ELEMENT(MadwifiRate)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -