📄 ettstat.cc
字号:
/* * John Bicket * * Copyright (c) 1999-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 <clicknet/ether.h>#include <click/error.hh>#include <click/glue.hh>#include <click/timer.hh>#include <click/straccum.hh>#include "ettstat.hh"#include "ettmetric.hh"#include "txcountmetric.hh"#include <clicknet/wifi.h>#include <elements/wifi/availablerates.hh>#include <elements/wifi/netcoding/guessmanager.hh>CLICK_DECLS// packet data should be 4 byte aligned #define ASSERT_ALIGNED(p) assert(((unsigned int)(p) % 4) == 0)#define min(x,y) ((x)<(y) ? (x) : (y))#define max(x,y) ((x)>(y) ? (x) : (y))enum { H_RESET, H_BCAST_STATS, H_BAD_VERSION, H_IP, H_TAU, H_PERIOD, H_PROBES,};static String ETTStat_read_param(Element *e, void *thunk){ ETTStat *td = (ETTStat *)e; switch ((uintptr_t) thunk) { case H_BCAST_STATS: return td->read_bcast_stats(); case H_BAD_VERSION: return td->bad_nodes(); case H_IP: return td->_ip.s() + "\n"; case H_TAU: return String(td->_tau) + "\n"; case H_PERIOD: return String(td->_period) + "\n"; case H_PROBES: { StringAccum sa; for(int x = 0; x < td->_ads_rs.size(); x++) { sa << td->_ads_rs[x]._rate << " " << td->_ads_rs[x]._size << " "; } return sa.take_string() + "\n"; } default: return String() + "\n"; }}static int ETTStat_write_param(const String &in_s, Element *e, void *vparam, ErrorHandler *errh){ ETTStat *f = (ETTStat *)e; String s = cp_uncomment(in_s); switch((int)vparam) { case H_RESET: { //reset f->reset(); break; } case H_TAU: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("tau parameter must be unsigned"); f->_tau = m; f->reset(); } case H_PERIOD: { unsigned m; if (!cp_unsigned(s, &m)) return errh->error("period parameter must be unsigned"); f->_period = m; f->reset(); } case H_PROBES: { Vector<RateSize> ads_rs; Vector<String> a; cp_spacevec(s, a); if (a.size() % 2 != 0) { return errh->error("must provide even number of numbers\n"); } for (int x = 0; x < a.size() - 1; x += 2) { int rate; int size; if (!cp_integer(a[x], &rate)) { return errh->error("invalid PROBES rate value\n"); } if (!cp_integer(a[x + 1], &size)) { return errh->error("invalid PROBES size value\n"); } ads_rs.push_back(RateSize(rate, size)); } if (!ads_rs.size()) { return errh->error("no PROBES provided\n"); } f->_ads_rs = ads_rs; } } return 0;}ETTStat::ETTStat() : _tau(10000), _period(1000), _sent(0), _ett_metric(0), _etx_metric(0), _arp_table(0), _next_neighbor_to_ad(0), _timer(this), _ads_rs_index(0), _rtable(0){ add_input();}ETTStat::~ETTStat(){}voidETTStat::notify_noutputs(int n) { set_noutputs(n > 0 ? 1 : 0); }//1. configure//2. initialize//3. take_stateintETTStat::configure(Vector<String> &conf, ErrorHandler *errh){ String probes; int res = cp_va_parse(conf, this, errh, cpKeywords, "ETHTYPE", cpUnsigned, "Ethernet encapsulation type", &_et, "IP", cpIPAddress, "IP address", &_ip, "ETH", cpEtherAddress, "Source Ethernet address", &_eth, "PERIOD", cpUnsigned, "Probe broadcast period (msecs)", &_period, "TAU", cpUnsigned, "Loss-rate averaging period (msecs)", &_tau, "ETT", cpElement, "ETT Metric element", &_ett_metric, "ETX", cpElement, "ETX Metric element", &_etx_metric, "ARP", cpElement, "ARPTable element", &_arp_table, "PROBES", cpString, "PROBES", &probes, "RT", cpElement, "AvailabeRates", &_rtable, "GUESSMGR", cpElement, "GuessManager element", &_guessmgr, cpEnd); if (res < 0) return res; if ((res = ETTStat_write_param(probes, this, (void *) H_PROBES, errh)) < 0) { return res; } if (!_et) { return errh->error("Must specify ETHTYPE"); } if (!_ip) { return errh->error("Invalid IPAddress specified\n"); } if (!_eth) { return errh->error("Invalid EtherAddress specified\n"); } if (_ett_metric && _ett_metric->cast("ETTMetric") == 0) { return errh->error("ETTMetric element is not a ETTMetric"); } if (_etx_metric && _etx_metric->cast("TXCountMetric") == 0) { return errh->error("ETXMetric element is not a ETXMetric"); } if (_rtable && _rtable->cast("AvailableRates") == 0) { return errh->error("RT element is not a AvailableRates"); } if (_arp_table && _arp_table->cast("ARPTable") == 0) { return errh->error("ARPTable element is not a ARPTable"); } if (_guessmgr && _guessmgr->cast("GuessManager") == 0) { return errh->error("GUESSMGR element is not a GuessManager"); } return res;}void add_jitter(unsigned int max_jitter, Timestamp *t) { unsigned j = (unsigned) (random() % (max_jitter + 1)); if (random() & 1) { *t += Timestamp::make_msec(j); } else { *t -= Timestamp::make_msec(j); } return;}voidETTStat::run_timer(){ int p = _period / _ads_rs.size(); unsigned max_jitter = p / 10; send_probe(); _next += Timestamp::make_msec(p); add_jitter(max_jitter, &_next); _timer.schedule_at(_next);}voidETTStat::take_state(Element *e, ErrorHandler *errh){ /* * take_state gets called after * --configure * --initialize * so we may need to unschedule probe timers * and sync them up so the rates don't get * screwed up. */ ETTStat *q = (ETTStat *)e->cast("ETTStat"); if (!q) { errh->error("Couldn't cast old ETTStat"); return; } _neighbors = q->_neighbors; _bcast_stats = q->_bcast_stats; _rev_arp = q->_rev_arp; _sent = q->_sent; _start = q->_start; if (Timestamp::now() < q->_next) { _timer.unschedule(); _timer.schedule_at(q->_next); _next = q->_next; } }void ETTStat::update_link(IPAddress from, IPAddress to, Vector<RateSize> rs, Vector<int> fwd, Vector<int> rev, uint32_t seq){ if (_ett_metric) { _ett_metric->update_link(from, to, rs, fwd, rev, seq); } if (_etx_metric) { _etx_metric->update_link(from, to, rs, fwd, rev, seq); } if (_guessmgr) { EtherAddress src = _arp_table->lookup(from); if (from == _ip) { src = EtherAddress(_eth.data()); } EtherAddress dst = _arp_table->lookup(to); if (to == _ip) { dst = EtherAddress(_eth.data()); } if ((src != _arp_table->_bcast) && (dst != _arp_table->_bcast)) { _guessmgr->update_del_prob(src, dst, rs, fwd, rev, seq); } }} voidETTStat::send_probe() { if (!_ads_rs.size()) { click_chatter("%{element} :: %s no probes to send at\n", this, __func__); return; } int size = _ads_rs[_ads_rs_index]._size; int rate = _ads_rs[_ads_rs_index]._rate; _ads_rs_index = (_ads_rs_index + 1) % _ads_rs.size(); _sent++; unsigned min_packet_sz = sizeof(click_ether) + sizeof(struct link_probe); if ((unsigned) size < min_packet_sz) { click_chatter("%{element} cannot send packet size %d: min is %d\n", this, size, min_packet_sz); return; } WritablePacket *p = Packet::make(size + 2); // +2 for alignment if (p == 0) { click_chatter("ETTStat %s: cannot make packet!", id().cc()); return; } ASSERT_ALIGNED(p->data()); p->pull(2); memset(p->data(), 0, p->length()); p->set_timestamp_anno(Timestamp::now()); // fill in ethernet header click_ether *eh = (click_ether *) p->data(); memset(eh->ether_dhost, 0xff, 6); // broadcast eh->ether_type = htons(_et); memcpy(eh->ether_shost, _eth.data(), 6); link_probe *lp = (struct link_probe *) (p->data() + sizeof(click_ether)); lp->_version = _ett_version; lp->_ip = _ip.addr(); lp->_seq = p->timestamp_anno().sec(); lp->_period = _period; lp->_tau = _tau; lp->_sent = _sent; lp->_flags = 0; lp->_rate = rate; lp->_size = size; lp->_num_probes = _ads_rs.size(); uint8_t *ptr = (uint8_t *) (lp + 1); uint8_t *end = (uint8_t *) p->data() + p->length(); Vector<int> rates; if (_rtable) { rates = _rtable->lookup(_eth); } if (rates.size() && 1 + ptr + rates.size() < end) { ptr[0] = rates.size(); ptr++; int x = 0; while (ptr < end && x < rates.size()) { ptr[x] = rates[x]; x++; } ptr += rates.size(); lp->_flags |= PROBE_AVAILABLE_RATES; } int num_entries = 0; while (ptr < end && num_entries < _neighbors.size()) { _next_neighbor_to_ad = (_next_neighbor_to_ad + 1) % _neighbors.size(); if (_next_neighbor_to_ad >= _neighbors.size()) { break; } probe_list_t *probe = _bcast_stats.findp(_neighbors[_next_neighbor_to_ad]); if (!probe) { click_chatter("%{element}: lookup for %s, %d failed in ad \n", this, _neighbors[_next_neighbor_to_ad].s().cc(), _next_neighbor_to_ad); } else { int size = probe->_probe_types.size()*sizeof(link_info) + sizeof(link_entry); if (ptr + size > end) { break; } num_entries++; link_entry *entry = (struct link_entry *)(ptr); entry->_ip = probe->_ip; entry->_seq = probe->_seq; if ((uint32_t) probe->_ip > (uint32_t) _ip) { entry->_seq = lp->_seq; } entry->_num_rates = probe->_probe_types.size(); ptr += sizeof(link_entry); Vector<RateSize> rates; Vector<int> fwd; Vector<int> rev; for (int x = 0; x < probe->_probe_types.size(); x++) { RateSize rs = probe->_probe_types[x]; link_info *lnfo = (struct link_info *) (ptr + x*sizeof(link_info)); lnfo->_size = rs._size; lnfo->_rate = rs._rate; lnfo->_fwd = probe->fwd_rate(rs._rate, rs._size); lnfo->_rev = probe->rev_rate(_start, rs._rate, rs._size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -