1 提出PacketBurest的背景
在无线通信的过程中,为了保证数据及时有效的传输,我们经常使用Ack控制帧来进行同步。但是 像MS/CPE这样的户外设备,在长距离传输过程中,如果大量传送以低速率传输(6 Mbps / 1Mbps)的Ack帧,势必会影响到整个系统的Performance。
为了解决这个矛盾,也就是在保证数据及时有效传输的前提下,我们采取某种方法来代替现有的应答机制,以达到提高系统性能的目的,于是我们想到了PacketBurest。也就是无线设备批量爆发性的发送数据包,Wireless driver不再发送Ack帧,通过PacketBurest模块内部的应答机制来实现两台设备之间的同步。
2 PacketBurest模块需要解决的问题以及实现原理
2.1 实现原理
正如前面所描述的,在现有的应答机制中,AP逐个回复来自station的Ping Req, Station在收到AP的Reply后,也会向AP逐个发送Ack。
PacketBurest实现在Station和AP上对等的一种同步机制,PacketBurest模块内部为每个和当前设备通信的设备维护一块叫做BurestBuffer的空间,用来缓存接受到数据包,然后按照下面的步骤进行同步:
APP
Bridge
ixp eth0
|
Packet Burst |
CPE |
APP
Bridge
eth0 ixp
|
MS |
Packet Burst |
1) 在Station端,将待发送 Req1, Req2, Req3…数据,经过一定的封装,加入Packet Index和开始结束标志,发送给AP,自己保存发送的副本;
2) 当发送到结束数据帧的时候,Station端清除已发送的副本,Packet Index清零,重新开始计数;
3) AP端在收到这些包以后加入接受队列,每隔一定数量的包(可以通过测试调整),判断是否有丢失包,如果有则生成一个Ack帧,告知Station那些包没有成功收到 。
如果全部成功收到,则进行第5步,否则进入第四步;
4) 如果Ack中包含有发送失败的信息,则Station应重复第一步,重新发送丢失的数据包;
5) AP每隔一段时间(可以是10ms),把收到的成功数据包,去掉Packet Index和开始结束标志,交给上层处理。
通过测试,把数据的缓冲区和时间片全部设在接受端,在通过接收队列滑动窗口的设计,可以减少时间片的省耗,同时也可以保证数据的同步,连续性和完整性。
2.2 主要的数据结构和帧格式
struct sk_buff * array_packet[500]; //保存已发送数据副本指针的数组
int * array_index; //用于解析接收到的ACK后,保存的丢失包索引的数组
static struct sk_buff * array_data[500]; //保存接收到的数据的指针的数组,根据包的索引连续存放
static int index_array[500]; //保存接收到的数据索引的的数组,用于构建ACK
struct FRAME_DATA_HEAD
{
/* the control field of the frame */
/*011:ACK_complete; 100:Data_begin; 101:Data_continue; 110:Data_end;111:Data_Rsend */
u_int8_t type :3; /* the define of the type */
u_int8_t flag_again :1;
u_int8_t flag_ack :1;
u_int8_t hode :3;
u_int16_t packet_index; /* the index of the packet */
u_int16_t ether_type; /* the original proto type of the packet */
};
struct FRAME_ACK_HEAD
{
u_int8_t num; /* the count of the lost packets */
u_int16_t pIndex_lost[100]; /* the index of the lost packets */
};
2.3 收/发包的流程
2.3.1 发包
待发送数据包
Packet_index++,修改数据包的协议类型,插入自定义的帧
Packet_index==500
NO
设置数据包的索引和标志,发送数据包
保存数据包的副本,用于重发
设置数据包的索引和标志,发送数据包,清空保存副本的数组,计数器清零
YES
待发送数据包
Packet_index++,修改数据包的协议类型,插入自定义的帧
Packet_index==500
NO
设置数据包的索引和标志,发送数据包
保存数据包的副本,用于重发
设置数据包的索引和标志,发送数据包,清空保存副本的数组,计数器清零
YES
注意:可以修改发送数据包函数的回调函数,让自定义数据包发完以后不释放,只设置标志,表示已经完成发送。这样可以不拷贝数据包,直接保存原始数据 ,等重发完成以后,在释放已经标志的数据包,可以提高性能。
2.3.2 收包
接收数据包 |
ACK |
data_index++,根据数据包的索引,放入接收的数组,并把该索引添加到索引表 |
data_index %5==0 |
根据接收到的索引表,查找丢失的数据,如果有丢失数据则发送ACK |
解析ACK,得到丢失数据的索引,根据索引重发丢失的数据报文。 |
时间片到来 |
根据接收的索引表,设置滑动窗口,把接收到的数据报文还原,根据索引依次传给上层处理 |
2.4 函数介绍及代码分析
Packet_brust_hook.c (主要包括发送和接收钩子函数的注册,把钩子挂接到bridge模块上面)
unsigned int PacketRxBrust();
unsigned int PacketTxBrust ( );
ackOperate.c(是接收方的处理部分)
int Ack_array_index(); //把接收到的数据包根据索引放在接收数组中。
static inline init_ackOperate(); //初始化接收部分的数据结构和一些标识。
static inline int in_array(); //判断给定的数据包索引是否已接收到,接受到返回1,否则返回0。
static int alloc_ack_end(); //根据丢失的数据包索引构建ACK报文。
int packet_Tx(); //时间片的发送函数。
static int Revert_received_skb();//还原接收到的数据为原始数据
skbOperate.c(对发送方的数据处理部分)
int Amend_type_skb(); //设置数据的索引和标识(开始,继续,结束)
int parse_ack(); //解析接收到ACK报文,得到的丢失的数据
int parse_skb(); //解析接收到数据包,返回数据标识(开始,继续,结束,ACK等)
RSend.c
void Ack_operate(void) //根据解析ACK报文,重发丢失的数据