📄 ctproutingenginep.nc
字号:
for (i = 0; i < routingTableActive; i++) {
entry = &routingTable[i];
// Avoid bad entries and 1-hop loops
if (entry->info.parent == INVALID_ADDR || entry->info.parent == my_ll_addr) {
dbg("TreeRouting",
"routingTable[%d]: neighbor: [id: %d parent: %d etx: NO ROUTE]\n",
i, entry->neighbor, entry->info.parent);
continue;
}
/* Compute this neighbor's path metric */
linkEtx = evaluateEtx(call LinkEstimator.getLinkQuality(entry->neighbor));
dbg("TreeRouting",
"routingTable[%d]: neighbor: [id: %d parent: %d etx: %d retx: %d]\n",
i, entry->neighbor, entry->info.parent, linkEtx, entry->info.etx);
pathEtx = linkEtx + entry->info.etx;
/* Operations specific to the current parent */
if (entry->neighbor == routeInfo.parent) {
dbg("TreeRouting", " already parent.\n");
currentEtx = pathEtx;
/* update routeInfo with parent's current info */
atomic {
routeInfo.etx = entry->info.etx;
routeInfo.congested = entry->info.congested;
}
continue;
}
/* Ignore links that are congested */
if (entry->info.congested)
continue;
/* Ignore links that are bad */
if (!passLinkEtxThreshold(linkEtx)) {
dbg("TreeRouting", " did not pass threshold.\n");
continue;
}
if (pathEtx < minEtx) {
dbg("TreeRouting", " best is %d, setting to %d\n", pathEtx, entry->neighbor);
minEtx = pathEtx;
best = entry;
}
}
//call CollectionDebug.logEventDbg(NET_C_DBG_3, routeInfo.parent, currentEtx, minEtx);
/* Now choose between the current parent and the best neighbor */
/* Requires that:
1. at least another neighbor was found with ok quality and not congested
2. the current parent is congested and the other best route is at least as good
3. or the current parent is not congested and the neighbor quality is better by
the PARENT_SWITCH_THRESHOLD.
Note: if our parent is congested, in order to avoid forming loops, we try to select
a node which is not a descendent of our parent. routeInfo.ext is our parent's
etx. Any descendent will be at least that + 10 (1 hop), so we restrict the
selection to be less than that.
*/
if (minEtx != MAX_METRIC) {
if (currentEtx == MAX_METRIC ||
(routeInfo.congested && (minEtx < (routeInfo.etx + 10))) ||
minEtx + PARENT_SWITCH_THRESHOLD < currentEtx) {
// routeInfo.metric will not store the composed metric.
// since the linkMetric may change, we will compose whenever
// we need it: i. when choosing a parent (here);
// ii. when choosing a next hop
parentChanges++;
dbg("TreeRouting","Changed parent. from %d to %d\n", routeInfo.parent, best->neighbor);
call CollectionDebug.logEventDbg(NET_C_TREE_NEW_PARENT, best->neighbor, best->info.etx, minEtx);
call LinkEstimator.unpinNeighbor(routeInfo.parent);
call LinkEstimator.pinNeighbor(best->neighbor);
call LinkEstimator.clearDLQ(best->neighbor);
atomic {
routeInfo.parent = best->neighbor;
routeInfo.etx = best->info.etx;
routeInfo.congested = best->info.congested;
}
if (currentEtx - minEtx > 20) {
call CtpInfo.triggerRouteUpdate();
}
}
}
/* Finally, tell people what happened: */
/* We can only loose a route to a parent if it has been evicted. If it hasn't
* been just evicted then we already did not have a route */
if (justEvicted && routeInfo.parent == INVALID_ADDR)
signal Routing.noRoute();
/* On the other hand, if we didn't have a parent (no currentEtx) and now we
* do, then we signal route found. The exception is if we just evicted the
* parent and immediately found a replacement route: we don't signal in this
* case */
else if (!justEvicted &&
currentEtx == MAX_METRIC &&
minEtx != MAX_METRIC)
signal Routing.routeFound();
justEvicted = FALSE;
}
/* send a beacon advertising this node's routeInfo */
// only posted if running and radioOn
task void sendBeaconTask() {
error_t eval;
if (sending) {
return;
}
beaconMsg->options = 0;
/* Congestion notification: am I congested? */
if (call CtpCongestion.isCongested()) {
beaconMsg->options |= CTP_OPT_ECN;
}
beaconMsg->parent = routeInfo.parent;
if (state_is_root) {
beaconMsg->etx = routeInfo.etx;
}
else if (routeInfo.parent == INVALID_ADDR) {
beaconMsg->etx = routeInfo.etx;
beaconMsg->options |= CTP_OPT_PULL;
} else {
beaconMsg->etx = routeInfo.etx +
evaluateEtx(call LinkEstimator.getLinkQuality(routeInfo.parent));
}
dbg("TreeRouting", "%s parent: %d etx: %d\n",
__FUNCTION__,
beaconMsg->parent,
beaconMsg->etx);
call CollectionDebug.logEventRoute(NET_C_TREE_SENT_BEACON, beaconMsg->parent, 0, beaconMsg->etx);
eval = call BeaconSend.send(AM_BROADCAST_ADDR,
&beaconMsgBuffer,
sizeof(ctp_routing_header_t));
if (eval == SUCCESS) {
sending = TRUE;
} else if (eval == EOFF) {
radioOn = FALSE;
dbg("TreeRoutingCtl","%s running: %d radioOn: %d\n", __FUNCTION__, running, radioOn);
}
}
event void BeaconSend.sendDone(message_t* msg, error_t error) {
if ((msg != &beaconMsgBuffer) || !sending) {
//something smells bad around here
return;
}
sending = FALSE;
}
event void RouteTimer.fired() {
if (radioOn && running) {
post updateRouteTask();
}
}
event void BeaconTimer.fired() {
if (radioOn && running) {
if (!tHasPassed) {
post updateRouteTask(); //always send the most up to date info
post sendBeaconTask();
dbg("RoutingTimer", "Beacon timer fired at %s\n", sim_time_string());
remainingInterval();
}
else {
decayInterval();
}
}
}
ctp_routing_header_t* getHeader(message_t* ONE m) {
return (ctp_routing_header_t*)call BeaconSend.getPayload(m, call BeaconSend.maxPayloadLength());
}
/* Handle the receiving of beacon messages from the neighbors. We update the
* table, but wait for the next route update to choose a new parent */
event message_t* BeaconReceive.receive(message_t* msg, void* payload, uint8_t len) {
am_addr_t from;
ctp_routing_header_t* rcvBeacon;
bool congested;
// Received a beacon, but it's not from us.
if (len != sizeof(ctp_routing_header_t)) {
dbg("LITest", "%s, received beacon of size %hhu, expected %i\n",
__FUNCTION__,
len,
(int)sizeof(ctp_routing_header_t));
return msg;
}
//need to get the am_addr_t of the source
from = call AMPacket.source(msg);
rcvBeacon = (ctp_routing_header_t*)payload;
congested = call CtpRoutingPacket.getOption(msg, CTP_OPT_ECN);
dbg("TreeRouting","%s from: %d [ parent: %d etx: %d]\n",
__FUNCTION__, from,
rcvBeacon->parent, rcvBeacon->etx);
//update neighbor table
if (rcvBeacon->parent != INVALID_ADDR) {
/* If this node is a root, request a forced insert in the link
* estimator table and pin the node. */
if (rcvBeacon->etx == 0) {
dbg("TreeRouting","from a root, inserting if not in table\n");
call LinkEstimator.insertNeighbor(from);
call LinkEstimator.pinNeighbor(from);
}
//TODO: also, if better than my current parent's path etx, insert
routingTableUpdateEntry(from, rcvBeacon->parent, rcvBeacon->etx);
call CtpInfo.setNeighborCongested(from, congested);
}
if (call CtpRoutingPacket.getOption(msg, CTP_OPT_PULL)) {
resetInterval();
}
return msg;
}
/* Signals that a neighbor is no longer reachable. need special care if
* that neighbor is our parent */
event void LinkEstimator.evicted(am_addr_t neighbor) {
routingTableEvict(neighbor);
dbg("TreeRouting","%s\n",__FUNCTION__);
if (routeInfo.parent == neighbor) {
routeInfoInit(&routeInfo);
justEvicted = TRUE;
post updateRouteTask();
}
}
/* Interface UnicastNameFreeRouting */
/* Simple implementation: return the current routeInfo */
command am_addr_t Routing.nextHop() {
return routeInfo.parent;
}
command bool Routing.hasRoute() {
return (routeInfo.parent != INVALID_ADDR);
}
/* CtpInfo interface */
command error_t CtpInfo.getParent(am_addr_t* parent) {
if (parent == NULL)
return FAIL;
if (routeInfo.parent == INVALID_ADDR)
return FAIL;
*parent = routeInfo.parent;
return SUCCESS;
}
command error_t CtpInfo.getEtx(uint16_t* etx) {
if (etx == NULL)
return FAIL;
if (routeInfo.parent == INVALID_ADDR)
return FAIL;
if (state_is_root == 1) {
*etx = 0;
} else {
// path etx = etx(parent) + etx(link to the parent)
*etx = routeInfo.etx + evaluateEtx(call LinkEstimator.getLinkQuality(routeInfo.parent));
}
return SUCCESS;
}
command void CtpInfo.recomputeRoutes() {
post updateRouteTask();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -