Page MenuHomec4science

forwarder.cc
No OneTemporary

File Metadata

Created
Fri, Jul 4, 15:26

forwarder.cc

#include <click/config.h>
#include "util.hh"
#include "forwarder.hh"
CLICK_DECLS
Forwarder::Forwarder() : _notifier(ActiveNotifier::SEARCH_CONTINUE_WAKE) {}
Forwarder::~Forwarder(){}
void * Forwarder::cast(const char *n)
{
if (strcmp(n, ActiveNotifier::EMPTY_NOTIFIER) == 0){
return &_notifier;
}
else
return Element::cast(n);
}
int Forwarder::configure(Vector<String> &conf, ErrorHandler *errh){
click_chatter("[Forwarder] enters configure.\n");
_notifier.initialize(ActiveNotifier::EMPTY_NOTIFIER, router());
_debug = false;
_verb_debug = false;
_node_index = -1;
_print_freq = 1;
_print_info = false;
_priority_encap = "";
if (Args(conf, this, errh)
.read_m("NEIGHBORS", _neighbors_name)
.read("INT1_ADDR", _addr_int1)
.read("INT2_ADDR", _addr_int2)
.read("DEBUG", _debug)
.read("VERB_DEBUG", _verb_debug)
.read("NODE_INDEX", _node_index)
.read("PRINT_FREQ", _print_freq)
.read("PRINT_INFO", _print_info)
.read("PRIORITY_ENCAP", _priority_encap) // can be TOS or VLAN
.complete() < 0)
return -1;
if(_verb_debug)
_debug = true;
if(!(_priority_encap.equals("TOS") || _priority_encap.equals("VLAN"))) {
if(_priority_encap.length() > 0)
click_chatter("[Forwarder] WARNING: valid values for PRIORITY_ENCAP are TOS or VLAN; no priority encapsulation");
_priority_encap = "";
}
if(_node_index != -1){
//we are part of a compound element, we need to adapt the names of the elements...
String index_str = String(_node_index);
String tempstr = String("node")+index_str.c_str();
tempstr = tempstr + "/";
_neighbors_name = tempstr + _neighbors_name.c_str();
}
_neighbors = (Neighbors*)router()->find(_neighbors_name, errh);
if(_addr_int1 != _empty_eth) _nr_interfaces++;
if(_addr_int2 != _empty_eth) _nr_interfaces++;
if(_nr_interfaces == 0)
return errh->error("[Forwarder]: Need at least 1 interface !");
if (_neighbors && _neighbors->cast("Neighbors") == 0)
return errh->error("[Forwarder] NEIGHBORS element is not a Neighbors");
if(_debug) click_chatter("[Forwarder] configure done.\n");
return 0;
}
int Forwarder::initialize(ErrorHandler *errh){
if(_debug)
click_chatter("[Forwarder] Initializing...\n");
Element::initialize(errh);
if(_debug)
click_chatter("[Forwarder] Initialized!\n");
_bytes_sent = Vector<uint32_t>(noutputs(),0);
return 0;
}
void Forwarder::push(int port, Packet* p){
//Receives a layer 2.5 frame.
// must be routed (if I'm in the route): get next hop, update routing header,
// add next hop address and forward (output corresponding to the interface)
Timestamp now;
/*if (_debug)
now.assign_now();
if(_debug) click_chatter("[Forwarder %s]: Checking the route...", now.unparse().c_str());*/
acne_header *hdr = (acne_header *)(p->data());
EtherAddress next_hop = _neighbors->get_eth_addr_from_last_bytes(&(hdr->_route._route[(hdr->_hop)*NB_BYTES_HOP]));
//EtherAddress next_hop;
//Packet *p_temp = update_routing_header(p, next_hop);
//if(next_hop==_empty_eth) {
if(next_hop == EtherAddress()){
if(_debug) {
now.assign_now();
click_chatter("[Forwarder %s]: I don't know to whom to forward: discard packet (length %d).", now.unparse().c_str(), p->length());
}
//p_temp->kill();
p->kill();
return;
}
// packet must be forwaded
/*if (_debug)
now.assign_now();
if(_debug) click_chatter("[Forwarder %s]: Packet must be forwarded to %s. Adding MAC header...", now.unparse().c_str(), next_hop->unparse().c_str());*/
int interface_out = 0;
if(_nr_interfaces > 1){
interface_out = _neighbors->get_interface_to_neighbor(next_hop);
//0 = PLC, 1 = WIFI
if(interface_out == -1){
if(_debug) click_chatter("[Forwarder] Unknown output interface for packet with type %d, hop %d and route %s (next hop %s), dropping packet.", hdr->_type, hdr->_hop, hdr->_route.unparse().c_str(), next_hop.unparse().c_str());
//p_temp->kill();
p->kill();
return;
}
}
hdr->_hop++;
WritablePacket *p_eth = p->uniqueify();
bool add_ip = false;
bool add_vlan = false;
// if MAB ack or control, add IP header with high priority
if((hdr->_type == MAB_ACK || hdr->_type == MAB_CONTROL || hdr->_type == SPECIAL_TRAFFIC) && _priority_encap.length() > 0) {
if(_priority_encap.equals("TOS")) {
add_ip = true;
p_eth = p_eth->push(sizeof(click_ip));
if (!p_eth) {
click_chatter("[Forwarder] WARNING: couldn't add space for new IP header\n");
p_eth->kill();
return;
}
click_ip *ip_hdr = (click_ip *) p_eth->data();
memset(ip_hdr, 0, sizeof(click_ip));
// fake IP header (only TOS field is useful anyway)
ip_hdr->ip_v = 4;
ip_hdr->ip_hl = sizeof(click_ip) >> 2;
// make different TTL for debug
if(hdr->_type == MAB_ACK)
ip_hdr->ip_ttl = 100;
else
ip_hdr->ip_ttl = 200;
ip_hdr->ip_id = hdr->_id_rate_mab;
ip_hdr->ip_p = IP_PROTO_IPIP;
ip_hdr->ip_dst = IPAddress("10.10.10.100").in_addr(); // fake IP address
ip_hdr->ip_src = IPAddress("10.10.10.100").in_addr();
ip_hdr->ip_len = htons(p_eth->length());
// TOS field
ip_hdr->ip_tos = 160; // class 2 for PLC
#if HAVE_FAST_CHECKSUM
ip_hdr->ip_sum = ip_fast_csum((unsigned char *) ip_hdr, sizeof(click_ip) >> 2);
#else
ip_hdr->ip_sum = click_in_cksum((unsigned char *) ip_hdr, sizeof(click_ip));
#endif
p_eth->set_ip_header(ip_hdr, sizeof(click_ip));
}
else if (_priority_encap.equals("VLAN")) {
add_vlan = true;
p_eth = p_eth->push_mac_header(sizeof(click_ether_vlan));
if (!p_eth) {
click_chatter("[Forwarder] WARNING: couldn't add space for new Ethernet header\n");
p_eth->kill();
return;
}
memset(p_eth->data(),0,sizeof(click_ether_vlan));
click_ether_vlan *vlan = (click_ether_vlan *) p_eth->data();
vlan->ether_vlan_proto = htons(ETHERTYPE_8021Q);
vlan->ether_vlan_tci = htons(0xAAA | 5 << 13); // VLAN ID + PCP
vlan->ether_vlan_encap_proto = htons(ETHERTYPE_ACNE);
}
}
click_ether *eth_hdr = (click_ether *) (p_eth->data());
if (!add_vlan) {
// add the ethernet header
p_eth = p_eth->push_mac_header(sizeof(click_ether));
if (!p_eth) {
click_chatter("[Forwarder] WARNING: couldn't add space for new Ethernet header\n");
p_eth->kill();
return;
}
memset(p_eth->data(),0,sizeof(click_ether));
eth_hdr = (click_ether *) (p_eth->data());
if(add_ip)
eth_hdr->ether_type = htons(ETHERTYPE_IP);
else
eth_hdr->ether_type = htons(ETHERTYPE_ACNE);
}
// for VLAN, first 12 bytes are addresses: OK to use click_ether
if(_nr_interfaces > 1) {
if(interface_out == INTERFACE2)
memcpy(eth_hdr->ether_shost, _addr_int2.data(), 6);
else if(interface_out == INTERFACE1)
memcpy(eth_hdr->ether_shost, _addr_int1.data(), 6);
}
else {
if (_addr_int1 != _empty_eth)
memcpy(eth_hdr->ether_shost, _addr_int1.data(), 6);
else if (_addr_int2 != _empty_eth)
memcpy(eth_hdr->ether_shost, _addr_int2.data(), 6);
else // should not happen
click_chatter("[Forwarder] WARNING: no address given??\n");
}
memcpy(eth_hdr->ether_dhost, next_hop.data(), 6);
if (_debug || _print_info) {
now.assign_now();
if(_verb_debug) click_chatter("[Forwarder %s]: Packet for %s goes to output %d (0 = PLC, 1 = WIFI).", now.unparse().c_str(), next_hop.unparse().c_str(), interface_out);
Timestamp diff = (now-_last_print);
if (diff.sec() >= _print_freq) {
StringAccum s;
s << "[Forwarder-" << name() << " " << now.unparse() << "] Sent ";
uint32_t total=0;
for (int i=0;i<_bytes_sent.size();i++) {
uint32_t rate = int_divide(_bytes_sent[i],diff.msecval());
total+=rate;
s << String(rate) << " kB/s on output " << i << ", ";
}
s << "total " << String(total) << " kB/s.";
click_chatter("%s", s.take_string().c_str());
_last_print.assign_now();
_bytes_sent = Vector<uint32_t>(noutputs(),0);
}
}
if(noutputs() == 1) {
_bytes_sent[0]+=p_eth->length();
output(0).push(p_eth);
}
else {
_bytes_sent[interface_out]+=p_eth->length();
output(interface_out).push(p_eth);
}
}
int
Forwarder::debug_handler(const String &s, Element *e, void *,
ErrorHandler *errh) {
Forwarder *elmt = (Forwarder *)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");
elmt->set_debug(debug==1);
return 0;
}
int
Forwarder::print_freq_handler(const String &s, Element *e, void *,
ErrorHandler *errh) {
Forwarder *elmt = (Forwarder *)e;
int freq;
if(!cp_integer(s, &freq))
return errh->error("Frequency must be an integer");
if(freq <= 0)
return errh->error("Frequency must be strictly positive");
elmt->set_freq(freq);
return 0;
}
void Forwarder::add_handlers() {
add_write_handler("debug", debug_handler, 0);
add_write_handler("print_freq", print_freq_handler, 0);
}
/*Packet *
Forwarder::update_routing_header(Packet *p_in, EtherAddress& next_hop) {
acne_header *hdr = (acne_header *)(p_in->data());
if(_debug) click_chatter("[Forwarder:%d] header: type=%d, hop=%d, seq=%d, route=%s",_node_index, hdr->_type, hdr->_hop, hdr->_seq, hdr->_route.unparse().c_str());
next_hop = get_eth_address_source_routing(hdr->_route._route, hdr->_hop);
hdr->_hop++;
return p_in;
}
EtherAddress
Forwarder::get_eth_address_source_routing(unsigned char *route, uint8_t hop) const {
unsigned char data[NB_BYTES_HOP];
for (int b=0;b<NB_BYTES_HOP;b++) {
data[b] = route[hop*NB_BYTES_HOP + b];
}
return _neighbors->get_eth_addr_from_last_bytes(data);
}*/
/*Packet *
Forwarder::add_header(Packet *p_in, EtherAddress next_hop, int interface_out) const{
//if(_debug) click_chatter("[Forwarder] Adding header");
// add the ethernet header
WritablePacket *p = p_in->push_mac_header(sizeof(click_ether));
if (!p) {
click_chatter("[Forwarder] couldn't add space for new Ethernet header\n");
return p;
}
//Julien: is that needed?
//click_ip *ip = (click_ip *)(p->data() + sizeof(acne_header) + sizeof(click_ether));
//p->set_ip_header(ip, sizeof(click_ip));
click_ether *eth_hdr = (click_ether *) (p->data());
eth_hdr->ether_type = htons(ETHERTYPE_ACNE);
if(interface_out == INTERFACE2)
memcpy(eth_hdr->ether_shost, _addr_int2.data(), 6);
else if(interface_out == INTERFACE1)
memcpy(eth_hdr->ether_shost, _addr_int1.data(), 6);
memcpy(eth_hdr->ether_dhost, next_hop.data(), 6);
return p;
}*/
CLICK_ENDDECLS
EXPORT_ELEMENT(Forwarder)
ELEMENT_PROVIDES(Forwarder)

Event Timeline