2015年12月25日 星期五

struct sk_buff

Linux kernel 的封包用 struct sk_buff 管理,程式碼常用 skb 表示
  • 定義:include/linux/skbuff.h
  • 取得:alloc_skb() 或 dev_alloc_skb()
  • 釋出:kfree_skb() 或 dev_kfree_skb()
一些欄位
  • struct sk_buff *next, *prev
  • head、data、tail、end:head 和 end 分別指到整個資料區塊的開頭和結束,其中有一段是封包的部份,用 data 和 tail 分別指到封包的開頭和結束。skb_pull(len) 將開頭後移 len。
  • len
  • transport_header (h)、network_header (nh)、mac_header (mac):三個 union 經過這些層時分別指到不同協定層的信頭,分別用 skb_transport_header(skb)、skb_network_header(skb) 及 skb_mac_header(skb) 取得這些指標。
  • pkt_type 封包類型:PACKET_BROADCAST、PACKET_MULTICAST、PACKET_OTHERHOST、PACKET_LOOPBCK (針對位址決定?什麼位址?)
  • prev、next、list
  • sk
  • ktime_t tstamp:收到封包的時間。net_enable_timestamp() must be called in order to get values
  • struct net_device *dev, *rx_dev
  • struct dst_entry *dst:系統決定的路由,有兩個重要的函數指標:
    • int (*input)(struct sk_buff*):可指定為 ip_local_deliver, ip_forward, ip_mr_input, ip_error 或 dst_discard_in
    • int (*output)(struct sk_buff*):可指定為 ip_output, ip_mc_output, ip_rt_bug, 或 dst_discard_out.
    一般只有一個 dst_entry。當在 IPSec 時是一個 linked list,只用最後一個來路由,其它的作為 IPSec transformers,flag 會設 DST_NOHASH。
  • data_len
  • mac_len
  • __be16 protocol:1536 以上的 EtherType、或 ETH_P_802_3、ETH_P_802_2 等其它 ETH_P_xxx 協定。
skb_shared()
  • 檢查 sk_buff 是毋是共有,就是看伊 reference count (users) 不是 1。
  • kfree_skb() 會將 reference count 減 1,在 reference count 是 0 時才會真正釋出。
  • 通常一個封包使用者用 skb_shared() 檢查是否 shared,如果是的話用 skb_clone() 複製一份,並用 kfree_skb() 將原本的 reference count 減 1。這些動作可用 skb_share_check() 完成。
    • 什麼情況需要 skb_shared() 檢查?
  • skb_clone() 是複製資料結構,封包資料仍是共用的。如果封包資料也要複製一份,則用 skb_copy();如果只是部份封包資料要複製一份,則用 pskb_copy()。
  • 大部分 reference count 是 1,什麼時候會大於 1 呢?
skb_clone()

參考來源
  1. Linux Kernel Networking by Rami Rosen at Haifux, August 2007
  2. Linux Kernel Source Codes
最後更新 20200721

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...