Chinaunix首页 | 论坛 | 博客
  • 博客访问: 586472
  • 博文数量: 201
  • 博客积分: 3076
  • 博客等级: 中校
  • 技术积分: 2333
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:44
文章分类

全部博文(201)

文章存档

2010年(118)

2009年(83)

我的朋友

分类: 系统运维

2009-12-28 18:17:06

http://andychenkan.blog.163.com/blog/static/56300913200961695519363/ 

struct sk_buff {
    /* These two members must be first. */
    //以下两个变量用于将sk_buff链接到一个双向循环链表中
    struct sk_buff        *next;
    struct sk_buff        *prev;
    
//此报文所属的sock结构,此值在本机发出的报文中有效,从网络设备收到
//的报文此值为空
    struct sock        *sk;

//此报文收到时的时间
    ktime_t            tstamp;

//收到此报文的网络设备
    struct net_device    *dev;

//此报文的路由
    union {
        struct  dst_entry    *dst;
        struct  rtable        *rtable;
    };
    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];
//len表示存储区的数据长度和分片长度之和
    unsigned int        len,
    
    //da
ta_len表示分片长度
                data_len;
//mac_len表示mac头的长度
    __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;
    //pkt_type,数据报的类型。这个值在网卡驱动程序中由函数eth_type_trans通过判断
    //目的以太网地址来确定。如果目的地址是 FF:FF:FF:FF:FF:FF,则为广播地址,
    //pkt_type=PACKET_BROADCAST,如果最高位为1,则为组播地址,pkt_type=PACKET_MULTICAST,
    //如果目的mac地址跟本机mac地址不相等,则不是发给本机的数据报,
    //pkt_type=PACKET_OTHERHOST,否则就是缺省值PACKET_HOST。
    __u8            pkt_type:3,
                fclone:2,
                ipvs_property:1,
                peeked:1,
                nf_trace:1;
    //protocol, 它的值是以太网首部的第三个成员,即帧类型,对于IP数据来讲,
    //就是ETH_P_IP(0x8000),对ARP数据报来讲,就是ETH_P_ARP(0x8086)
    __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;
    __u16            queue_mapping;
#ifdef CONFIG_NET_SCHED
    __u16            tc_index;    /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
    __u16            tc_verd;    /* traffic control verdict */
#endif
#endif
#ifdef CONFIG_IPV6_NDISC_NODETYPE
    __u8            ndisc_nodetype:2;
#endif
#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
    __u8            do_not_encrypt:1;
#endif
    /* 0/13/14 bit hole */

#ifdef CONFIG_NET_DMA
    dma_cookie_t        dma_cookie;
#endif
#ifdef CONFIG_NETWORK_SECMARK
    __u32            secmark;
#endif

    __u32            mark;

    __u16            vlan_tci;
 //传输层报文头
    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.  */
//以下四个变量指向此报文的存储区
//网络报文在存储空间里的存放的顺序
//依次是:链路层的头部,网络层的头部,传输层的头部,传输层的数据

//tail指向网络报文的结束地址
    sk_buff_data_t        tail;
    //end指向存储空间的结束地址
    sk_buff_data_t        end;
    //head指向存储空间的起始地址
    unsigned char        *head,
    //data指向网络报文的起始地址
                *data;
    //truesize表示存储区总长度(即end-head)和sk_buff本身长度之和
    unsigned int        truesize;
    
    //表示该sk_buff结构实例被引用的计数。这个是结构本身的引用计数,
    //而不是其对应的存储区的引用计数。
    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头指针。

static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
{
    return (struct ethhdr *)skb_mac_header(skb);
}
获取以太网MAC头指针。以太网头指针结构体:
struct ethhdr {
    unsigned char    h_dest[ETH_ALEN];    /* destination eth addr    */
    unsigned char    h_source[ETH_ALEN];    /* source ether addr    */
    __be16        h_proto;        /* packet type ID field    */
} __attribute__((packed));

内核中网络地址转化为字符串形式的IP地址的宏定义:
#define NIPQUAD(addr)
((unsigned char *)&addr)[0],
((unsigned char *)&addr)[1],
((unsigned char *)&addr)[2],
((unsigned char *)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"
阅读(1121) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~