Chinaunix首页 | 论坛 | 博客
  • 博客访问: 95992
  • 博文数量: 14
  • 博客积分: 188
  • 博客等级: 入伍新兵
  • 技术积分: 142
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-11 09:59
文章分类

全部博文(14)

文章存档

2012年(14)

分类:

2012-03-10 21:50:53

读了一下《Professional Linux Kernel Architecture》的Network这一章。由于本书讲得比较新,可以说是市面上目前讲Linux内核版本最新的著作了,涉及到了2.6.24版本。其中,有很多微妙的变化,由于struct sk_buff是内核网络机构的基础,因此我也比较关心这个结构的变化:
struct sk_buff {
 /* These two members must be first. */
 struct sk_buff  *next;
 struct sk_buff  *prev;
 struct sock  *sk;
 ktime_t   tstamp;
 struct net_device *dev;
 struct  dst_entry *dst;
 struct sec_path *sp;
 /*
  * This is the control buffer. It is free to use for every
  * layer. Please put your private variables there. If you
  * want to keep them across layers you have to do a skb_clone()
  * first. This is owned by whoever has the skb queued ATM.
  */
 char   cb[48];
 unsigned int  len,
    data_len;
 __u16   mac_len,
    hdr_len;
 union {
  __wsum  csum;
  struct {
   __u16 csum_start;
   __u16 csum_offset;
  };
 };
 __u32   priority;
 __u8   local_df:1,
    cloned:1,
    ip_summed:2,
    nohdr:1,
    nfctinfo:3;
 __u8   pkt_type:3,
    fclone:2,
    ipvs_property:1,
    peeked:1,
    nf_trace:1;
 __be16   protocol;
 void   (*destructor)(struct sk_buff *skb);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 struct nf_conntrack *nfct;
 struct sk_buff  *nfct_reasm;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
 struct nf_bridge_info *nf_bridge;
#endif
 int   iif;
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
 __u16   queue_mapping;
#endif
#ifdef CONFIG_NET_SCHED
 __u16   tc_index; /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
 __u16   tc_verd; /* traffic control verdict */
#endif
#endif
 /* 2 byte hole */
#ifdef CONFIG_NET_DMA
 dma_cookie_t  dma_cookie;
#endif
#ifdef CONFIG_NETWORK_SECMARK
 __u32   secmark;
#endif
 __u32   mark;
 sk_buff_data_t  transport_header;
 sk_buff_data_t  network_header;
 sk_buff_data_t  mac_header;

 /* These elements must be at the end, see alloc_skb() for details.  */
 sk_buff_data_t  tail;
 sk_buff_data_t  end;
 unsigned char  *head,
    *data;
 unsigned int  truesize;
 atomic_t  users;
};
用红色标记这三个成员,分别是传输头,网络头以及mac头相对于Sk_buff的head的偏移。有了这三个成员,可以说为内核编程人员提供了更便利的获取传输层、网络层和MAC层头的偏移。并且,内核也新增了几个函数,来提供获取这些偏移的接口:
#ifdef NET_SKBUFF_DATA_USES_OFFSET
如果使用了offset来表示偏移的话,就是说是一个相对偏移的情况:
static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
{
 return skb->head + skb->transport_header;
}
static inline void skb_reset_transport_header(struct sk_buff *skb)
{
 skb->transport_header = skb->data - skb->head;
}
static inline void skb_set_transport_header(struct sk_buff *skb,
         const int offset)
{
 skb_reset_transport_header(skb);
 skb->transport_header += offset;
}
static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{
 return skb->head + skb->network_header;
}
static inline void skb_reset_network_header(struct sk_buff *skb)
{
 skb->network_header = skb->data - skb->head;
}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
{
 skb_reset_network_header(skb);
 skb->network_header += offset;
}
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
{
 return skb->head + skb->mac_header;
}
static inline int skb_mac_header_was_set(const struct sk_buff *skb)
{
 return skb->mac_header != ~0U;
}
static inline void skb_reset_mac_header(struct sk_buff *skb)
{
 skb->mac_header = skb->data - skb->head;
}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
{
 skb_reset_mac_header(skb);
 skb->mac_header += offset;
}
#else /* NET_SKBUFF_DATA_USES_OFFSET */
不使用相对偏移的情况
static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
{
 return skb->transport_header;
}
static inline void skb_reset_transport_header(struct sk_buff *skb)
{
 skb->transport_header = skb->data;
}
static inline void skb_set_transport_header(struct sk_buff *skb,
         const int offset)
{
 skb->transport_header = skb->data + offset;
}
static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{
 return skb->network_header;
}
static inline void skb_reset_network_header(struct sk_buff *skb)
{
 skb->network_header = skb->data;
}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
{
 skb->network_header = skb->data + offset;
}
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
{
 return skb->mac_header;
}
static inline int skb_mac_header_was_set(const struct sk_buff *skb)
{
 return skb->mac_header != NULL;
}
static inline void skb_reset_mac_header(struct sk_buff *skb)
{
 skb->mac_header = skb->data;
}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
{
 skb->mac_header = skb->data + offset;
}
#endif /* NET_SKBUFF_DATA_USES_OFFSET */
1、TCP层获取相关偏移的函数
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
{
 return (struct tcphdr *)skb_transport_header(skb);
}
这个函数用来获得sk_buff结构中TCP头的指针
static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)
{
 return tcp_hdr(skb)->doff * 4;
}
这个函数用来获得TCP头的长度
static inline unsigned int tcp_optlen(const struct sk_buff *skb)
{
 return (tcp_hdr(skb)->doff - 5) * 4;
}
获取tcp option的长度
2、IP相关的函数
static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
{
 return (struct iphdr *)skb_network_header(skb);
}
该函数获得ip头
static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
{
 return (struct iphdr *)skb_transport_header(skb);
}
该函数获得ipip头,实际上偏移已经跑到了传输层的开始
3、MAC相关函数
static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb)
{
 return (struct ebt_802_3_hdr *)skb_mac_header(skb);
}
获取802.3MAC头指针。
 
可以说,这些函数,为我们编写内核程序提供了极大的便捷,而不用再花更多的精力去考虑计算各层的指针偏移,可以把更多的精力用来考虑策略性的设计。
阅读(1115) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~