路由层如何处理底层的传输失败
转自:http://hi.baidu.com/karashun/blog/item/0fad3e4f7bbb28d5d0c86a08.html
1. 大致思想
MAC 在传输失败的时候,通过函数指针调用 上层(路由层)的失败处理函数。2. 函数指针的用法:
1) 定义:
// packet.h
typedef void (*FailureCallback)(Packet *,void *);
// FailureCallback 是一个函数指针类型, 可以指向 任意参数 为(Packet *,void *),返回值为void的函数。
struct hdr_cmn {
.....
// called if pkt can't obtain media or isn't ack'd. not called if droped by a queue
FailureCallback xmit_failure_;
void *xmit_failure_data_;
}
2) 赋值:
赋值为函数地址就好了
例如,在adov中,ch->xmit_failure_ = aodv_rt_failed_callback;
3) 使用:
(a) 定义函数 aodv_rt_failed_callback, 符合指针类型要求
尤其注意返回类型, 是void, 而不能是void DSRAgent:: !!
所以只能用两个函数实现, 继续调用路由协议agent的失败处理函数。
void XmitFlowFailureCallback(Packet *pkt, void *data)
{
DSRAgent *agent = (DSRAgent *)data;
agent->xmitFlowFailed(pkt);
}
void DSRAgent::xmitFailed(Packet *pkt, const char* reason) {
}
(b) 调用:
ch->xmit_failure_ (pDATA->copy(), ch->xmit_failure_data_);
3. MAC 层的传输 失败
1) RTS/CTS 握手次数超过 limit
2) MAC层数据重传 次数超过limit
// mac-802_11Ext.cc
1) void TXC::handleTCTStimeout() {
if (shortretrycounter >= mac_->macmib_.getShortRetryLimit()) {
.......
// higher layers feedback support
struct hdr_cmn *ch = HDR_CMN(pDATA);
if (ch->xmit_failure_) {
ch->xmit_reason_ = XMIT_REASON_RTS;
ch->xmit_failure_(pDATA->copy(), ch->xmit_failure_data_);
}
mac_->discard(pDATA, DROP_MAC_RETRY_COUNT_EXCEEDED);
.....}
2) void TXC::handleTACKtimeout() {
if (*counter >= limit) {
// higher layers feedback support
struct hdr_cmn *ch = HDR_CMN(pDATA);
if (ch->xmit_failure_) {
ch->xmit_reason_ = XMIT_REASON_RTS;
ch->xmit_failure_(pDATA->copy(), ch->xmit_failure_data_);
}
mac_->discard(pDATA, DROP_MAC_RETRY_COUNT_EXCEEDED);
}
4. 路由层的失败处理:
以aodv.cc 为例:
1) 对回调函数进行赋值: ch->xmit_failure_
void
AODV::rt_resolve(Packet *p) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
aodv_rt_entry *rt;
// 赋值 : Set the transmit failure callback. That won't change.
ch->xmit_failure_ = aodv_rt_failed_callback;
// kara say: xmit_failure_ 是一个函数指针, 这里赋值为 aodv 中的失败回调函数, 函数名称代表函数地址。
ch->xmit_failure_data_ = (void*) this;
rt = rtable.rt_lookup(ih->daddr());
if(rt == 0) {
rt = rtable.rt_add(ih->daddr());
}
2) 失败处理函数
/* Link Failure Management Functions*/
static void
aodv_rt_failed_callback(Packet *p, void *arg) {
((AODV*) arg)->rt_ll_failed(p);
}
/* * This routine is invoked when the link-layer reports a route failed. */
void
AODV::rt_ll_failed(Packet *p) {
nsaddr_t broken_nbr = ch->next_hop_;
log_link_broke(p);
if((rt = rtable.rt_lookup(ih->daddr())) == 0) {
drop(p, DROP_RTR_MAC_CALLBACK);
return;
}
log_link_del(ch->next_hop_);
#ifdef AODV_LOCAL_REPAIR
/* if the broken link is closer to the dest than source, attempt a local repair. Otherwise, bring down the route. */
if (ch->num_forwards() > rt->rt_hops) {
local_rt_repair(rt, p); // local repair
// retrieve all the packets in the ifq using this link,
// queue the packets for which local repair is done,
return;
}
else
#endif // LOCAL REPAIR