Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F120467529
routingpaths.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
Fri, Jul 4, 14:44
Size
80 KB
Mime Type
text/x-c
Expires
Sun, Jul 6, 14:44 (2 d)
Engine
blob
Format
Raw Data
Handle
27189110
Attached To
R6591 HyMAB
routingpaths.cc
View Options
#include <click/config.h>
#include <click/package.hh>
#include <clicknet/ether.h>
#include <click/etheraddress.hh>
#include <click/ipaddress.hh>
#include <click/args.hh>
#include <click/bitvector.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include <clicknet/ip.h>
#include <click/router.hh>
#include <click/string.hh>
#include <click/vector.hh>
#include <click/confparse.hh>
#include <click/timestamp.hh>
#include "routingpaths.hh"
//#define DEBUG_CHATTER(arg, ...) do { if (_debug) { fprintf(stderr, "[%s] ", class_name()); fflush(stderr); click_chatter(arg, ## __VA_ARGS__);} } while (0)
//#define VERB_DEBUG_CHATTER(arg, ...) do { if (_verb_debug) { fprintf(stderr, "[%s] ", class_name()); fflush(stderr); click_chatter(arg, ## __VA_ARGS__);} } while (0)
//re-defined in kernel-compatible way:
#define DEBUG_CHATTER(arg, ...) do { if (_debug) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
#define VERB_DEBUG_CHATTER(arg, ...) do { if (_verb_debug) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
CLICK_DECLS
RoutingPaths::RoutingPaths() : timer(this)
{
}
RoutingPaths::~RoutingPaths()
{
}
int
RoutingPaths::configure(Vector<String> &conf, ErrorHandler *errh)
{
_multi_paths = false;
_debug = false;
_verb_debug = false;
_test_capa_one_hop = false;
_test_capa_one_hop_wifi = false;
_warning_n_N = false;
_print_routes_freq = 0;
_empty_eth = EtherAddress();
_time = 0;
_multirouting_2best_paths = false;
_k_value = 5;
_reset = false;
_csc_choice = "min";
_keep_routes = false;
adjacency_matrix = AdjacencyMatrix();
dijkstra_result = HashTable<VirtualNodeRouting,VirtualNodeRouting>();
me = NodeRouting();
EtherAddress addr_wifi, addr_plc, addr_wifi2;
int node_index = -1;
String rtl_name;
String compound_name;
String test_capa_one_hop_str;
_notify_invalid_links = false;
if(Args(this, errh).bind(conf)
.read_m("IP", me.ip)
//.read_m("ROUTING_LINKS", reinterpret_cast<Element *&>(_routing_links))
.read_m("ROUTING_LINKS", rtl_name)
.read_m("GW", _default_gw_ip)
.read("MULTI_PATHS", _multi_paths)
.read("DEBUG", _debug)
.read("VERB_DEBUG", _verb_debug)
.read("WIFI_ADDR", addr_wifi)
.read("PLC_ADDR", addr_plc)
.read("WIFI2_ADDR", addr_wifi2)
.read("CSC_CHOICE", _csc_choice)
.read("NODE_INDEX", node_index)
.read("PRINT_ROUTES", _print_routes_freq)
.read("TEST_CAPA_ONE_HOP", test_capa_one_hop_str)
.read("MULTIROUTING_2BEST_PATHS", _multirouting_2best_paths)
.read("NOTIFY_INVALID_LINKS", _notify_invalid_links)
.consume() < 0)
return -1;
if(test_capa_one_hop_str.compare("wifi") == 0) {
_test_capa_one_hop = true;
_test_capa_one_hop_wifi = true;
}
else if (test_capa_one_hop_str.compare("plc") == 0) {
_test_capa_one_hop = true;
_test_capa_one_hop_wifi = false;
}
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();
compound_name = tempstr + "/";
}
_routing_links = (RoutingLinks*)router()->find(rtl_name, compound_name, errh);
if(_routing_links == 0) {
return errh->error("No RoutingLinks element %s%s.",
compound_name.c_str(), rtl_name.c_str());
}
if(_routing_links->cast("RoutingLinks") == 0)
return errh->error("%s%s is not a RoutingLinks.",
compound_name.c_str(), rtl_name.c_str());
if(!(_csc_choice.compare("min") == 0 || _csc_choice.compare("no") == 0 ))
return errh->error("Possible values for CSC_CHOICE are min or no");
if(!(addr_wifi != _empty_eth || addr_plc != _empty_eth))
return errh->error("Needs at least one interface address");
Timestamp now;
now.assign_now();
if(addr_wifi != _empty_eth && addr_plc != _empty_eth) {
if(addr_wifi2 != _empty_eth)
return errh->error("[RoutingPaths] Cannot provide both WIFI2 and PLC");
me.interfaces=Vector<EtherAddress>(2,_empty_eth);
me.is_wifi=Vector<bool>(2,true);
me.interfaces[INTERFACE2] = addr_plc;
me.interfaces[INTERFACE1] = addr_wifi;
me.is_wifi[INTERFACE2] = false;
DEBUG_CHATTER("[RoutingPaths %s] Has interfaces Wifi %s and PLC %s.",
now.unparse().c_str(),addr_wifi.unparse().c_str(), addr_plc.unparse().c_str());
set_wifi_addr(addr_wifi);
set_plc_addr(addr_plc);
}
else if(addr_wifi != _empty_eth && addr_wifi2 != _empty_eth) {
me.interfaces=Vector<EtherAddress>(2,_empty_eth);
me.is_wifi=Vector<bool>(2,true);
me.interfaces[INTERFACE2] = addr_wifi2;
me.interfaces[INTERFACE1] = addr_wifi;
DEBUG_CHATTER("[RoutingPaths %s] Has interfaces Wifi %s and Wifi2 %s.",
now.unparse().c_str(),addr_wifi.unparse().c_str(), addr_wifi2.unparse().c_str());
set_wifi_addr(addr_wifi);
set_wifi_addr(addr_wifi2);
}
else if(addr_plc != _empty_eth) {
me.interfaces=Vector<EtherAddress>(1,addr_plc);
me.unique_interface = INTERFACE2;
me.unique_interface_wifi = false;
DEBUG_CHATTER("[RoutingPaths %s] Has interface PLC %s.", now.unparse().c_str(), addr_plc.unparse().c_str());
set_plc_addr(addr_plc);
}
else if(addr_wifi != _empty_eth) {
me.interfaces=Vector<EtherAddress>(1,addr_wifi);
me.unique_interface = INTERFACE1;
me.unique_interface_wifi = true;
DEBUG_CHATTER("[RoutingPaths %s] Has interface Wifi %s.",now.unparse().c_str(), addr_wifi.unparse().c_str());
set_wifi_addr(addr_wifi);
}
else
return errh->error("[RoutingPaths] Wrong combination of given addresses");
me.last_time_seen_node = now;
me.last_time_seen_interfaces = Vector<Timestamp>(me.interfaces.size(), now);
if (_verb_debug)
_debug = true;
if (_routing_links && _routing_links->cast("RoutingLinks") == 0)
return errh->error("ROUTING_LINKS element is not a RoutingLinks");
timer.initialize(this);
timer.schedule_after_msec(1000);
DEBUG_CHATTER("[RoutingPaths %s] RoutingPaths configured with %d interfaces!",now.unparse().c_str(), me.interfaces.size());
if(_verb_debug) {
for (int i_node = 0;i_node < _routing_links->get_nodes_in_network().size();i_node++) {
VERB_DEBUG_CHATTER("[RoutingPaths %s] Node %d has %d interfaces",now.unparse().c_str(), i_node,
_routing_links->get_nodes_in_network()[i_node].interfaces.size());
}
}
_routes_table_mp = HashTable<MultiPathDemand, Vector<Vector<Route> > >();
_last_seen_routes_mp = HashTable<IPAddress, Vector<Vector<Route> > >();
return 0;
}
int
RoutingPaths::initialize(ErrorHandler *errh) {
Timestamp now;
if (_debug)
now.assign_now();
//srand (time(NULL));
DEBUG_CHATTER("[RoutingPaths %s] Initializing...", now.unparse().c_str());
VERB_DEBUG_CHATTER("[RoutingPaths %s] Setting RoutingLinks", now.unparse().c_str());
if(!_routing_links->set_routing_links(me))
return errh->error("Error while setting RoutingLinks element.");
DEBUG_CHATTER("[RoutingPaths %s] Done!", now.unparse().c_str());
return 0;
}
void
RoutingPaths::push(int port, Packet *p_in) {
Timestamp now;
if (_debug)
now.assign_now();
acne_header *acne_hdr;
if(port > 0) {
acne_hdr = (acne_header *)(p_in->data());
}
click_ip *ip=(click_ip *)(p_in->data() + (port>0)*sizeof(acne_header));
IPAddress src_addr(ip->ip_src.s_addr);
IPAddress dst_addr(ip->ip_dst.s_addr);
DEBUG_CHATTER("[RoutingPaths %s] Packet received from %s to %s on port %d",now.unparse().c_str(),
src_addr.unparse().c_str(), dst_addr.unparse().c_str(), port);
if(_multi_paths == false) {
// single (best) path: act as a router
if(port == 0) {
// comes from host: compute path, add routing header, add next hop mac address
// and forward (output corresponding to the interface)
DEBUG_CHATTER("[RoutingPaths %s] Packet must be source routed. Getting route...",now.unparse().c_str());
Route route = get_route(dst_addr);
if(dst_addr != _default_gw_ip && route.ip == _default_gw_ip) {
if(me.ip == _default_gw_ip) {
output(0).push(p_in);
return;
}
}
if(route.links.empty()) {
DEBUG_CHATTER("[RoutingPaths %s] No route to destination %s!", now.unparse().c_str(), route.ip.unparse().c_str());
p_in->kill();
return;
}
EtherAddress next_hop = route.links[0].dst;
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Adding source routing header...", now.unparse().c_str());
Packet *p_tmp = add_source_routing(p_in, route);
if(p_tmp == 0) {
return;
}
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Adding MAC header...", now.unparse().c_str());
int interface_out = _routing_links->get_interface(next_hop);
Packet *p_out = _routing_links->add_headers(p_tmp, next_hop, interface_out, REGULAR_TRAFFIC);
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Packet goes to output %s.", now.unparse().c_str(),
_routing_links->interface(interface_out).c_str());
output(1 + interface_out).push(p_out);
}
else {
// comes from device
bool is_for_me = false;
for (int i=0;i<me.interfaces.size();i++) {
if(are_last_bytes_in_addr(acne_hdr->_route._dst, me.interfaces[i])) {
is_for_me = true;
break;
}
}
if(is_for_me) {
// is for me: remove source routing header, go to output 0
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Packet is for me: to output 0", now.unparse().c_str());
Packet *p_out = delete_routing_header(p_in);
output(0).push(p_out);
}
else {
// 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)
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Checking the route...", now.unparse().c_str());
EtherAddress next_hop;
Packet *p_temp = update_routing_header(p_in, next_hop);
if(next_hop==_empty_eth) {
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] I'm not in the route: discard packet.", now.unparse().c_str());
p_temp->kill();
return;
}
// packet must be forwarded
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Packet must be forwarded to %s. Adding MAC header...", now.unparse().c_str(), next_hop.unparse().c_str());
int interface_out = _routing_links->get_interface(next_hop);
if(interface_out == -1) {
click_chatter("[RoutingPaths %s] Warning: don't have a forwarding interface for this next_hop.", now.unparse().c_str());
p_temp->kill();
return;
}
Packet *p_out = _routing_links->add_headers(p_temp, next_hop, interface_out, REGULAR_TRAFFIC);
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Packet goes to output %s.", now.unparse().c_str(),
_routing_links->interface(interface_out).c_str());
output(1 + interface_out).push(p_out);
}
}
}
}
void
RoutingPaths::run_timer(Timer *t) {
assert(t == &timer);
if(_warning_n_N) {
click_chatter("[RoutingPaths] WARNING: only n=1 or n=2 and N=1 are supported for now.");
_warning_n_N = false;
}
/*
if(_routing_links->get_and_reset_has_changed()) {
// routing links has changed: recompute paths
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Adjacency matrix needs to be (re)computed. Computing...", now.unparse().c_str());
recompute_adjacency_matrix();
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Adjacency matrix computed!", now.unparse().c_str());
VERB_DEBUG_CHATTER("[RoutingPaths %s] %d virtual nodes", now.unparse().c_str(), adjacency_matrix.size());
HashTable<VirtualNodeRouting, uint32_t> min_distances;
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Computing paths...", now.unparse().c_str());
//dijkstra_compute_paths(VirtualNodeRouting(SRC_VN,me.ip), adjacency_matrix,min_distances, dijkstra_result);
bellmanford_compute_paths(VirtualNodeRouting(SRC_VN,me.ip), adjacency_matrix,min_distances, dijkstra_result);
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Paths computed!", now.unparse().c_str());
_routes_table_mp.clear();
}
*/
if(_print_routes_freq > 0) {
click_chatter(print_routes().c_str());
timer.schedule_after_sec(_print_routes_freq);
}
}
Vector<Route>
RoutingPaths::get_multipath (IPAddress dst, int n) {
Vector<Vector<Route> > multipaths = get_multipaths(dst, 1, n, true, false, false, true);
if(multipaths.empty())
return Vector<Route>();
return multipaths[0];
}
Vector<Route>
RoutingPaths::get_multipath_wifi (IPAddress dst, int n) {
Vector<Vector<Route> > multipaths = get_multipaths(dst, 1, n, true, true, false, true);
if(multipaths.empty())
return Vector<Route>();
return multipaths[0];
}
Vector<Route>
RoutingPaths::get_multipath_plc (IPAddress dst, int n) {
Vector<Vector<Route> > multipaths = get_multipaths(dst, 1, n, true, false, true, true);
if(multipaths.empty())
return Vector<Route>();
return multipaths[0];
}
Vector<Multipath>
RoutingPaths::get_multipaths_mp(IPAddress dst, int N, int n) {
Vector<Vector<Route> > routes = get_multipaths(dst,N,n);
Vector<Multipath> multipaths;
for(int i=0;i<routes.size();i++) {
Multipath multipath;
for(int j=0;j<routes[i].size();j++)
multipath.add_route(routes[i][j]);
multipaths.push_back(multipath);
}
return multipaths;
}
Vector<Vector<Route> >
RoutingPaths::get_multipaths(IPAddress dst, int N, int n) {
return get_multipaths(dst, N, n, true, false, false, true);
}
Vector<Vector<Route> >
RoutingPaths::get_multipaths_wifi(IPAddress dst, int N, int n) {
return get_multipaths(dst, N, n, true, true,false, true);
}
Vector<Vector<Route> >
RoutingPaths::get_multipaths_plc(IPAddress dst, int N, int n) {
return get_multipaths(dst, N, n, true, false, true, true);
}
Route
RoutingPaths::get_best_path_ack(IPAddress src_ip) {
Vector<Vector<Route> > multipaths = get_multipaths(src_ip,1,1,false,false,false,false);
if(multipaths.empty())
return Route();
Vector<Route> routes = multipaths[0];
if(routes.empty())
return Route();
else
return routes[0];
}
Route
RoutingPaths::get_best_path_ack(unsigned char *data) {
//using only the last bytes of an EtherAddress
IPAddress src_ip = _routing_links->get_ip(data);
if(_debug) {
Timestamp now;
now.assign_now();
String data_str = String::make_garbage(4);
if (char *x = data_str.mutable_c_str())
sprintf(x, "%02X%02X",data[0], data[1]);
DEBUG_CHATTER("[RoutingPaths %s] Found destination %s from last bytes %s",now.unparse().c_str(),
src_ip.unparse().c_str(),data_str.c_str());
}
return get_best_path_ack(src_ip);
}
String
RoutingPaths::print_routes() {
Vector<NodeRouting> nodes_in_network = _routing_links->get_nodes_in_network();
StringAccum s;
for(int i=0;i<nodes_in_network.size();i++) {
if (is_in_hash_table(_routes_to_print, nodes_in_network[i].ip)) {
s << "Multipaths to " << nodes_in_network[i].ip.unparse() << " are:\n";
for (int j=0;j<_routes_to_print[nodes_in_network[i].ip].size();j++) {
for(int k=0;k<_routes_to_print[nodes_in_network[i].ip][j].size();k++)
s << " " << _routes_to_print[nodes_in_network[i].ip][j][k].unparse() << ".\n";
s << " ---------------------------------------------------------- \n";
}
}
else
s << "Route to " << nodes_in_network[i].ip.unparse() << " is unknown.\n";
}
return s.take_string();
}
void
RoutingPaths::set_2bp(bool b) {
if(b!=_multirouting_2best_paths) {
_routes_table_mp_wifi.clear();
_routes_table_mp.clear();
_routes_table_mp_plc.clear();
}
_multirouting_2best_paths=b;
}
void
RoutingPaths::reset() {
_routes_table_mp_wifi.clear();
_routes_table_mp.clear();
_routes_table_mp_plc.clear();
_reset = true;
}
void
RoutingPaths::add_forbidden_multipath(Multipath mp) {
if(!is_in_vector(_forbidden_multipaths, mp)) {
_forbidden_multipaths.push_back(mp);
DEBUG_CHATTER("Add %s in forbidden multipath", mp.unparse().c_str());
}
DEBUG_CHATTER("Forbidden multipaths are now:");
for (int i=0;i<_forbidden_multipaths.size();i++) {
DEBUG_CHATTER("\t%s", _forbidden_multipaths[i].unparse().c_str());
}
}
void
RoutingPaths::rm_forbidden_multipath(Multipath mp) {
Vector<Multipath> new_vector;
for(int i=0;i<_forbidden_multipaths.size();i++) {
if(_forbidden_multipaths[i]!=mp)
new_vector.push_back(_forbidden_multipaths[i]);
}
_forbidden_multipaths=new_vector;
DEBUG_CHATTER("Removed %s, forbidden multipaths are now:", mp.unparse().c_str());
for (int i=0;i<_forbidden_multipaths.size();i++) {
DEBUG_CHATTER("\t%s", _forbidden_multipaths[i].unparse().c_str());
}
}
////////////////////////// PRIVATE FUNCTIONS ////////////////////////////////////
Vector<Vector<Route> >
RoutingPaths::get_multipaths (IPAddress dst, int N, int n, bool store_route, bool wifi_only, bool plc_only, bool check_order) {
// N multipaths of n paths
if (n>2) { // right now: n=1 or n=2
_warning_n_N = true;
n=2;
}
Timestamp now;
Timestamp start = Timestamp::now();
if(!_keep_routes && (_routing_links->get_and_reset_has_changed() || _reset)) {
// routing links has changed: recompute paths
_reset = false;
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Adjacency matrix needs to be (re)computed. Computing...", now.unparse().c_str());
_routes_table_mp.clear();
_routes_table_mp_wifi.clear();
_routes_table_mp_plc.clear();
Timestamp now2;
if(_debug)
now.assign_now();
recompute_adjacency_matrix();
if (_debug)
now2.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Adjacency matrix computed in %s seconds!", now2.unparse().c_str(),
(now2-now).unparse().c_str());
VERB_DEBUG_CHATTER("[RoutingPaths %s] %d virtual nodes", now.unparse().c_str(), adjacency_matrix.size());
}
else {
if(wifi_only) {
if(!_test_capa_one_hop && is_in_hash_table(_routes_table_mp_wifi, MultiPathDemand(dst, N, n))) {
check_paths_valid(dst, _routes_table_mp_wifi[MultiPathDemand(dst, N, n)], store_route, check_order);
return _routes_table_mp_wifi[MultiPathDemand(dst, N, n)];
}
}
else if (plc_only) {
if(!_test_capa_one_hop && is_in_hash_table(_routes_table_mp_plc, MultiPathDemand(dst, N, n))) {
check_paths_valid(dst, _routes_table_mp_plc[MultiPathDemand(dst, N, n)], store_route, check_order);
return _routes_table_mp_plc[MultiPathDemand(dst, N, n)];
}
}
else {
if(!_test_capa_one_hop && is_in_hash_table(_routes_table_mp, MultiPathDemand(dst, N, n))) {
check_paths_valid(dst, _routes_table_mp[MultiPathDemand(dst, N, n)], store_route, check_order);
return _routes_table_mp[MultiPathDemand(dst, N, n)];
}
}
}
if (_test_capa_one_hop) {
Vector<Route> best_path_vec;
Route route = get_route(dst);
best_path_vec.push_back(route);
Vector<Vector<Route> > best_mp;
best_mp.push_back(best_path_vec);
check_paths_valid(dst, best_mp, store_route, check_order);
return best_mp;
}
// compute N paths
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Computing %d paths to %s...", now.unparse().c_str(), N, dst.unparse().c_str());
//computes N paths by updating the adjacency matrix
AdjacencyMatrix adj_mat_loc = AdjacencyMatrix(adjacency_matrix);
Route path_loc;
uint32_t C_max_P = 10000;
if(_multirouting_2best_paths) { // only two best path instead of complete routing protocol
if(N>1) {
click_chatter("[RoutingPaths] N>1 not supported with multirouting_2best_paths");
N=1;
}
DEBUG_CHATTER("[RoutingPaths] Getting two best paths...");
Vector<Route> first_k_paths;
// get first n paths
if(wifi_only)
first_k_paths = get_k_shortest_paths(adjacency_matrix_wifi_only, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), n);
else if (plc_only)
first_k_paths = get_k_shortest_paths(adjacency_matrix_plc_only, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), n);
else
first_k_paths = get_k_shortest_paths(adjacency_matrix, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), n);
// set capa to be 1/weight (good order of magnitude)
for(int i=0;i<first_k_paths.size();i++) {
first_k_paths[i].max_capa = SCALE_WEIGHTS/first_k_paths[i].weight;
first_k_paths[i].max_capa_alone = first_k_paths[i].max_capa;
}
Vector<Vector<Route> > multipath = Vector<Vector<Route> >(1,first_k_paths);
if(wifi_only) {
if (!multipath[0].empty() && !multipath[0][0].links.empty())
_routes_table_mp_wifi.set(MultiPathDemand(dst, N, n), multipath);
else
_routes_table_mp_wifi.erase(MultiPathDemand(dst, N, n));
}
else if(plc_only) {
if (!multipath[0].empty() && !multipath[0][0].links.empty())
_routes_table_mp_plc.set(MultiPathDemand(dst, N, n), multipath);
else
_routes_table_mp_plc.erase(MultiPathDemand(dst, N, n));
}
else {
if (!multipath[0].empty() && !multipath[0][0].links.empty())
_routes_table_mp.set(MultiPathDemand(dst, N, n), multipath);
else
_routes_table_mp.erase(MultiPathDemand(dst, N, n));
}
check_paths_valid(dst, multipath, store_route, check_order);
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] We computed %d multipaths!", now.unparse().c_str(), multipath.size());
if(_debug) {
StringAccum s;
s << "[RoutingPaths] Multipaths are \n";
for(int j=0;j<multipath.size();j++) {
for (int i=0;i<multipath[j].size();i++)
s << " " << multipath[j][i].unparse() << " \n";
s << " --------------\n";
}
DEBUG_CHATTER(s.c_str());
}
return multipath;
}
else {
int k;
if(n==1 && N==1)
k = 1;
else
k = _k_value;
Vector<Multipath> sorted_multipaths;
Vector<Route> first_k_paths;
if(wifi_only)
first_k_paths = get_k_shortest_paths(adjacency_matrix_wifi_only, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), k);
else if(plc_only)
first_k_paths = get_k_shortest_paths(adjacency_matrix_plc_only, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), k);
else
first_k_paths = get_k_shortest_paths(adjacency_matrix, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), k);
//uint32_t C_tot_max = 0;
for (int i=0;i<first_k_paths.size();i++) {
path_loc = first_k_paths[i];
if (path_loc != Route()) {
VERB_DEBUG_CHATTER("[RoutingPaths] Updating capacity for path %s", path_loc.unparse().c_str());
if(wifi_only)
adj_mat_loc = update_capacities_adjacency_matrix_multi_paths(adjacency_matrix_wifi_only, path_loc, C_max_P, false);
else if(plc_only)
adj_mat_loc = update_capacities_adjacency_matrix_multi_paths(adjacency_matrix_plc_only, path_loc, C_max_P, false);
else
adj_mat_loc = update_capacities_adjacency_matrix_multi_paths(adjacency_matrix, path_loc, C_max_P, false);
//uint32_t C_first_path = C_max_P;
path_loc.max_capa = C_max_P;
path_loc.max_capa_alone = C_max_P;
Vector<Route> next_k_paths;
if (n>=2)
next_k_paths = get_k_shortest_paths(adj_mat_loc, VirtualNodeRouting(SRC_VN,me.ip), VirtualNodeRouting(DST_VN, dst), k);
if (next_k_paths.size() > 0) {
for (int j=0;j<next_k_paths.size();j++) {
Multipath current_mp;
current_mp.add_route(path_loc);
if (next_k_paths[j] == Route()) {
if(!is_in_vector(_forbidden_multipaths,current_mp))
if(insert_in_sorted_descent_vector(sorted_multipaths, current_mp))
DEBUG_CHATTER("[RoutingPaths] Inserting multipath %s", current_mp.unparse().c_str());
}
else {
VERB_DEBUG_CHATTER("[RoutingPaths] Computing max capacity for path %s", next_k_paths[j].unparse().c_str());
update_capacities_adjacency_matrix_multi_paths(adj_mat_loc, next_k_paths[j], C_max_P, true);
//if(C_max_P > path_loc.max_capa/20) { // add only path if capa greater than 5% of first path
next_k_paths[j].max_capa = C_max_P; // capacity with other route
update_capacities_adjacency_matrix_multi_paths(adjacency_matrix, next_k_paths[j], C_max_P, true);
next_k_paths[j].max_capa_alone = C_max_P; // capacity alone
current_mp.add_route(next_k_paths[j]);
//}
if(!is_in_vector(_forbidden_multipaths,current_mp))
if (insert_in_sorted_descent_vector(sorted_multipaths, current_mp))
DEBUG_CHATTER("[RoutingPaths] Inserting multipath %s", current_mp.unparse().c_str());
}
}
}
else {
Multipath current_mp;
current_mp.add_route(path_loc);
if(!is_in_vector(_forbidden_multipaths,current_mp))
if (insert_in_sorted_descent_vector(sorted_multipaths, current_mp))
DEBUG_CHATTER("[RoutingPaths] Inserting multipath %s", current_mp.unparse().c_str());
}
}
}
DEBUG_CHATTER("[RoutingPaths] Computed %d multipaths", sorted_multipaths.size());
Vector<Vector<Route> > best_multipaths;
for(int i=0;i<mymin(N, sorted_multipaths.size()); i++)
best_multipaths.push_back(sorted_multipaths[i]._routes);
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] We computed %d multipaths in %s seconds!", now.unparse().c_str(), best_multipaths.size(), (now - start).unparse().c_str());
if(_debug) {
StringAccum s;
s << "[RoutingPaths] Multipaths are \n";
for(int j=0;j<best_multipaths.size();j++) {
for (int i=0;i<best_multipaths[j].size();i++)
s << " " << best_multipaths[j][i].unparse() << " \n";
s << " --------------\n";
}
DEBUG_CHATTER(s.c_str());
}
if(wifi_only) {
if (!best_multipaths.empty() && !best_multipaths[0].empty() && !best_multipaths[0][0].links.empty())
_routes_table_mp_wifi.set(MultiPathDemand(dst, N, n), best_multipaths);
else
_routes_table_mp_wifi.erase(MultiPathDemand(dst, N, n));
}
else if(plc_only) {
if (!best_multipaths.empty() && !best_multipaths[0].empty() && !best_multipaths[0][0].links.empty())
_routes_table_mp_plc.set(MultiPathDemand(dst, N, n), best_multipaths);
else
_routes_table_mp_plc.erase(MultiPathDemand(dst, N, n));
}
else {
if (!best_multipaths.empty() && !best_multipaths[0].empty() && !best_multipaths[0][0].links.empty())
_routes_table_mp.set(MultiPathDemand(dst, N, n), best_multipaths);
else
_routes_table_mp.erase(MultiPathDemand(dst, N, n));
}
check_paths_valid(dst, best_multipaths, store_route, check_order);
return best_multipaths;
}
}
AdjacencyMatrix
RoutingPaths::update_capacities_adjacency_matrix_multi_paths(const AdjacencyMatrix mat, Route &path, uint32_t &max_achievable_capa, bool only_max_capa) {
uint32_t max_sum_weights = 0;
int tot_nb_links_contending = 0;
for(int i=0;i<path.links.size();i++) {
LinkRouting link = path.links[i];
uint32_t sum_weights = 0;
int nb_links_contending = 0;
for (int j=0;j<path.links.size();j++) {
if (i==j || _routing_links->are_contending(UndirectedLinkRouting(link), UndirectedLinkRouting(path.links[j]))) {
nb_links_contending++;
VirtualNodeRouting virtual_egress = VirtualNodeRouting(EGR_VN, path.links[j].src);
VirtualNeighbor virtual_neighbor = VirtualNeighbor(VirtualNodeRouting(ING_VN, path.links[j].dst),0);
int ind;
if(!is_in_hash_table(mat, virtual_egress) || (ind = find_in_vector(mat[virtual_egress], virtual_neighbor)) == -1)
sum_weights+=DEFAULT_WEIGHT;
else
sum_weights+=mat[virtual_egress][ind].weight;
}
}
if (sum_weights > max_sum_weights) {
max_sum_weights = sum_weights;
tot_nb_links_contending = nb_links_contending;
}
VirtualNodeRouting virtual_egress = VirtualNodeRouting(EGR_VN, path.links[i].src);
VirtualNeighbor virtual_neighbor = VirtualNeighbor(VirtualNodeRouting(ING_VN, path.links[i].dst),0);
int ind;
if(!is_in_hash_table(mat, virtual_egress) || (ind = find_in_vector(mat[virtual_egress], virtual_neighbor)) == -1)
path.links[i].weight == DEFAULT_WEIGHT;
else
path.links[i].weight = mat[virtual_egress][ind].weight;
}
if(max_sum_weights > 0)
max_achievable_capa = int_divide(SCALE_WEIGHTS, max_sum_weights);
else {
max_achievable_capa = 0;
tot_nb_links_contending = 1;
}
VERB_DEBUG_CHATTER("Max achievable capacity is %d (%d links contending)", max_achievable_capa, tot_nb_links_contending);
AdjacencyMatrix new_matrix = AdjacencyMatrix(mat);
if (!only_max_capa) {
for(int i=0;i<path.links.size();i++) {
Vector<UndirectedLinkRouting> contending_links = _routing_links->get_contending_links(path.links[i]);
contending_links.push_back(UndirectedLinkRouting(path.links[i].src, path.links[i].dst));
VERB_DEBUG_CHATTER("Links contending with %s are %s", path.links[i].unparse().c_str(), print_vector(contending_links).c_str());
for (int j=0;j<contending_links.size();j++) {
UndirectedLinkRouting cont_link = contending_links[j];
VirtualNodeRouting virt_src = VirtualNodeRouting(EGR_VN, cont_link.src);
VirtualNodeRouting virt_dst = VirtualNodeRouting(ING_VN, cont_link.dst);
int ind = find_in_vector(mat[virt_src], VirtualNeighbor(virt_dst,0));
if (ind == -1) {
virt_src = VirtualNodeRouting(EGR_VN, cont_link.dst);
virt_dst = VirtualNodeRouting(ING_VN, cont_link.src);
ind = find_in_vector(mat[virt_src], VirtualNeighbor(virt_dst,0));
}
VirtualNodeRouting virt_src_ing = VirtualNodeRouting(ING_VN, virt_src.eth);
int ind_src_ing_egr = find_in_vector(mat[virt_src_ing], VirtualNeighbor(virt_src,0));
if (ind != -1) {
if (mat[virt_src][ind].weight == new_matrix[virt_src][ind].weight) {
// link not modified yet
bool update_csc = false;
if(ind_src_ing_egr!=-1 && mat[virt_src][ind].weight == mat[virt_src_ing][ind_src_ing_egr].weight)
// must update CSC as well
update_csc = true;
int remaining_time = 1000;
for (int k=0;k<path.links.size();k++) {
if(_routing_links->are_contending(cont_link, path.links[k])) {
VirtualNodeRouting virt_src_path = VirtualNodeRouting(EGR_VN, path.links[k].src);
int ind_link_path = find_in_vector(mat[virt_src_path], VirtualNeighbor(VirtualNodeRouting(ING_VN, path.links[k].dst),0));
uint32_t capa_link;
if(mat[virt_src_path][ind_link_path].weight > 0)
capa_link = int_divide(SCALE_WEIGHTS, mat[virt_src_path][ind_link_path].weight);
else
capa_link = 0;
if(capa_link > 0)
remaining_time -= int_divide(1000*max_achievable_capa, capa_link);
else
remaining_time = 0;
VERB_DEBUG_CHATTER("[RoutingPaths] Link %s is contending with %s (capa %d): remaining_time = %d", cont_link.unparse().c_str(),
path.links[k].unparse().c_str(), capa_link, remaining_time);
if (remaining_time <= 0) {
remaining_time = 0;
break;
}
}
}
if (mat[virt_src][ind].weight >= remaining_time*int_divide(DEFAULT_WEIGHT, 1000)) {
new_matrix[virt_src][ind].weight = DEFAULT_WEIGHT;
}
else {
uint64_t weight64 = (uint64_t) mat[virt_src][ind].weight;
new_matrix[virt_src][ind].weight = (uint32_t) int_divide(weight64*1000, remaining_time);
if(update_csc && (new_matrix[virt_src_ing][ind_src_ing_egr].weight == mat[virt_src_ing][ind_src_ing_egr].weight ||
new_matrix[virt_src][ind].weight < new_matrix[virt_src_ing][ind_src_ing_egr].weight)) {
VERB_DEBUG_CHATTER("[RoutingPaths] Update CSC for %s->%s, was %s, is %s", virt_src_ing.unparse().c_str(),
new_matrix[virt_src_ing][ind_src_ing_egr].neighbor.unparse().c_str(),
String(new_matrix[virt_src_ing][ind_src_ing_egr].weight).c_str(),
String(new_matrix[virt_src][ind].weight).c_str());
new_matrix[virt_src_ing][ind_src_ing_egr].weight = new_matrix[virt_src][ind].weight;
}
}
update_csc = false;
VERB_DEBUG_CHATTER("[RoutingPaths] New weight for link %s (was %d, remaining time %d): %d", cont_link.unparse().c_str(), mat[virt_src][ind].weight,
remaining_time, new_matrix[virt_src][ind].weight);
EtherAddress src_eth = virt_src.eth;
virt_src = VirtualNodeRouting(EGR_VN, virt_dst.eth);
virt_dst = VirtualNodeRouting(ING_VN, src_eth);
virt_src_ing = VirtualNodeRouting(ING_VN, virt_src.eth);
ind_src_ing_egr = find_in_vector(mat[virt_src_ing], VirtualNeighbor(virt_src,0));
ind = find_in_vector(mat[virt_src], VirtualNeighbor(virt_dst,0));
if(ind != -1) {
if(ind_src_ing_egr!=-1 && mat[virt_src][ind].weight == mat[virt_src_ing][ind_src_ing_egr].weight)
// must update CSC as well
update_csc = true;
if (mat[virt_src][ind].weight >= remaining_time*int_divide(DEFAULT_WEIGHT, 1000))
new_matrix[virt_src][ind].weight = DEFAULT_WEIGHT;
else {
uint64_t weight64 = (uint64_t) mat[virt_src][ind].weight;
new_matrix[virt_src][ind].weight = (uint32_t) int_divide(weight64*1000, remaining_time);
if(update_csc && (new_matrix[virt_src_ing][ind_src_ing_egr].weight == mat[virt_src_ing][ind_src_ing_egr].weight ||
new_matrix[virt_src][ind].weight < new_matrix[virt_src_ing][ind_src_ing_egr].weight)) {
VERB_DEBUG_CHATTER("[RoutingPaths] Update CSC for %s->%s, was %s, is %s", virt_src_ing.unparse().c_str(),
new_matrix[virt_src_ing][ind_src_ing_egr].neighbor.unparse().c_str(),
String(new_matrix[virt_src_ing][ind_src_ing_egr].weight).c_str(),
String(new_matrix[virt_src][ind].weight).c_str());
new_matrix[virt_src_ing][ind_src_ing_egr].weight = new_matrix[virt_src][ind].weight;
}
}
VERB_DEBUG_CHATTER("[RoutingPaths] New weight for anti-link %s (was %d, remaining time %d): %d", cont_link.unparse().c_str(), mat[virt_src][ind].weight,
remaining_time, new_matrix[virt_src][ind].weight);
}
}
}
else
VERB_DEBUG_CHATTER("[RoutingPaths] Link %s->%s not found in adjacency matrix",
virt_src.eth.unparse().c_str(), virt_dst.eth.unparse().c_str());
}
}
}
// add a penalty of 10% for each link contending (non-perfect MAC)
max_achievable_capa -= ((tot_nb_links_contending-1)*max_achievable_capa)/10;
return new_matrix;
}
bool
RoutingPaths::are_neighbors(EtherAddress node1, EtherAddress node2) const {
return (is_in_vector(_routing_links->get_neighbor_links()[node1], RealNeighbor(node2)));
}
bool RoutingPaths::are_neighbors(LinkRouting link1, LinkRouting link2) const {
return are_neighbors(link1.src, link2.src) || are_neighbors(link1.src, link2.dst) ||
are_neighbors(link1.dst, link2.src) || are_neighbors(link1.dst, link2.dst);
}
Route
RoutingPaths::get_route(IPAddress dst) {
Timestamp now;
if (dst == me.ip)
return Route();
Route route = get_route_no_gw(dst);
if(_test_capa_one_hop)
return route;
if(route.links.empty()) {
if(_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] No route to %s, packet sent to default gateway", now.unparse().c_str(), dst.unparse().c_str());
if (_default_gw_ip == me.ip)
return Route();
if (is_in_hash_table(_routes_table_mp,MultiPathDemand(_default_gw_ip, 1, 1) ) && !_routes_table_mp[MultiPathDemand(_default_gw_ip, 1, 1)].empty() &&
!_routes_table_mp[MultiPathDemand(_default_gw_ip, 1, 1)][0].empty()) {
route = _routes_table_mp[MultiPathDemand(_default_gw_ip, 1, 1)][0][0];
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Got path to gateway! Path is %s", now.unparse().c_str(), route.unparse().c_str());
return route;
}
else {
VirtualRoute virtual_route = compute_shortest_path_to
(VirtualNodeRouting(DST_VN, _default_gw_ip),adjacency_matrix, dijkstra_result);
DEBUG_CHATTER("[RoutingPaths %s] Got virtual path to gateway! Virtual path is %s. Getting real path...", now.unparse().c_str(), virtual_route.unparse().c_str());
route = virtual_route_to_route(virtual_route);
route.ip = _default_gw_ip;
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Got real path! Path is %s", now.unparse().c_str(), route.unparse().c_str());
if (!route.links.empty()) {
uint32_t C_max_P;
update_capacities_adjacency_matrix_multi_paths(adjacency_matrix, route, C_max_P, true);
route.max_capa = C_max_P;
_routes_table_mp.set(MultiPathDemand(route.ip, 1, 1), Vector<Vector<Route> >(1,Vector<Route>(1,route)));
}
else
_routes_table_mp.erase(MultiPathDemand(route.ip, 1, 1));
}
}
return route;
}
Route
RoutingPaths::get_route_no_gw(IPAddress dst) {
Timestamp now;
if (_debug)
now.assign_now();
if(is_in_hash_table(_routes_table_mp, MultiPathDemand(dst, 1, 1)) && !_routes_table_mp[MultiPathDemand(dst, 1, 1)].empty() &&
!_routes_table_mp[MultiPathDemand(dst, 1, 1)][0].empty()) {
if (_debug)
now.assign_now();
Route route = _routes_table_mp[MultiPathDemand(dst, 1, 1)][0][0];
DEBUG_CHATTER("[RoutingPaths %s] Got real path! Path is %s", now.unparse().c_str(), route.unparse().c_str());
return route;
}
if (_test_capa_one_hop) {
Vector<NodeRouting> nodes = _routing_links->get_nodes_in_network();
DEBUG_CHATTER("Searching one-hop route...");
int ind_node = find_in_vector(nodes, NodeRouting(dst));
if (ind_node == -1) {
DEBUG_CHATTER("Destination node unknown");
return Route();
}
else {
NodeRouting node_dst = nodes[ind_node];
for (int i=0;i<node_dst.interfaces.size();i++) {
EtherAddress my_eth;
EtherAddress eth_dst = node_dst.interfaces[i];
if(_test_capa_one_hop_wifi)
if (me.unique_interface == INTERFACE1)
my_eth = me.interfaces[0];
else
my_eth = me.interfaces[INTERFACE1];
else
my_eth = me.interfaces[INTERFACE2];
int ind_neighbor = find_in_vector(_routing_links->get_neighbor_links()[my_eth], RealNeighbor(eth_dst));
if(ind_neighbor >= 0) {
RealNeighbor neighbor = _routing_links->get_neighbor_links()[my_eth][ind_neighbor];
Route route;
LinkRouting link = LinkRouting(my_eth, eth_dst, neighbor.weight);
route.links.push_back(link);
route.weight = neighbor.weight;
route.ip = dst;
DEBUG_CHATTER("Found route %s", route.unparse().c_str());
if (!route.links.empty()) {
uint32_t C_max_P;
update_capacities_adjacency_matrix_multi_paths(adjacency_matrix, route, C_max_P, true);
route.max_capa = C_max_P;
_routes_table_mp.set(MultiPathDemand(route.ip, 1, 1), Vector<Vector<Route> >(1,Vector<Route>(1,route)));
}
else
_routes_table_mp.erase(MultiPathDemand(route.ip, 1, 1));
return route;
}
}
DEBUG_CHATTER("Node is not a neighbor");
return Route();
}
}
DEBUG_CHATTER("[RoutingPaths %s] Getting path to destination %s...", now.unparse().c_str(), dst.unparse().c_str());
VirtualRoute virtual_route = compute_shortest_path_to
(VirtualNodeRouting(DST_VN, dst),adjacency_matrix, dijkstra_result);
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Got virtual path! Virtual path is %s. Getting real path...", now.unparse().c_str(), virtual_route.unparse().c_str());
Route route = virtual_route_to_route(virtual_route);
route.ip = dst;
if (_debug)
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Got real path! Path is %s", now.unparse().c_str(), route.unparse().c_str());
if (!route.links.empty()) {
uint32_t C_max_P;
update_capacities_adjacency_matrix_multi_paths(adjacency_matrix, route, C_max_P, true);
route.max_capa = C_max_P;
_routes_table_mp.set(MultiPathDemand(route.ip, 1, 1), Vector<Vector<Route> >(1,Vector<Route>(1,route)));
}
else
_routes_table_mp.erase(MultiPathDemand(route.ip, 1, 1));
return route;
}
Packet *
RoutingPaths::add_source_routing(Packet * p_in, Route source_route) {
Timestamp now;
if(source_route.links.size() > HDR_ROUTE_SIZE) {
click_chatter("[RoutingPaths %s] Route is too long", now.unparse().c_str());
return 0;
}
// the source and destination addresses are not included
// as hops in the source route
// add the extra header size and get a new packet
WritablePacket *p = p_in->push(sizeof(acne_header));
if (!p) {
if (_debug)
now.assign_now();
click_chatter("[RoutingPaths %s] Couldn't add space for acne header\n", now.unparse().c_str());
return p;
}
// add the fixed header
acne_header *hdr = (acne_header *)(p->data());
int last = source_route.links.size() - 1;
hdr->_type = REGULAR_TRAFFIC; // regular IP traffic
hdr->_hop = 0;
for (int b=0;b<NB_BYTES_HOP;b++) {
hdr->_route._dst[b] = source_route.links[last].dst.data()[6-NB_BYTES_HOP+b];
}
for (int i=0; i<source_route.links.size(); i++) {
unsigned char *data = source_route.links[i].dst.data();
for (int b=0;b<NB_BYTES_HOP;b++) {
hdr->_route._route[NB_BYTES_HOP*i+b] = data[6-NB_BYTES_HOP+b];
}
}
return p;
}
Packet *
RoutingPaths::update_routing_header(Packet *p_in, EtherAddress& next_hop) {
acne_header *hdr = (acne_header *)(p_in->data());
bool is_me = false;
for (int i=0;i<me.interfaces.size();i++) {
unsigned char *first_byte_this_hop = &hdr->_route._route[NB_BYTES_HOP*hdr->_hop];
if(are_last_bytes_in_addr(first_byte_this_hop, me.interfaces[i])) {
is_me = true;
break;
}
}
if (is_me) {
hdr->_hop++;
next_hop = get_eth_address_source_routing(hdr->_route._route, hdr->_hop);
}
else {
// I'm not in the route
next_hop = _empty_eth;
}
return p_in;
}
Packet *
RoutingPaths::delete_routing_header(Packet *p_in) {
p_in->pull(sizeof(acne_header));
click_ip *ip=(click_ip *)(p_in->data());
p_in->set_ip_header(ip, sizeof(click_ip));
return p_in;
}
EtherAddress
RoutingPaths::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 _routing_links->get_ether_address(data);
}
Route
RoutingPaths::virtual_route_to_route(VirtualRoute virtual_route) {
Route route;
if (virtual_route.weight >= DEFAULT_WEIGHT)
return Route();
for(int i=0;i<virtual_route.route.size();i++) {
if (virtual_route.route[i].neighbor.type == EGR_VN) {
uint32_t weight = virtual_route.route[i+1].weight;
// check if one interface of next node is already in the route (loop in the real graph)
int ind_next_node_in_route = -1;
NodeRouting next_node = _routing_links->get_node_from_eth(virtual_route.route[i+1].neighbor.eth);
for (int j=0;j<next_node.interfaces.size();j++) {
int ind = route.is_in_route_src(next_node.interfaces[j]);
if (ind != -1) {
ind_next_node_in_route = ind;
break; // can appear only once
}
}
if(ind_next_node_in_route == -1)
route.links.push_back(LinkRouting(virtual_route.route[i].neighbor.eth, virtual_route.route[i+1].neighbor.eth, weight));
else // loop in real graph
route.links.erase(&route.links[ind_next_node_in_route], route.links.end());
}
}
route.weight = virtual_route.weight;
return route;
}
void
RoutingPaths::recompute_adjacency_matrix() {
// Note: recompute_adjacency_metric is very time-consuming, should be used rarely!
Timestamp now;
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Computing adjacency matrix...", now.unparse().c_str());
VERB_DEBUG_CHATTER("[RoutingPaths %s] Clearing adjacency matrix...", now.unparse().c_str());
adjacency_matrix.clear();
adjacency_matrix_wifi_only.clear();
adjacency_matrix_plc_only.clear();
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Adjacency matrix cleared!", now.unparse().c_str());
Vector<NodeRouting> nodes = _routing_links->get_nodes_in_network();
VERB_DEBUG_CHATTER("[RoutingPaths %s] %d nodes to transform", now.unparse().c_str(), nodes.size());
// add virtual nodes and corresponding links for all node in the network
for (int i_node = 0;i_node < nodes.size();i_node++) {
VERB_DEBUG_CHATTER("[RoutingPaths %s] Node %d has %d interfaces", now.unparse().c_str(), i_node,
nodes[i_node].interfaces.size());
NodeRouting this_node = nodes[i_node];
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Transforming node %d, with %d interfaces...", now.unparse().c_str(), i_node, this_node.interfaces.size());
// add virtual nodes X+ (with links to in-node egresses) and X- (links to in-node ingresses)
IPAddress addr_node;
addr_node = this_node.ip;
Vector<VirtualNeighbor> virtual_neighbors_plus;
Vector<VirtualNeighbor> virtual_neighbors_plus_wifi;
Vector<VirtualNeighbor> virtual_neighbors_plus_plc;
uint32_t min_weight = DEFAULT_WEIGHT;
// add ingress and egress node for each interface
for (int i=0;i < this_node.interfaces.size();i++) {
VERB_DEBUG_CHATTER("[RoutingPaths %s] Transforming interface %d of %d...", now.unparse().c_str(), i, this_node.interfaces.size());
EtherAddress addr_interface = this_node.interfaces[i];
Vector<RealNeighbor> neighbors = _routing_links->get_neighbor_links().get(addr_interface);
VirtualNodeRouting egr_node = VirtualNodeRouting(EGR_VN, addr_interface);
Vector<VirtualNeighbor> virtual_neighbors_egr;
// neighbors represents the real neighbors: add the corresponding virtual neighbors (egress->ingress)
for(int j=0;j < neighbors.size();j++) {
virtual_neighbors_egr.push_back(VirtualNeighbor(
VirtualNodeRouting(ING_VN, neighbors[j].neighbor), neighbors[j].weight));
if(neighbors[j].weight < min_weight)
min_weight = neighbors[j].weight;
}
adjacency_matrix.set(egr_node, virtual_neighbors_egr);
if(is_wifi_addr(addr_interface))
adjacency_matrix_wifi_only.set(egr_node, virtual_neighbors_egr);
if(is_plc_addr(addr_interface))
adjacency_matrix_plc_only.set(egr_node, virtual_neighbors_egr);
}
for (int i=0;i < this_node.interfaces.size();i++) {
EtherAddress addr_interface = this_node.interfaces[i];
VirtualNodeRouting ingr_node = VirtualNodeRouting(ING_VN, addr_interface);
Vector<VirtualNeighbor> virtual_neighbors_ingr;
Vector<VirtualNeighbor> virtual_neighbors_ingr_wifi;
Vector<VirtualNeighbor> virtual_neighbors_ingr_plc;
// add the in-node ingress->egress links
for (int j=0;j<this_node.interfaces.size();j++) {
EtherAddress addr_interface2 = this_node.interfaces[j];
uint32_t CSC = 0;
// if same interface, CSC is min_weight
if(i==j && _csc_choice.compare("no") != 0)
CSC = min_weight;
virtual_neighbors_ingr.push_back(VirtualNeighbor(VirtualNodeRouting(EGR_VN, addr_interface2), CSC));
if(is_wifi_addr(addr_interface2))
virtual_neighbors_ingr_wifi.push_back(VirtualNeighbor(VirtualNodeRouting(EGR_VN, addr_interface2), 0));
if(is_plc_addr(addr_interface2))
virtual_neighbors_ingr_plc.push_back(VirtualNeighbor(VirtualNodeRouting(EGR_VN, addr_interface2), 0));
}
// X+->egress, ingress->X-
virtual_neighbors_plus.push_back(VirtualNeighbor(VirtualNodeRouting(EGR_VN, addr_interface), 0));
virtual_neighbors_ingr.push_back(VirtualNeighbor(VirtualNodeRouting(DST_VN, addr_node), 0));
adjacency_matrix.set(ingr_node, virtual_neighbors_ingr);
if(is_wifi_addr(addr_interface)) {
virtual_neighbors_plus_wifi.push_back(VirtualNeighbor(VirtualNodeRouting(EGR_VN, addr_interface), 0));
virtual_neighbors_ingr_wifi.push_back(VirtualNeighbor(VirtualNodeRouting(DST_VN, addr_node), 0));
adjacency_matrix_wifi_only.set(ingr_node, virtual_neighbors_ingr_wifi);
}
if(is_plc_addr(addr_interface)) {
virtual_neighbors_plus_plc.push_back(VirtualNeighbor(VirtualNodeRouting(EGR_VN, addr_interface), 0));
virtual_neighbors_ingr_plc.push_back(VirtualNeighbor(VirtualNodeRouting(DST_VN, addr_node), 0));
adjacency_matrix_plc_only.set(ingr_node, virtual_neighbors_ingr_plc);
}
}
adjacency_matrix.set(VirtualNodeRouting(SRC_VN, addr_node), virtual_neighbors_plus);
adjacency_matrix.set(VirtualNodeRouting(DST_VN, addr_node), Vector<VirtualNeighbor>());
adjacency_matrix_wifi_only.set(VirtualNodeRouting(SRC_VN, addr_node), virtual_neighbors_plus_wifi);
adjacency_matrix_wifi_only.set(VirtualNodeRouting(DST_VN, addr_node), Vector<VirtualNeighbor>());
adjacency_matrix_plc_only.set(VirtualNodeRouting(SRC_VN, addr_node), virtual_neighbors_plus_plc);
adjacency_matrix_plc_only.set(VirtualNodeRouting(DST_VN, addr_node), Vector<VirtualNeighbor>());
if (_debug)
now.assign_now();
VERB_DEBUG_CHATTER("[RoutingPaths %s] Node transformed!", now.unparse().c_str());
}
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Adjacency matrix computed.", now.unparse().c_str());
}
void
RoutingPaths::dijkstra_compute_paths(VirtualNodeRouting source,
const AdjacencyMatrix adjacency_mat,
HashTable<VirtualNodeRouting,uint32_t> &min_distance,
HashTable<VirtualNodeRouting, VirtualNodeRouting> &previous)
{
min_distance.clear();
previous.clear();
for(AdjacencyMatrix::const_iterator it=adjacency_mat.begin();
it != adjacency_mat.end();it++) {
min_distance.set(it->first, DEFAULT_WEIGHT);
previous.set(it->first, VirtualNodeRouting());
}
min_distance.set(source,0);
SetNeighbor vertex_queue;
vertex_queue.insert_neighbor(VirtualNeighbor(source, min_distance[source]));
while (!vertex_queue.empty())
{
uint32_t dist = vertex_queue.begin().weight;
VirtualNodeRouting u = vertex_queue.begin().neighbor;
vertex_queue.erase_neighbor(vertex_queue.begin());
// Visit each edge exiting u
const Vector<VirtualNeighbor> neighbors = adjacency_mat[u];
for(int i=0; i < neighbors.size();i++) {
VirtualNodeRouting v = neighbors[i].neighbor;
uint32_t weight = neighbors[i].weight;
uint32_t distance_through_u = dist + weight;
if (distance_through_u < min_distance[v]) {
vertex_queue.erase_neighbor(VirtualNeighbor(v,min_distance[v]));
min_distance.set(v,distance_through_u);
previous.set(v,u);
vertex_queue.insert_neighbor(VirtualNeighbor(v,min_distance[v]));
}
}
}
}
void
RoutingPaths::bellmanford_compute_paths(VirtualNodeRouting source,
const AdjacencyMatrix adjacency_mat,
HashTable<VirtualNodeRouting,uint32_t> &min_distance,
HashTable<VirtualNodeRouting, VirtualNodeRouting> &previous)
{
min_distance.clear();
previous.clear();
for(AdjacencyMatrix::const_iterator it=adjacency_mat.begin();
it != adjacency_mat.end();it++) {
min_distance.set(it->first, DEFAULT_WEIGHT);
previous.set(it->first, VirtualNodeRouting());
}
min_distance.set(source,0);
bool weights_changed = true;
while (weights_changed) { // converge after at most (nb_nodes - 1) steps
weights_changed = false;
for(AdjacencyMatrix::const_iterator it=adjacency_mat.begin();
it != adjacency_mat.end();it++) {
VirtualNodeRouting u = it->first;
uint32_t dist = min_distance[u];
// Visit each edge exiting u
const Vector<VirtualNeighbor> neighbors = adjacency_mat[u];
for(int i=0; i < neighbors.size();i++) {
VirtualNodeRouting v = neighbors[i].neighbor;
uint32_t weight = neighbors[i].weight;
uint32_t distance_through_u = dist + weight;
if (distance_through_u < min_distance[v]) {
min_distance.set(v,distance_through_u);
previous.set(v,u);
weights_changed = true;
}
}
}
}
if (_debug) { // check
for(AdjacencyMatrix::const_iterator it=adjacency_mat.begin();
it != adjacency_mat.end();it++) {
VirtualNodeRouting u = it.key();
uint32_t dist = min_distance[u];
// Visit each edge exiting u
const Vector<VirtualNeighbor> neighbors = adjacency_mat[u];
for(int i=0; i < neighbors.size();i++) {
VirtualNodeRouting v = neighbors[i].neighbor;
uint32_t weight = neighbors[i].weight;
uint32_t distance_through_u = dist + weight;
if (distance_through_u < min_distance[v])
DEBUG_CHATTER("Error, negative weight cycle for %s and %s", u.unparse().c_str(), v.unparse().c_str());
}
}
}
}
VirtualRoute
RoutingPaths::compute_shortest_path_to(VirtualNodeRouting dst,
const AdjacencyMatrix adjacency_mat,
const HashTable<VirtualNodeRouting,VirtualNodeRouting> previous)
{
Timestamp now;
if (_debug)
now.assign_now();
VirtualRoute path;
VirtualNodeRouting null = VirtualNodeRouting();
int count_loop = 0;
while(dst != null) {
path.route.push_front(VirtualNeighbor(dst, 0));
if(path.route.size() > 1) {
int ind = find_in_vector(adjacency_mat[dst], path.route[1]);
if (ind >= 0) {
uint32_t weight = adjacency_mat[dst][ind].weight;
path.route[1].weight = weight;
path.weight += weight;
//VERB_DEBUG_CHATTER("[RoutingPaths %s] Virtual link %s added", now.unparse().c_str(), path.route[1].unparse().c_str() );
}
else { //should not happen
click_chatter("Warning, virtual node not in network");
return VirtualRoute();
}
}
dst = previous[dst];
count_loop++;
if(count_loop > 20)
break;
}
return path;
}
VirtualRoute
RoutingPaths::get_shortest_path_dij(const AdjacencyMatrix adj_mat, const VirtualNodeRouting src, const VirtualNodeRouting dst)
{
HashTable<VirtualNodeRouting,VirtualNodeRouting> dijkstra_result_loc;
HashTable<VirtualNodeRouting, uint32_t> min_distances;
dijkstra_compute_paths(src, adj_mat,min_distances, dijkstra_result_loc);
VirtualRoute virtual_path = compute_shortest_path_to(dst,adj_mat,dijkstra_result_loc);
return virtual_path;
}
VirtualRoute
RoutingPaths::get_shortest_path_bf(const AdjacencyMatrix adj_mat, const VirtualNodeRouting src, const VirtualNodeRouting dst)
{
HashTable<VirtualNodeRouting,VirtualNodeRouting> bf_result_loc;
HashTable<VirtualNodeRouting, uint32_t> min_distances;
bellmanford_compute_paths(src, adj_mat,min_distances, bf_result_loc);
VirtualRoute virtual_path = compute_shortest_path_to(dst,adj_mat,bf_result_loc);
return virtual_path;
}
Vector<Route>
RoutingPaths::get_k_shortest_paths(const AdjacencyMatrix adj_mat, const VirtualNodeRouting src, const VirtualNodeRouting dst, int K, VirtualRoute& virtual_best_path)
{
// Yen's algorithm for finding k-shortest paths (pseudo-code from Wikipedia)
//
// function YenKSP(Graph, source, sink, K):
// // Determine the shortest path from the source to the sink.
// A[0] = Dijkstra(Graph, source, sink);
// // Initialize the heap to store the potential kth shortest path.
// B = [];
// for k from 1 to K:
// // The spur node ranges from the first node to the next to last node in the shortest path.
// for i from 0 to size(A[k − 1]) − 1:
// // Spur node is retrieved from the previous k-shortest path, k − 1.
// spurNode = A[k-1].node(i);
// // The sequence of nodes from the source to the spur node of the previous k-shortest path.
// rootPath = A[k-1].nodes(0, i);
// for each path p in A:
// if rootPath == p.nodes(0, i):
// // Remove the links that are part of the previous shortest paths which share the same root path.
// remove p.edge(i, i + 1) from Graph;
// // Calculate the spur path from the spur node to the sink.
// spurPath = Dijkstra(Graph, spurNode, sink);
// // Entire path is made up of the root path and spur path.
// totalPath = rootPath + spurPath;
// // Add the potential k-shortest path to the heap.
// B.append(totalPath);
// // Add back the edges that were removed from the graph.
// restore edges to Graph;
// // Sort the potential k-shortest paths by cost.
// B.sort();
// // Add the lowest cost path becomes the k-shortest path.
// A[k] = B[0];
// B.pop();
// return A;
Timestamp now;
if (_debug)
now.assign_now();
// src should be SRC_VN, dst DST_VN
Vector<Route> k_shortest_paths; // corresponds to A
if (src.type == SRC_VN && dst.type == DST_VN) {
Vector<VirtualRoute> k_shortest_virt_paths; // corresponds to A (virtual)
VirtualRoute first_virt_path = get_shortest_path_dij(adj_mat, src, dst);
Route first_path = virtual_route_to_route(first_virt_path);
first_path.ip = dst.ip;
virtual_best_path = first_virt_path;
if (first_path == Route()) {
return Vector<Route>(1,Route());
}
k_shortest_paths.push_back(first_path);
k_shortest_virt_paths.push_back(first_virt_path);
VERB_DEBUG_CHATTER("Path %s found, k=1", first_path.unparse().c_str());
Vector<VirtualRoute> potential_virt_paths; // corresponds to B (virtual)
Vector<Route> potential_real_paths;
Vector<uint32_t> weights_potential_paths;
AdjacencyMatrix adj_mat_loc = adj_mat;
int k=1;
while(k<K) {
VirtualRoute last_path = k_shortest_virt_paths.back();
VirtualRoute rootPath;
for (int i=0;i < (last_path.route.size() - 2);i++) { //do not consider last link in virtual path (-> DST_VN)
VirtualNodeRouting spurNode = last_path.route[i].neighbor;
VERB_DEBUG_CHATTER("[RoutingPaths] Spur node is %s, root path is %s", spurNode.unparse().c_str(), rootPath.unparse().c_str());
for (int p=0;p<k_shortest_virt_paths.size();p++) {
bool remove;
// test if rootPath == p.nodes(0, i)
if (k_shortest_virt_paths[p].route.size() > i) {
remove = true;
for (int j=0;j<=i;j++) {
if (last_path.route[j]!=k_shortest_virt_paths[p].route[j]) {
remove = false;
break;
}
}
}
else
remove = false;
if (remove) {
int ind_neighbor = find_in_vector(adj_mat_loc[k_shortest_virt_paths[p].route[i].neighbor], k_shortest_virt_paths[p].route[i+1]);
if (ind_neighbor != -1) {
VERB_DEBUG_CHATTER("[RoutingPaths] Remove link between %s and %s", k_shortest_virt_paths[p].route[i].neighbor.unparse().c_str(),
k_shortest_virt_paths[p].route[i+1].unparse().c_str());
adj_mat_loc[k_shortest_virt_paths[p].route[i].neighbor][ind_neighbor].weight = DEFAULT_WEIGHT;
}
else //should not happen
click_chatter("[RoutingPaths %s] Error! Next node is not a neighbor", now.unparse().c_str());
// if node i is virtual source (i.e. we remove SRC_VN->EGR), remove as well ING->EGR (to avoid loops)
if (k_shortest_virt_paths[p].route[i].neighbor == src) {
for(int j=0;j<adj_mat_loc[k_shortest_virt_paths[p].route[i].neighbor].size();j++) {
VirtualNodeRouting egr_neighbor = adj_mat_loc[k_shortest_virt_paths[p].route[i].neighbor][j].neighbor;
VirtualNodeRouting ing_neighbor = VirtualNodeRouting(ING_VN, egr_neighbor.eth);
int ind = find_in_vector(adj_mat_loc[ing_neighbor], k_shortest_virt_paths[p].route[i+1]);
if(ind != -1) {
VERB_DEBUG_CHATTER("[RoutingPaths] Remove link between %s and %s", ing_neighbor.unparse().c_str(),
k_shortest_virt_paths[p].route[i+1].unparse().c_str());
adj_mat_loc[ing_neighbor][ind].weight = DEFAULT_WEIGHT;
}
else //should not happen
click_chatter("[RoutingPaths %s] Error! Next node is not a neighbor", now.unparse().c_str());
}
}
}
}
// nodes in rootPath cannot be included in the path (to avoid loops): remove them of adj_mat
for(int j=0;j<rootPath.route.size();j++) {
if (rootPath.route[j].neighbor.type == ING_VN || rootPath.route[j].neighbor.type == EGR_VN) {
NodeRouting node_path = _routing_links->get_node_from_eth(rootPath.route[j].neighbor.eth);
for (int l=0;l<node_path.interfaces.size();l++) {
adj_mat_loc.erase(VirtualNodeRouting(ING_VN, node_path.interfaces[l]));
adj_mat_loc.erase(VirtualNodeRouting(EGR_VN, node_path.interfaces[l]));
}
}
else
adj_mat_loc.erase(rootPath.route[j].neighbor);
}
// if spurNode is egress, remove corresponding ingresses (to avoid loops)
if (spurNode.type == EGR_VN) {
NodeRouting node_path = _routing_links->get_node_from_eth(spurNode.eth);
for (int l=0;l<node_path.interfaces.size();l++) {
adj_mat_loc.erase(VirtualNodeRouting(ING_VN, node_path.interfaces[l]));
}
}
// find shortest path
VirtualRoute spurPath = get_shortest_path_dij(adj_mat_loc, spurNode, dst);
// add weight of link between last node of rootPath and first node of spurPath
if (spurPath != VirtualRoute() && spurPath.route[0].neighbor == spurNode) {
VERB_DEBUG_CHATTER("[RoutingPaths] SpurPath is %s", spurPath.unparse().c_str());
VirtualRoute totalPath_virt = rootPath.concat_routes(spurPath, adj_mat);
// add shortest path to B
Route totalPath_real = virtual_route_to_route(totalPath_virt);
totalPath_real.ip = dst.ip;
if (totalPath_real != Route() && !is_in_vector(k_shortest_paths, totalPath_real)) {
potential_virt_paths.push_back(totalPath_virt);
potential_real_paths.push_back(totalPath_real);
weights_potential_paths.push_back(totalPath_virt.weight);
VERB_DEBUG_CHATTER("[RoutingPaths] Add potential path %s with weight %u", totalPath_real.unparse().c_str(), totalPath_virt.weight);
}
}
adj_mat_loc = adj_mat; // restore graph
rootPath.add_node(last_path.route[i]); // add spurNode to rootPath
}
assert(potential_virt_paths.size()==potential_real_paths.size());
assert(potential_virt_paths.size()==weights_potential_paths.size());
if(_verb_debug) {
VERB_DEBUG_CHATTER("List potential paths\n");
for(int count=0;count<potential_virt_paths.size();count++) {
VERB_DEBUG_CHATTER("%s", potential_virt_paths[count].unparse().c_str());
VERB_DEBUG_CHATTER("%s", potential_real_paths[count].unparse().c_str());
VERB_DEBUG_CHATTER("%u\n", weights_potential_paths[count]);
}
}
// find best path (minimum weight)
//if ((k + potential_virt_paths.size()) >= K) {
//while (k < K) {
int ind_min = find_min(weights_potential_paths);
if (ind_min != -1 && weights_potential_paths[ind_min] < DEFAULT_WEIGHT) {
if(!is_in_vector(k_shortest_paths, potential_real_paths[ind_min])) {
// insert best path in A
k_shortest_virt_paths.push_back(potential_virt_paths[ind_min]);
k_shortest_paths.push_back(potential_real_paths[ind_min]);
k++;
VERB_DEBUG_CHATTER("Path %s found, k=%d", potential_real_paths[ind_min].unparse().c_str(), k);
}
// remove best path from B
potential_virt_paths.erase(&potential_virt_paths[ind_min]);
potential_real_paths.erase(&potential_real_paths[ind_min]);
weights_potential_paths.erase(&weights_potential_paths[ind_min]);
}
else { // no more paths: break
VERB_DEBUG_CHATTER("Found %d/%d paths; no more paths", k, K);
k=K;
}
//}
// }
// else {
// int ind_min = find_min(weights_potential_paths);
// if (ind_min != -1 && weights_potential_paths[ind_min] < DEFAULT_WEIGHT) {
// // insert best path in A
// k_shortest_virt_paths.push_back(potential_virt_paths[ind_min]);
// k_shortest_paths.push_back(potential_real_paths[ind_min]);
// k++;
// VERB_DEBUG_CHATTER("Path %s found, k=%d", potential_real_paths[ind_min].unparse().c_str(), k);
// // remove best path from B
// potential_virt_paths.erase(&potential_virt_paths[ind_min]);
// weights_potential_paths.erase(&weights_potential_paths[ind_min]);
// }
// else { // no more paths: break
// VERB_DEBUG_CHATTER("Found %d paths; no more paths", k);
// k=K;
// }
// }
}
}
else
click_chatter("[RoutingPaths %s] WARNING: Paths can only be found between SRC_VN and DST_VN", now.unparse().c_str());
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] KShortestPaths done. Found %d paths", now.unparse().c_str(), k_shortest_paths.size());
return k_shortest_paths;
}
Vector<Route>
RoutingPaths::get_k_shortest_paths(const AdjacencyMatrix adj_mat, const VirtualNodeRouting src, const VirtualNodeRouting dst, int K)
{
VirtualRoute virtual_path;
return get_k_shortest_paths(adj_mat, src, dst, K, virtual_path);
}
void RoutingPaths::check_paths_valid(IPAddress dst, Vector<Vector<Route> > multipaths, bool store_route, bool check_order) {
if (check_order && _routing_links->get_has_order()) {
if (!equals_vector(multipaths, _last_seen_routes_mp[dst])) {
// paths are different: should notify dst in LinkState packets
Vector<Route> invalid_paths;
for(int i=0;i<_last_seen_routes_mp[dst].size();i++) {
for(int j=0;j<_last_seen_routes_mp[dst][i].size();j++) {
if(_notify_invalid_links && !is_in_vector(multipaths, _last_seen_routes_mp[dst][i][j]) && !_last_seen_routes_mp[dst][i][j].links.empty()) {
invalid_paths.push_back(_last_seen_routes_mp[dst][i][j]);
Timestamp now;
now.assign_now();
DEBUG_CHATTER("[RoutingPaths %s] Route %s has become invalid.",
now.unparse().c_str(), _last_seen_routes_mp[dst][i][j].unparse().c_str());
}
}
}
if (!invalid_paths.empty()) {
_routing_links->set_invalid_paths(invalid_paths);
_invalid_routes = invalid_paths;
}
_last_seen_routes_mp.set(dst, multipaths);
}
}
if(store_route)
_routes_to_print.set(dst, multipaths);
}
Vector<Route>
RoutingPaths::get_and_reset_invalid_routes() {
Vector<Route> invalid_paths = _invalid_routes;
_invalid_routes.clear();
return invalid_paths;
}
////////////////////// Handlers //////////////////////////////
static String
print_handler(Element *e, void *) {
RoutingPaths *rp = (RoutingPaths *)e;
return rp->print_routes();
}
int
RoutingPaths::get_route_handler(const String &s, Element *e, void *arg,
ErrorHandler *errh) {
RoutingPaths *rp = (RoutingPaths *)e;
Vector<String> arg_strings = parse_string(s,"/");
if (arg_strings.size() != 3)
return errh->error("Argument must be IP/N/n");
IPAddress ip = IPAddress(arg_strings[0]);
if (ip == IPAddress())
return errh->error("invalid IP address");
int N;
int n;
if(!cp_integer(arg_strings[1], &N))
return errh->error("Invalid N");
if(!cp_integer(arg_strings[2], &n))
return errh->error("Invalid n");
if(((intptr_t) arg) == 0)
rp->get_multipaths(ip, N, n, true, false, false, false);
else if(((intptr_t) arg) == 1)
rp->get_multipaths(ip, N, n, true, true, false, false);
else if(((intptr_t) arg) == 2)
rp->get_multipaths(ip, N, n, true, false, true, false);
return 0;
}
int
RoutingPaths::bool_handler(const String &s, Element *e, void *a,
ErrorHandler *errh) {
RoutingPaths *elmt = (RoutingPaths *)e;
int arg;
if(!cp_integer(s, &arg))
return errh->error("Debug must be 0 or 1");
if (!(arg == 0 || arg == 1))
return errh->error("Debug must be 0 or 1");
if(((intptr_t) a) == 0)
elmt->set_debug(arg==1);
if(((intptr_t) a) == 1)
elmt->set_verb_debug(arg==1);
if(((intptr_t) a) == 2)
elmt->reset();
if(((intptr_t) a) == 3)
elmt->set_keep_routes(arg==1);
return 0;
}
int
RoutingPaths::k_handler(const String &s, Element *e, void *arg,
ErrorHandler *errh) {
RoutingPaths *elmt = (RoutingPaths *)e;
int k;
if(!cp_integer(s, &k))
return errh->error("K must be an integer");
if(((intptr_t) arg) == 0)
elmt->set_k(k);
return 0;
}
int
RoutingPaths::multirouting_2best_paths_handler(const String &s, Element *e, void *,
ErrorHandler *errh) {
RoutingPaths *elmt = (RoutingPaths *)e;
int arg;
if(!cp_integer(s, &arg))
return errh->error("Arg must be 0 or 1");
if (!(arg == 0 || arg == 1))
return errh->error("Arg must be 0 or 1");
elmt->set_2bp(arg==1);
return 0;
}
int
RoutingPaths::forbidden_multipath_handler(const String &s, Element *e, void *arg,
ErrorHandler *errh) {
// format is addr1>addr2,addr2>addr3;addr4>addr5,addr6>addr7
RoutingPaths *elmt = (RoutingPaths *)e;
if(((intptr_t) arg) == 1 && s.equals("*"))
elmt->clear_forbidden_multipaths();
else {
Vector<String> arg_strings_mp = parse_string(s,";");
Multipath mp;
for(int i=0;i<arg_strings_mp.size();i++) {
Vector<String> arg_strings_route = parse_string(arg_strings_mp[i],",");
Route route;
for(int j=0;j<arg_strings_route.size();j++) {
Vector<String> arg_strings_link = parse_string(arg_strings_route[j],">");
if(arg_strings_link.size()!=2) {
click_chatter("Must have two addresses for a link");
return errh->error("Error in format");
}
EtherAddress eth1;
EtherAddress eth2;
click_chatter("%s %s", arg_strings_link[0].c_str(), arg_strings_link[1].c_str());
if (!cp_ethernet_address(arg_strings_link[0], ð1) || !cp_ethernet_address(arg_strings_link[1], ð2)) {
click_chatter("Could not parse addresses %s %s", arg_strings_link[0].c_str(), arg_strings_link[1].c_str());
return errh->error("Error in format");
}
LinkRouting link = LinkRouting(eth1, eth2, 0);
route.links.push_back(link);
}
mp.add_route(route);
}
if(((intptr_t) arg) == 0)
elmt->add_forbidden_multipath(mp);
if(((intptr_t) arg) == 1)
elmt->rm_forbidden_multipath(mp);
}
return 0;
}
void RoutingPaths::add_handlers() {
add_read_handler("print_routes", print_handler,0);
add_write_handler("get_route", get_route_handler, 0);
add_write_handler("get_route_wifi", get_route_handler, 1);
add_write_handler("get_route_plc", get_route_handler, 2);
add_write_handler("debug", bool_handler, 0);
add_write_handler("verb_debug", bool_handler, 1);
add_write_handler("reset", bool_handler, 2);
add_write_handler("keep_routes", bool_handler, 3);
add_write_handler("k", k_handler, 0);
add_write_handler("2bp", multirouting_2best_paths_handler, 0);
add_write_handler("add_forbidden_path", forbidden_multipath_handler, 0);
add_write_handler("rm_forbidden_path", forbidden_multipath_handler, 1);
}
ELEMENT_REQUIRES(RoutingLinks)
EXPORT_ELEMENT(RoutingPaths)
CLICK_ENDDECLS
Event Timeline
Log In to Comment