Page MenuHomec4science

tcpanalyzer.cc
No OneTemporary

File Metadata

Created
Sat, Jul 5, 07:45

tcpanalyzer.cc

#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