?? ctpforwardingenginep.nc
字號:
/* $Id: CtpForwardingEngineP.nc,v 1.23 2009/08/15 18:11:30 gnawali Exp $ */
/*
* Copyright (c) 2008-9 Stanford University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Stanford University nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL STANFORD
* UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This component contains the forwarding path of CTP Noe, the
* standard CTP implementation packaged with TinyOS 2.x. The CTP
* specification can be found in TEP 123. The paper entitled
* "Collection Tree Protocol," by Omprakash Gnawali et al., in SenSys
* 2009, describes the implementation and provides detailed
* performance results of CTP Noe.</p>
*
* <p>The CTP ForwardingEngine is responsible for queueing and
* scheduling outgoing packets. It maintains a pool of forwarding
* messages and a packet send queue. A ForwardingEngine with a
* forwarding message pool of size <i>F</i> and <i>C</i>
* CollectionSenderC clients has a send queue of size <i>F +
* C</i>. This implementation several configuration constants, which
* can be found in <code>ForwardingEngine.h</code>.</p>
*
* <p>Packets in the send queue are sent in FIFO order, with
* head-of-line blocking. Because this is a tree collection protocol,
* all packets are going to the same destination, and so the
* ForwardingEngine does not distinguish packets from one
* another. Packets from CollectionSenderC clients are sent
* identically to forwarded packets: only their buffer handling is
* different.</p>
*
* <p>If ForwardingEngine is on top of a link layer that supports
* synchronous acknowledgments, it enables them and retransmits packets
* when they are not acked. It transmits a packet up to MAX_RETRIES times
* before giving up and dropping the packet. MAX_RETRIES is typically a
* large number (e.g., >20), as this implementation assumes there is
* link layer feedback on failed packets, such that link costs will go
* up and cause the routing layer to pick a next hop. If the underlying
* link layer does not support acknowledgments, ForwardingEngine sends
* a packet only once.</p>
*
* <p>The ForwardingEngine detects routing loops and tries to correct
* them. Routing is in terms of a cost gradient, where the collection
* root has a cost of zero and a node's cost is the cost of its next
* hop plus the cost of the link to that next hop. If there are no
* loops, then this gradient value decreases monotonically along a
* route. When the ForwardingEngine sends a packet to the next hop,
* it puts the local gradient value in the packet header. If a node
* receives a packet to forward whose gradient value is less than its
* own, then the gradient is not monotonically decreasing and there
* may be a routing loop. When the ForwardingEngine receives such a
* packet, it tells the RoutingEngine to advertise its gradient value
* soon, with the hope that the advertisement will update the node
* who just sent a packet and break the loop. It also pauses the
* before the next packet transmission, in hopes of giving the
* routing layer's packet a priority.</p>
*
* <p>ForwardingEngine times its packet transmissions. It
* differentiates between four transmission cases: forwarding,
* success, ack failure, and loop detection. In each case, the
* ForwardingEngine waits a randomized period of time before sending
* the next packet. This approach assumes that the network is
* operating at low utilization; its goal is to prevent correlated
* traffic -- such as nodes along a route forwarding packets -- from
* interfering with itself.</p>
*
* <p>While this implementation can work on top of a variety of link
* estimators, it is designed to work with a 4-bit link estimator
* (4B). Details on 4B can be found in the HotNets paper "Four Bit
* Link Estimation" by Rodrigo Fonseca et al. The forwarder provides
* the "ack" bit for each sent packet, telling the estimator whether
* the packet was acknowledged.</p>
*
* @author Philip Levis
* @author Kyle Jamieson
* @date $Date: 2009/08/15 18:11:30 $
*/
#include <CtpForwardingEngine.h>
#include <CtpDebugMsg.h>
generic module CtpForwardingEngineP() {
provides {
interface Init;
interface StdControl;
interface Send[uint8_t client];
interface Receive[collection_id_t id];
interface Receive as Snoop[collection_id_t id];
interface Intercept[collection_id_t id];
interface Packet;
interface CollectionPacket;
interface CtpPacket;
interface CtpCongestion;
}
uses {
// These five interfaces are used in the forwarding path
// SubSend is for sending packets
// PacketAcknowledgements is for enabling layer 2 acknowledgments
// RetxmitTimer is for timing packet sends for improved performance
// LinkEstimator is for providing the ack bit to a link estimator
interface AMSend as SubSend;
interface PacketAcknowledgements;
interface Timer<TMilli> as RetxmitTimer;
interface LinkEstimator;
interface UnicastNameFreeRouting;
interface Packet as SubPacket;
// These four data structures are used to manage packets to forward.
// SendQueue and QEntryPool are the forwarding queue.
// MessagePool is the buffer pool for messages to forward.
// SentCache is for suppressing duplicate packet transmissions.
interface Queue<fe_queue_entry_t*> as SendQueue;
interface Pool<fe_queue_entry_t> as QEntryPool;
interface Pool<message_t> as MessagePool;
interface Cache<message_t*> as SentCache;
interface Receive as SubReceive;
interface Receive as SubSnoop;
interface CtpInfo;
interface RootControl;
interface CollectionId[uint8_t client];
interface AMPacket;
interface Leds;
interface Random;
// This implementation has extensive debugging instrumentation.
// Wiring up the CollectionDebug interface provides information
// on important events, such as transmissions, receptions,
// and cache checks. The TinyOS release includes scripts for
// parsing these messages.
interface CollectionDebug;
// The ForwardingEngine monitors whether the underlying
// radio is on or not in order to start/stop forwarding
// as appropriate.
interface SplitControl as RadioControl;
}
}
implementation {
/* Helper functions to start the given timer with a random number
* masked by the given mask and added to the given offset.
*/
static void startRetxmitTimer(uint16_t mask, uint16_t offset);
void clearState(uint8_t state);
bool hasState(uint8_t state);
void setState(uint8_t state);
// CTP state variables.
enum {
QUEUE_CONGESTED = 0x1, // Need to set C bit?
ROUTING_ON = 0x2, // Forwarding running?
RADIO_ON = 0x4, // Radio is on?
ACK_PENDING = 0x8, // Have an ACK pending?
SENDING = 0x10 // Am sending a packet?
};
// Start with all states false
uint8_t forwardingState = 0;
/* Keep track of the last parent address we sent to, so that
unacked packets to an old parent are not incorrectly attributed
to a new parent. */
am_addr_t lastParent;
/* Network-level sequence number, so that receivers
* can distinguish retransmissions from different packets. */
uint8_t seqno;
enum {
CLIENT_COUNT = uniqueCount(UQ_CTP_CLIENT)
};
/* Each sending client has its own reserved queue entry.
If the client has a packet pending, its queue entry is in the
queue, and its clientPtr is NULL. If the client is idle,
its queue entry is pointed to by clientPtrs. */
fe_queue_entry_t clientEntries[CLIENT_COUNT];
fe_queue_entry_t* ONE_NOK clientPtrs[CLIENT_COUNT];
/* The loopback message is for when a collection roots calls
Send.send. Since Send passes a pointer but Receive allows
buffer swaps, the forwarder copies the sent packet into
the loopbackMsgPtr and performs a buffer swap with it.
See sendTask(). */
message_t loopbackMsg;
message_t* ONE_NOK loopbackMsgPtr;
command error_t Init.init() {
int i;
for (i = 0; i < CLIENT_COUNT; i++) {
clientPtrs[i] = clientEntries + i;
dbg("Forwarder", "clientPtrs[%hhu] = %p\n", i, clientPtrs[i]);
}
loopbackMsgPtr = &loopbackMsg;
lastParent = call AMPacket.address();
seqno = 0;
return SUCCESS;
}
command error_t StdControl.start() {
setState(ROUTING_ON);
return SUCCESS;
}
command error_t StdControl.stop() {
clearState(ROUTING_ON);
return SUCCESS;
}
/* sendTask is where the first phase of all send logic
* exists (the second phase is in SubSend.sendDone()). */
task void sendTask();
/* ForwardingEngine keeps track of whether the underlying
radio is powered on. If not, it enqueues packets;
when it turns on, it then starts sending packets. */
event void RadioControl.startDone(error_t err) {
if (err == SUCCESS) {
setState(RADIO_ON);
if (!call SendQueue.empty()) {
dbg("FHangBug", "%s posted sendTask.\n", __FUNCTION__);
post sendTask();
}
}
}
static void startRetxmitTimer(uint16_t window, uint16_t offset) {
uint16_t r = call Random.rand16();
r %= window;
r += offset;
call RetxmitTimer.startOneShot(r);
dbg("Forwarder", "Rexmit timer will fire in %hu ms\n", r);
}
/*
* If the ForwardingEngine has stopped sending packets because
* these has been no route, then as soon as one is found, start
* sending packets.
*/
event void UnicastNameFreeRouting.routeFound() {
dbg("FHangBug", "%s posted sendTask.\n", __FUNCTION__);
post sendTask();
}
event void UnicastNameFreeRouting.noRoute() {
// Depend on the sendTask to take care of this case;
// if there is no route the component will just resume
// operation on the routeFound event
}
event void RadioControl.stopDone(error_t err) {
if (err == SUCCESS) {
clearState(RADIO_ON);
}
}
ctp_data_header_t* getHeader(message_t* m) {
return (ctp_data_header_t*)call SubPacket.getPayload(m, sizeof(ctp_data_header_t));
}
/*
* The send call from a client. Return EBUSY if the client is busy
* (clientPtrs is NULL), otherwise configure its queue entry
* and put it in the send queue. If the ForwardingEngine is not
* already sending packets (the RetxmitTimer isn't running), post
* sendTask. It could be that the engine is running and sendTask
* has already been posted, but the post-once semantics make this
* not matter. What's important is that you don't post sendTask
* if the retransmit timer is running; this would circumvent the
* timer and send a packet before it fires.
*/
command error_t Send.send[uint8_t client](message_t* msg, uint8_t len) {
ctp_data_header_t* hdr;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -