码迷,mamicode.com
首页 > 其他好文 > 详细

校验和快速计算方法

时间:2014-12-15 18:39:58      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:style   blog   ar   color   使用   sp   数据   div   art   

先将代码贴上

uint16_t cal_checksum(uint32_t *pstart,uint16_t len)
{
    uint64_t checksum;
    uint32_t *pend;
    uint32_t v0,v1,v2,v3,v4;
     checksum = 0;
    pend = (uint32_t*)((char*)pstart + (len & (~0xF)));
    while(pstart < pend)
    {
        v0 = *pstart;
        v1 = *(pstart+1);
        v2 = *(pstart+2);
        v3 = *(pstart+3);

        checksum += v0;
        checksum += v1;
        checksum += v2;
        checksum += v3;

        pstart += 4;
    }

    len = len & 0xF;
    pend = (uint32_t*)((char*)pstart + (len & (0xF)));
    while(pstart < pend)
    {
        v0 = (uint32_t)(*(uint16_t*)pstart);
        v1 = (uint32_t)(*((uint16_t*)pstart+1));

        checksum += v0;
        checksum += v1;

        pstart += 1;
    }

    switch(len & 0x3)
    {
        case 3:
            v0 = (uint32_t)(*(uint16_t*)pstart);
            v1 = ((uint32_t)(*((uint8_t*)pstart+2)) << 8);
            checksum += v0;
            checksum += v1;
            break;
        case 2:
            v0 = (uint32_t)(*(uint16_t*)pstart);
            checksum += v0;
            break;
        case 1:
            v0 = ((uint32_t)(*((uint8_t*)pstart+2)) << 8);
            checksum += v0;
        default:
            break;
    }

    checksum = (checksum>>32) + (checksum&0xFFFFFFFF);
    checksum = (checksum>>32) + (checksum&0xFFFFFFFF);
    checksum = (checksum>>16) + (checksum&0xFFFF);
    checksum = (checksum>>16) + (checksum&0xFFFF);

    return checksum ^ 0xFFFF;
}

RFC规定的checksum的计算方法是对每两个字节当做一个数进行计算,出现进位则加到低位上。

此处的代码优化有两个点:

1  交叉使用变量,以便节省装载延迟导致CPU等待

2  一次加法完成两对16字节数据相加,低16位进位则先加到高16位上,最终高16位也会加回低16位;为了防止高16位溢出,使用了uint64_t类型以便记录溢出

优化的第二条借鉴自Cavium的代码,不过可惜的是其代码由于使用非对齐加载以及未使用第一条优化,并且判断条件过多等,导致其性能严重低下。

优化后的代码性能基本上达到,cycle_num = len / 2,也就是说一个1500的数据包大概只需要不到800个cycles就能够完成checksum计算(CPU 1GHZ);

当然此代码也存在限制,那就是pstart指针至少需要4字节对齐,这就是为什么将其类型写成uint32_t*的原因。若不对齐,轻者严重影响效率;重者CPU出错。

一般来说,buff的首地址至少4字节对齐,计算checksum时,数据应该都已经在buff中装配好了,假设说buff中的开始数据是MAC头,接着是IP头,再跟着TCP头,那么只需要将

checksum=0

替换成

checksum=*(uint16_t*)pstart;

pstart = (uint32_t*)((uint16_t*)pstart+1);

len -=2;

即可直接将IP的payload首地址直接传进更正之后的函数,这是因为不管是Ethernet II还是802.3定义的MAC头都满足4n+2字节,甚至VLAN字段数据长度也是4的倍数。

校验和快速计算方法

标签:style   blog   ar   color   使用   sp   数据   div   art   

原文地址:http://www.cnblogs.com/long-wu/p/4165293.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!