【Atheros】无线网卡驱动性能测试工具pktgen的使用

时间:2024-02-17 08:18:57

前言:从12年开始做无线驱动相关的工作,到13年大概做了一年半,现在歇了快一年了,以免白学那么久,最近重新整理了一下当时的资料,写一点文章,这方面的帖子比较少,当时碰到过很多问题难以解决,我是用的linux2.6的内核,将来用其他版本的朋友也可能会碰到类似的问题,可以把我的解决方案做一个参考~主要内容是pktgen、iperf使用的注意事项、驱动禁用CSMA、BACKOFF、ACK的方法、速率调整算法源码解读等。后面的几篇文章一一介绍,文章列表

测试无线性能的pktgen有专用的版本,编译atheros固件的时候会自带一个无线版本的pktgen,我一开始用pktgen官网提供的pktgen发送脚本,怎么发都是一运行内核就panic,或者开发板变得非常卡,有时候没有崩溃的情况下,dmsg查看输出,可以看到源码里这一句打印了堆栈信息:

WARN_ON(tid->ac->txq != txq);

代码位置不重要,反正可以看到是txq,也就是发送队列有问题。正巧呢经过仔细观察pktgen的统计信息:

发现里面有queue_map_min和queue_map_max这样两个参数,pktgen官方的脚本里没有设置,我从pktgen官网上下载的源码里面也没有提这两个参数,这俩就是关键,现在的2是我后来自己设置的,默认好像是0。这个发送队列在代码里对应的是这样的取值:

/**
 * enum ieee80211_ac_numbers - AC numbers as used in mac80211
 * @IEEE80211_AC_VO: voice
 * @IEEE80211_AC_VI: video
 * @IEEE80211_AC_BE: best effort
 * @IEEE80211_AC_BK: background
 */
enum ieee80211_ac_numbers {
    IEEE80211_AC_VO        = 0,
    IEEE80211_AC_VI        = 1,
    IEEE80211_AC_BE        = 2,
    IEEE80211_AC_BK        = 3,
};

这是数据包对应于不同接入类别的几个发送队列,正常数据包都是使用尽力而为这种级别,只要把queue_map_min和queue_map_max都设置为2,pktgen的数据包都用这个AC来发就没问题了。

==================================分割线=========================================

关于这个发送队列,实际在使用pktgen的过程中还有一个后续问题,在这里分享一下:

虽然设置了queue_map,但是不知道为什么,生成的前两个数据包仍然是队列0和1的,后面才是我指定的2的,虽然影响不大,但是有两个弊端:一是pktgen的clone_skb域只能设置为0或其它较小的数,如果设置为10000,那么最前面的将近20000个包的发送队列都是不对的。而clone_skb的值越大,pktgen发送包的效率越高,当然,clone_skb为0时的效率已经够我们用的了,所以这一点关系不大。在这里解释一下clone_skb这个属性,pktgen调用驱动的某个函数(假设函数是tx())来进行发包,并把封装数据的sk_buff对象(skb)作为参数传进去,那么如果一共发三个包,大概就是这样的流程(下面的都是伪代码):

struct sk_buff *skb = get_new_skb();//生成一个新的skb并填充数据
tx(skb);
struct sk_buff *skb = get_new_skb();
tx(skb);
struct sk_buff *skb = get_new_skb();
tx(skb);

这是clone_skb=0或1的情况,也就是说,发送的这三个数据包是相互独立的,没有重复使用,如果clone_skb=2就指定两个包共用一个skb,就变成了下面这样:

struct sk_buff *skb = get_new_skb();
tx(skb);
tx(skb);
struct sk_buff *skb = get_new_skb();
tx(skb);

因为没有重复生成skb,也就提高了效率。这是第一个问题,第二个是在驱动里有一开始提到的WARN_ON的那一步判断,如果发送队列不是预期的值,会打印堆栈信息,这个打印操作是很耗时,在内核中,过于频繁的printk都可以导致系统崩溃,如果太频繁的打印堆栈信息,也是会导致崩溃的(这也是不设置pktgen的发送队列时板子可能会崩溃的原因),现在clone_skb的值是0,用脚本自动切换MCS时,每次使用新的MCS之后前两个包都会打印出堆栈信息,而堆栈信息又很长,这样很影响我们观察在驱动其它地方使用printk打印的输出。

解决方法是不管queue_map_min和queue_map_max怎么设置了,统一在数据包刚进入链路层代码的地方强制把这个字段置成2,当然如果是以真实使用为目的还要改回去,现在用pktgen做实验用,就没关系了,pktgen发包是通过调用atheros驱动的

ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev)

这个函数,该函数在/net/mac80211/tx.c中,就在这个函数开始的位置判断当前数据包是不是pktgen的数据包(通过pktgen头部的magic number来进行判断),如果是,就调用前面提到的skb_set_queue_mapping函数把它放到2号队列里去。代码片段如下:

if (skb->len > 58){
    __le32 *magic = &skb->data[42];
    if(*magic == 0xbe9be955)                /* magic number of pktgen */
        skb_set_queue_mapping(skb, 2);        /* BE */
}

pktgen的最小包长是14(MAC头)+20(IP头)+8(UDP头)+16(Pktgen头),大于该值才进行判断,pktgen头部是从第42字节开始,按小端序取出来和pktgen的magic number来进行比较,如果匹配,则设置发送队列。