禁用于任何商业用途。
msn: [email protected]
来源:http://yfydz.cublog.cn
1. 前言 在linux 2.6内核中对于网络数据包中的时间戳处理和2.4相比有了不少变化,如果原样照搬2.4就要出错 了。 2. 2.6中的tstamp 2.4中skb的时间戳直接就用struct timeval结构,而且使用时直接访问该参数。 2.6中的时间戳已经改为skb专用的时间结构struct skb_timeval: struct sk_buff { ...... struct skb_timeval tstamp; ..... }; 定义如下: struct skb_timeval { u32 off_sec; u32 off_usec; }; 和2.4区别就是强调了参数是32位无符号数,时间是相对于一个基准时间的偏差,基准点可以自己定义, 通常还是按UNIX的缺省基准时间;而在timeval中定义的是long,在64位系统中将是64位,而且是有符 号的,时间是绝对时间,即基准点是固定的。 在 include/linux/skbuff.h 中提供以下两个函数接口来获取和设置skb的时间戳: /** * skb_get_timestamp - get timestamp from a skb * @skb: skb to get stamp from * @stamp: pointer to struct timeval to store stamp in * * Timestamps are stored in the skb as offsets to a base timestamp. * This function converts the offset back to a struct timeval and stores * it in stamp. */ static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp) { stamp->tv_sec = skb->tstamp.off_sec; stamp->tv_usec = skb->tstamp.off_usec; } /** * skb_set_timestamp - set timestamp of a skb * @skb: skb to set stamp of * @stamp: pointer to struct timeval to get stamp from * * Timestamps are stored in the skb as offsets to a base timestamp. * This function converts a struct timeval to an offset and stores * it in the skb. */ static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp) { skb->tstamp.off_sec = stamp->tv_sec; skb->tstamp.off_usec = stamp->tv_usec; } 3. 记录时间 2.4中skb的时间戳是自动记录的,获取skb后就能直接读取其进入系统的时间。 而在2.6中,是否记录时间戳成为可选的,大概因为很多网络应用中用不到skb的内部时间,为其赋值将 增加系统的开销,系统增加了一个静态参数netstamp_needed来控制是否记录时间戳。 /* net/core/dev.c */ /* When > 0 there are consumers of rx skb time stamps */ static atomic_t netstamp_needed = ATOMIC_INIT(0); // 允许记录时间戳 void net_enable_timestamp(void) { atomic_inc(&netstamp_needed); } // 停止记录时间戳 void net_disable_timestamp(void) { atomic_dec(&netstamp_needed); } // 设置时间戳 void __net_timestamp(struct sk_buff *skb) { struct timeval tv; do_gettimeofday(&tv); skb_set_timestamp(skb, &tv); } EXPORT_SYMBOL(__net_timestamp); static inline void net_timestamp(struct sk_buff *skb) { if (atomic_read(&netstamp_needed)) // 有需要时才设置时间戳 __net_timestamp(skb); else { // 否则时间戳值为0 skb->tstamp.off_sec = 0; skb->tstamp.off_usec = 0; } } 在发包函数dev_queue_xmit_nit()和收包函数nettf_rx(),netif_receive_skb()中就调用了 net_timestamp()函数来设置时间戳,而缺省情况下不记录时间戳,要使系统记录时间戳必须模块中调用 net_enable_timestamp()来允许记录时间戳,模块退出时调用net_disable_timestamp()停止记录。 3. 结论 对于安全设备,要识别flood、scan等攻击都要用到时间上的统计信息,所以时间戳是必须的,而如果是从2.4移植到2.6,就必须增加net_enable_timestamp()打开时间戳记录,否则将会发现时间戳都是0而使统计失败,而如果没仔细检查时间戳值的话,真是死都不知道是怎么死的。