2008年6月3日 星期二

sk_buff->cb

閑來無事, 把 Understanding Linux Network Internals 抓來看看, 剛好看到了
sk_buff 這個恐怖的 structure. 其中有個 sk_buff->cb[64] 這個 64 bytes 的
東西, 專門拿來把一些 control information 放進去裡面的, 各層 protocol 都
可以拿來用, 但要小心別互相給蓋掉了...

看一下 definition:

include/linux/skbuff.h:

struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;
:
:
/*
* 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[64];
:
:
}

再來看一下 TCP layer 裡面有用到的部份...

include/net/tcp.h:

/* This is what the send packet queuing engine uses to pass
* TCP per-packet control information to the transmission
* code. We also store the host-order sequence numbers in
* here too. This is 36 bytes on 32-bit architectures,
* 40 bytes on 64-bit machines, if this grows please adjust
* skbuff.h:skbuff->cb[xxx] size appropriately.
*/
struct tcp_skb_cb {
union {
struct inet_skb_parm h4;
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct inet6_skb_parm h6;
#endif
} header; /* For incoming frames */
__u32 seq; /* Starting sequence number */
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
__u32 when; /* used to compute rtt's */
__u8 flags; /* TCP header flags. */

/* NOTE: These must match up to the flags byte in a
* real TCP header.
*/
:
:
__u8 sacked; /* State flags for SACK/FACK. */
:
:

__u16 urg_ptr; /* Valid w/URG flags is set. */
__u32 ack_seq; /* Sequence number ACK'd */
};

#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))

struct inet_skb_parm 是啥鬼捏?

include/net/ip.h:

struct inet_skb_parm
{
struct ip_options opt; /* Compiled IP options
unsigned char flags;
:
:
};

哇靠, 又來一個 struct ip_options...

include/linux/ip.h:

struct ip_options {
__u32 faddr; /* Saved first hop address */
unsigned char optlen;
unsigned char srr;
unsigned char rr;
unsigned char ts;
unsigned char is_setbyuser:1, /* Set by setsockopt?
is_data:1, /* Options in __data, rather th
is_strictroute:1, /* Strict source route
srr_is_hit:1, /* Packet destination addr was
is_changed:1, /* IP checksum more not valid
rr_needaddr:1, /* Need to record addr of outgo
ts_needtime:1, /* Need to record timestamp
ts_needaddr:1; /* Need to record addr of outgo
unsigned char router_alert;
unsigned char __pad1;
unsigned char __pad2;
unsigned char __data[0];
};

Total 大約會用到 36 bytes (32bit machine), or 40 bytes (64bit machine)...

事實上在 protocol layer 裡還有其他幾個地方會用到 skb->cb 的咚咚:

[MVL4 include/net]$ grep "cb\[" *
ipx.h:#define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0]))
llc_conn.h: skb->cb[sizeof(skb->cb) - 1] = type;
llc_conn.h: return skb->cb[sizeof(skb->cb) - 1];
tcp.h: * skbuff.h:skbuff->cb[xxx] size appropriately.
tcp.h:#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))


[MVL4 include/linux]$ grep "cb\[" *
if_vlan.h:#define VLAN_TX_SKB_CB(__skb) ((struct vlan_skb_tx_cookie *)&((__skb)->cb[0]))
if_vlan.h: * Puts the VLAN tag in @skb->cb[] and lets the device do the rest
if_vlan.h: * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[]
if_vlan.h: * Returns error if @skb->cb[] is not set correctly
llc.h:#define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0]))

所以盡量要使用 skb->cb[] 內容的話, 把它給擺在 cb[36] 以後吧, 反正有 64 bytes 可用...

... 這也難怪了... 先前把東西擺在 cb[0] & cb[1], 老是會不見 @_@ 唉啊, 真是沒看清楚啊~~~

沒有留言: