📄 probetxrate.cc
字号:
/* * probetxrate.{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 "probetxrate.hh"#include <elements/wifi/availablerates.hh>CLICK_DECLS#define PROBE_MAX_RETRIES 6ProbeTXRate::ProbeTXRate() : Element(2, 1), _offset(0), _packet_size_threshold(0), _rate_window_ms(0), _rtable(0){ static unsigned char bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; _bcast = EtherAddress(bcast_addr);}ProbeTXRate::~ProbeTXRate(){}voidProbeTXRate::notify_noutputs(int n){ set_noutputs(n <= 2 ? n : 1);}intProbeTXRate::configure(Vector<String> &conf, ErrorHandler *errh){ _debug = false; _active = true; _original_retries = 4; _min_sample = 20; int ret = cp_va_parse(conf, this, errh, cpKeywords, "OFFSET", cpUnsigned, "offset", &_offset, "WINDOW", cpUnsigned, "window", &_rate_window_ms, "THRESHOLD", cpUnsigned, "threshold", &_packet_size_threshold, "DEBUG", cpBool, "debug", &_debug, "RT", cpElement, "availablerates", &_rtable, "ACTIVE", cpBool, "xxx", &_active, cpEnd); if (ret < 0) { return ret; } if (_rate_window_ms <= 0) return errh->error("WINDOW must be > 0"); if (!_rtable || _rtable->cast("AvailableRates") == 0) return errh->error("AvailableRates element is not provided or not a AvailableRates"); _rate_window = Timestamp::make_msec(_rate_window_ms); return ret;}voidProbeTXRate::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() || !dst) { 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()) { _neighbors.insert(dst, DstInfo(dst, _rtable->lookup(dst))); nfo = _neighbors.findp(dst); } nfo->trim(Timestamp::now() - _rate_window); //nfo->check(); int best_ndx = nfo->best_rate_ndx(); if (nfo->_count++ % 10) { // pick the best bit-rate ceh->rate = nfo->_rates[best_ndx]; ceh->max_tries = 4; } else { //pick a random rate. Vector<int> possible = nfo->pick_rate(); if (possible.size()) { ceh->rate = possible[random() % possible.size()]; ceh->max_tries = 2; } else { // no rates to sample from ceh->rate = nfo->_rates[best_ndx]; ceh->max_tries = 4; } } ceh->rate1 = nfo->_rates[best_ndx]; ceh->max_tries1 = 2; ceh->rate2 = 0; ceh->max_tries2 = 0; ceh->rate3 = 0; ceh->max_tries3 = 0; return;}voidProbeTXRate::process_feedback(Packet *p_in) { if (!p_in) { 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); int retries = ceh->retries; Timestamp now = Timestamp::now(); if (dst == _bcast) { /* don't record info for bcast packets */ if (_debug) { click_chatter("%{element}: discarding bcast %s\n", this, dst.s().cc()); } return; } if (0 == ceh->rate) { /* rate wasn't set */ if (_debug) { click_chatter("%{element} no rate set for %s\n", this, dst.s().cc()); } return; } if (!success && p_in->length() < _packet_size_threshold) { /* * don't deal with short packets, * since they can skew what rate * we should be at */ if (_debug) { click_chatter("%{element} short success for %s\n", this, dst.s().cc()); } return; } DstInfo *nfo = _neighbors.findp(dst); if (!nfo) { if (_debug) { click_chatter("%{element} no info for %s\n", this, dst.s().cc()); } return; } if (!success && _debug) { click_chatter("%{element} packet failed %s retries %d rate %d alt %d\n", this, dst.s().cc(), retries, ceh->rate, ceh->rate1); } int tries = retries+1; bool s = (tries <= ceh->max_tries); int time = calc_usecs_wifi_packet(1500, ceh->rate, MIN(tries,ceh->max_tries)-1); if (_debug) { click_chatter("%{element}::%s() rate %d tries %d time %d\n", this, __func__, ceh->rate, tries, time); } nfo->add_result(now, ceh->rate, MIN(tries,ceh->max_tries), s, time); //nfo->check(); return ;}Packet *ProbeTXRate::pull(int port){ Packet *p = input(port).pull(); if (p && _active) { assign_rate(p); } return p;}voidProbeTXRate::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);}StringProbeTXRate::print_rates() { StringAccum sa; for (NIter iter = _neighbors.begin(); iter; iter++) { DstInfo nfo = iter.value(); sa << nfo._eth << "\n"; for (int x = 0; x < nfo._rates.size(); x++) { sa << " " << nfo._rates[x]; sa << " success " << nfo._total_success[x]; sa << " fail " << nfo._total_fail[x]; sa << " perfect_usecs " << nfo._perfect_time[x]; sa << " total_usecs " << nfo._total_time[x]; sa << " average_usecs " << nfo.average(x); sa << " average_tries "; if (nfo._packets[x]) { Timestamp average_tries = Timestamp::make_msec(nfo._total_tries[x] * 1000 / nfo._packets[x]); sa << average_tries; } else { sa << "0"; } sa << "\n"; } } return sa.take_string();}enum {H_DEBUG, H_RATES, H_THRESHOLD, H_RESET, H_OFFSET, H_ACTIVE, };static StringProbeTXRate_read_param(Element *e, void *thunk){ ProbeTXRate *td = (ProbeTXRate *)e; switch ((uintptr_t) thunk) { case H_DEBUG: return String(td->_debug) + "\n"; case H_THRESHOLD: return String(td->_packet_size_threshold) + "\n"; case H_OFFSET: return String(td->_offset) + "\n"; case H_RATES: return td->print_rates(); case H_ACTIVE: return String(td->_active) + "\n"; default: return String(); }}static int ProbeTXRate_write_param(const String &in_s, Element *e, void *vparam, ErrorHandler *errh){ ProbeTXRate *f = (ProbeTXRate *)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_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_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; } } return 0;}voidProbeTXRate::add_handlers(){ add_default_handlers(true); add_read_handler("debug", ProbeTXRate_read_param, (void *) H_DEBUG); add_read_handler("rates", ProbeTXRate_read_param, (void *) H_RATES); add_read_handler("threshold", ProbeTXRate_read_param, (void *) H_THRESHOLD); add_read_handler("offset", ProbeTXRate_read_param, (void *) H_OFFSET); add_read_handler("active", ProbeTXRate_read_param, (void *) H_ACTIVE); add_write_handler("debug", ProbeTXRate_write_param, (void *) H_DEBUG); add_write_handler("threshold", ProbeTXRate_write_param, (void *) H_THRESHOLD); add_write_handler("offset", ProbeTXRate_write_param, (void *) H_OFFSET); add_write_handler("reset", ProbeTXRate_write_param, (void *) H_RESET); add_write_handler("active", ProbeTXRate_write_param, (void *) H_ACTIVE); }// generate Vector template instance#include <click/bighashmap.cc>#include <click/dequeue.cc>#if EXPLICIT_TEMPLATE_INSTANCEStemplate class HashMap<EtherAddress, ProbeTXRate::DstInfo>;template class DEQueue<ProbeTXRate::tx_result>;#endifCLICK_ENDDECLSELEMENT_REQUIRES(bitrate)EXPORT_ELEMENT(ProbeTXRate)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -