Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F120570953
tcpanalyzer.cc
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Jul 5, 07:45
Size
14 KB
Mime Type
text/x-c
Expires
Mon, Jul 7, 07:45 (2 d)
Engine
blob
Format
Raw Data
Handle
27186510
Attached To
R6591 HyMAB
tcpanalyzer.cc
View Options
#include <click/config.h>
#include "tcpanalyzer.hh"
CLICK_DECLS
#define VERB_DEBUG_CHATTER(arg, ...) do { if (_verb_debug) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
TcpAnalyzer::TcpAnalyzer() : _end_timer(this), _timer(this)
{
}
TcpAnalyzer::~TcpAnalyzer()
{
}
int
TcpAnalyzer::configure(Vector<String> &conf, ErrorHandler *errh)
{
_active = false;
_debug = false;
_verb_debug = false;
alpha_ts = 125;
_print_retransmission = false;
_check_retransmission = false;
_freq_print_debug = 1000;
if(Args(this, errh).bind(conf)
.read_m("IP", _my_ip)
.read("DEBUG", _debug)
.read("VERB_DEBUG", _verb_debug)
.read("ACTIVE", _active)
.read("CHECK_RETRANSMISSION", _check_retransmission)
.read("PRINT_RETRANSMISSION", _print_retransmission)
.read("FREQ_PRINT_DEBUG", _freq_print_debug) // in ms
.complete() < 0)
return -1;
return 0;
}
int
TcpAnalyzer::initialize(ErrorHandler *)
{
_end_timer.initialize(this);
_timer.initialize(this);
return 0;
}
void
TcpAnalyzer::push(int port, Packet *p)
{
VERB_DEBUG_CHATTER("[TcpAnalyzer %s] Push packet %p", Timestamp::now().unparse().c_str(), p);
if(!_active) {
output(port).push(p);
return;
}
if(p->ip_header_offset()==sizeof(acne_header)) {
// acne header is here
acne_header *acne_hdr = (acne_header *) p->data();
if(acne_hdr->_type == DUMMY_TRAFFIC_MAB) {
// dummy traffic
output(port).push(p);
return;
}
}
// timer is scheduled if there is no packets during one second
_end_timer.schedule_after_sec(1);
if(_debug && !_timer.scheduled())
_timer.schedule_after_msec(_freq_print_debug);
click_ip *ip_hdr = (click_ip *)(p->ip_header());
if(ip_hdr->ip_p == IP_PROTO_TCP) {
click_tcp *tcp_hdr = (click_tcp *)(p->tcp_header());
if(!tcp_hdr) {
output(port).push(p);
return;
}
IPAddress src = ip_hdr->ip_src;
IPAddress dst = ip_hdr->ip_dst;
uint16_t len = htons(ip_hdr->ip_len) - 52; // 52 is observed value (IP header + TCP header + 12 B padding)
uint32_t next_seq = htonl(tcp_hdr->th_seq)+len; // value that will be in ack
uint32_t ack_num = htonl(tcp_hdr->th_ack);
String s;
if(_verb_debug)
s = p->timestamp_anno().unparse()+": "+src.unparse()+"->"+dst.unparse()+"; seq "+
String(htonl(tcp_hdr->th_seq))+":"+String(next_seq)+"; ack "+String(ack_num);
bool traffic = true, ack=false;
if(tcp_hdr->th_flags & TH_SYN) {
if(_verb_debug)
s+="; SYN";
traffic = false;
}
if(tcp_hdr->th_flags & TH_ACK) {
uint16_t a = htons(ip_hdr->ip_len);
uint32_t b = tcp_hdr->th_off;
uint32_t c = a - b*4 - 20;
if(c==0) {
if(_verb_debug)
s+="; ACK.";
traffic = false;
ack=true;
}
}
tcp_hdr->th_flags &= ~TH_URG; // remove flag used for TCP retransmission
if(traffic && src==_my_ip) {
// if(!is_in_hash_table(_seq2ts,src)) {
// _seq2ts[src]=HashTable<uint32_t,Timestamp>();
// _packets_sent[src]=0;
// _packets_sent_iteration[src]=0;
// _repeated_transmissions[src] = HashTable<uint32_t,int>();
// _timeouts[src]=0;
// _rtt_est[src]=Timestamp();
// _rtt_std_est[src]=Timestamp();
// }
_packets_sent[src]++;
_packets_sent_iteration[src]++;
_now.assign_now();
if(_seq2ts[src].get(next_seq) != Timestamp()) {
if(_print_retransmission)
click_chatter("[TcpAnalyzer %s:%s] Repeated seq %u:%u for flow %s->%s", name().c_str(), p->timestamp_anno().unparse().c_str(), htonl(tcp_hdr->th_seq), next_seq,
src.unparse().c_str(), dst.unparse().c_str());
if(_check_retransmission) {
tcp_hdr->th_flags |= TH_URG;
}
// repeated transmission
_repeated_transmissions[src][next_seq]++;
_repeated_transmissions_iteration[src]++;
}
else {
_seq2ts[src][next_seq]=_now;
if(htonl(tcp_hdr->th_seq)!=_next_seq[dst] && _print_retransmission) {
int missed = (int) (htonl(tcp_hdr->th_seq) - _next_seq[dst]);
missed = missed/((int) next_seq-htonl(tcp_hdr->th_seq));
if(next_seq<htonl(tcp_hdr->th_seq)) //shouldn't happen, sanity check
missed=-1*missed;
click_chatter("[TcpAnalyzer %s:%s] Received seq %u:%u for flow %s->%s, seq should be %u (missed %d)", name().c_str(), p->timestamp_anno().unparse().c_str(), htonl(tcp_hdr->th_seq), next_seq,
src.unparse().c_str(), dst.unparse().c_str(), _next_seq[dst], missed);
}
_next_seq.set(dst,next_seq);
_repeated_transmissions[src][next_seq] = 0;
}
}
else if(ack) {
if(!_seq2ts[dst].empty()) {
// we are the source of a flow
// if(!is_in_hash_table(_acks_received,dst)) {
// _acks_received[dst]=0;
// _acks_received_iteration[dst]=0;
// _count_dup_acks[dst]=HashTable<uint32_t,int>();
// _amb_acks[dst] = 0;
// }
_acks_received[dst]++;
_acks_received_iteration[dst]++;
if(_seq2ts[dst].get(ack_num) != Timestamp()) {
_now.assign_now();
Timestamp rtt = _now-_seq2ts[dst][ack_num];
if(_verb_debug)
s+=" RTT is "+rtt.unparse()+"sec.";
if(_rtt_est[dst] == Timestamp())
_rtt_est[dst]=rtt;
else {
Timestamp diff = _rtt_est[dst]-rtt;
if(diff < Timestamp())
diff = -diff;
if(_rtt_std_est[dst] == Timestamp())
_rtt_std_est[dst]=diff;
else {
if(rtt > (_rtt_est[dst] + 4*_rtt_std_est[dst])) {
// TCP timeout
_timeouts[dst]++;
_timeouts_iteration[dst]++;
}
_rtt_std_est[dst] = ((1000-alpha_ts)*_rtt_std_est[dst] + alpha_ts*diff)/1000;
}
_rtt_est[dst] = ((1000-alpha_ts)*_rtt_est[dst] + alpha_ts*rtt)/1000;
}
_seq2ts[dst].erase(ack_num);
}
else {
// duplicate ack
_count_dup_acks[dst][ack_num]++;
_count_dup_acks_iteration[dst]++;
if(_repeated_transmissions[dst].get(ack_num) > 0) {
_amb_acks[dst]++;
}
}
}
}
if(_verb_debug) click_chatter("%s",s.c_str());
}
output(port).push(p);
}
void TcpAnalyzer::run_timer(Timer *t) {
if(_verb_debug) click_chatter("[TcpAnalyzer] Run timer");
_now.assign_now();
if(t==&_end_timer) {
for (HashTable<IPAddress, HashTable<uint32_t, Timestamp> >::iterator iter = _seq2ts.begin(); iter.live(); iter++) {
IPAddress src = iter.key();
if(_packets_sent[src] > 0) {
click_chatter("[TcpAnalyzer %s:%s] Results for %s", name().c_str(), _now.unparse().c_str(), src.unparse().c_str());
String s = "\tSent "+String(_packets_sent[src])+" packets, "+String(_repeated_transmissions[src].size())+" repeated.\n";
s+="\tThere was "+String(_timeouts[src])+" timeouts.\n";
s+="\tRepeated transmissions:\n";
Vector<int> num_rep_trans = Vector<int>(4,0) ;
for(HashTable<uint32_t,int>::iterator it = _repeated_transmissions[src].begin();it.live();it++) {
if(it.value() == 1)
num_rep_trans[0]++;
else if(it.value() == 2)
num_rep_trans[1]++;
else if(it.value() == 3)
num_rep_trans[2]++;
else
num_rep_trans[3]++;
}
s+="\t\t 1: "+String(num_rep_trans[0]);
s+="\n\t\t 2: "+String(num_rep_trans[1]);
s+="\n\t\t 3: "+String(num_rep_trans[2]);
s+="\n\t\t +: "+String(num_rep_trans[3]);
if(is_in_hash_table(_acks_received,src)) {
int tot_dup_acks = 0;
int max_num_dup_acks = 0;
uint32_t seq_max = 0;
Vector<int> num_dup_ack = Vector<int>(4,0) ;
for(HashTable<uint32_t,int>::iterator it = _count_dup_acks[src].begin();it.live();it++) {
if(it.value() == 1)
num_dup_ack[0]++;
else if(it.value() == 2)
num_dup_ack[1]++;
else if(it.value() == 3)
num_dup_ack[2]++;
else
num_dup_ack[3]++;
tot_dup_acks+=it.value();
if(it.value() > max_num_dup_acks) {
max_num_dup_acks = it.value();
seq_max = it.key();
}
}
s+="\n\tReceived "+String(_acks_received[src])+" acks, "+String(tot_dup_acks)+" duplicate (for "+String(_count_dup_acks[src].size())+" seq numbers), "+
String(_amb_acks[src])+" ambiguous.\n";
s+="\tDuplicate acks:\n";
s+="\t\t 1: "+String(num_dup_ack[0]);
s+="\n\t\t 2: "+String(num_dup_ack[1]);
s+="\n\t\t 3: "+String(num_dup_ack[2]);
s+="\n\t\t +: "+String(num_dup_ack[3])+"(max "+String(max_num_dup_acks)+" for seq "+String(seq_max)+")";
}
int max_bucket_size=0;
for (int i=0;i<_seq2ts[src].bucket_count();i++) {
if(_seq2ts[src].bucket_size(i) > max_bucket_size)
max_bucket_size = _seq2ts[src].bucket_size(i);
}
s+="\n\tSize of table: "+String(_seq2ts[src].size())+" ("+String(_seq2ts[src].bucket_count())+" buckets, max size "+String(max_bucket_size)+").";
click_chatter("%s",s.c_str());
}
_repeated_transmissions[src].clear();
_repeated_transmissions.erase(src);
_count_dup_acks[src].clear();
_count_dup_acks.erase(src);
_seq2ts[src].clear();
_seq2ts.erase(src);
_packets_sent.erase(src);
_packets_sent_iteration.erase(src);
_acks_received.erase(src);
_acks_received_iteration.erase(src);
_amb_acks.erase(src);
_timeouts.erase(src);
_rtt_est.erase(src);
_rtt_std_est.erase(src);
}
}
else if(t==&_timer) {
for (HashTable<IPAddress, int>::iterator iter = _packets_sent_iteration.begin(); iter.live(); iter++) {
if(iter.value() > 0) {
click_chatter("[TcpAnalyzer %s:%s] %s has sent %d packets (%d rep), received %d acks (%d dup), RTT est %s, std %s (%d timeouts).", name().c_str(), _now.unparse().c_str(),
iter.key().unparse().c_str(), iter.value(), _repeated_transmissions_iteration[iter.key()], _acks_received_iteration[iter.key()],
_count_dup_acks_iteration[iter.key()], _rtt_est[iter.key()].unparse().c_str(), _rtt_std_est[iter.key()].unparse().c_str(),
_timeouts_iteration[iter.key()]);
}
_acks_received_iteration[iter.key()] = 0;
_packets_sent_iteration[iter.key()] = 0;
_repeated_transmissions_iteration[iter.key()] = 0;
_count_dup_acks_iteration[iter.key()] = 0;
_timeouts_iteration[iter.key()] = 0;
}
}
}
int
TcpAnalyzer::active_handler(const String &s, Element *e, void *a,
ErrorHandler *errh) {
TcpAnalyzer *elmt = (TcpAnalyzer *)e;
int arg;
if(!cp_integer(s, &arg))
return errh->error("Active must be 0 or 1");
if (!(arg == 0 || arg == 1))
return errh->error("Active must be 0 or 1");
if(((intptr_t) a) == 0)
elmt->set_active(arg==1);
if(((intptr_t) a) == 1)
elmt->set_print_retransmission(arg==1);
return 0;
}
int
TcpAnalyzer::freq_print_debug_handler(const String &s, Element *e, void *a,
ErrorHandler *errh) {
TcpAnalyzer *elmt = (TcpAnalyzer *)e;
int arg;
if(!cp_integer(s, &arg))
return errh->error("Argument must be a strictly positive integer");
if (arg <= 0)
return errh->error("Argument must be a strictly positive integer");
if(((intptr_t) a) == 0)
elmt->set_freq_print_debug(arg);
return 0;
}
int
TcpAnalyzer::debug_handler(const String &s, Element *e, void *a,
ErrorHandler *errh) {
TcpAnalyzer *elmt = (TcpAnalyzer *)e;
int debug;
if(!cp_integer(s, &debug))
return errh->error("Debug must be 0 or 1");
if (!(debug == 0 || debug == 1))
return errh->error("Debug must be 0 or 1");
if(((intptr_t) a) == 0)
elmt->set_debug(debug==1);
else if(((intptr_t) a) == 1)
elmt->set_verb_debug(debug==1);
return 0;
}
void TcpAnalyzer::add_handlers() {
add_write_handler("debug", debug_handler, 0);
add_write_handler("verb_debug", debug_handler, 1);
add_write_handler("active", active_handler, 0);
add_write_handler("print_retransmission", active_handler, 1);
add_write_handler("freq_print_debug", freq_print_debug_handler, 0);
}
CLICK_ENDDECLS
EXPORT_ELEMENT(TcpAnalyzer)
ELEMENT_MT_SAFE(TcpAnalyzer)
Event Timeline
Log In to Comment