Linux 網絡子系統


今天記錄一下Linux網絡子系統相關的東西。

因為感覺對這一塊還是有一個很大的空白,這件事情太可怕了。

摘抄多份博客進行總結一下Linux網絡子系統的相關東西。

一. Linux網絡子系統體系結構

  Linux 網絡體系結構由如下圖抽象的形容一下

1 . 用戶空間:-----> 應用層

2 . 內核空間:-----> 系統調用接口: 主要指socket 系統調用

       -----> 協議無關接口: 實現一組基於socket的通用函數訪問各種不同的協議

       -----> 網絡協議:   udp, tcp 協議

       -----> 設備無關接口: 將協議與各種網絡設備驅動連接在一起。

       -----> 設備驅動:   網絡體系結構的最底層部分是負責管理物理網絡設備的設備驅動層

3 . 硬件: 網絡物理設備。

    從上往下,形成Linux網絡子系統。

二. 重要的頭文件以及數據結構介紹

    重要的頭文件:include/linux/netdevice.h

    這里面有個網絡子系統的核心數據結構:net_device

net_device

        這里面包含了網絡設備的各種屬性,主要有如下重要屬性:
struct net_device
{
     char   name[IFNAMSIZ];
     // 這是設備的名稱,包含一個%d格式串,設備注冊時,
     // 用一個數替換它形成一個新的名稱,分配的編號從零開始
                    
     //...
     unsigned long       state;
     //記錄了設備的狀態,是否激活是否是有效是否沒有載波等等

     unsigned int        irq;
     /* device IRQ number  中斷號  */ 
     unsigned int        mtu;
     /* interface MTU value  最大傳輸單元,默認1500   */ 
               unsigned char       *dev_addr;  
     /* hw address, (before bcast                
               because most packets are                             
               unicast) */       
     //......還有很多相關的屬性。       
     //關於網絡設備的操作結構體
     const struct net_device_ops *netdev_ops;
     const struct ethtool_ops *ethtool_ops;
     
}
#define alloc_netdev(sizeof_priv, name, setup) \
          alloc_netdev_mqs(sizeof_priv, name, setup, 1, 1)\
         /*  分配一個net_device結構體可以用上面這個宏函數進行分配   
                其實最終調用是調用了alloc_netdev_mqs 函數*/
         /*  其中,參數sizeof_priv 表示網卡設備的私有數據大小,
                name指定網卡設備名稱,setup指定網卡設備初始化回調函數  */ 
   

//對於不同的網卡設備,kernel提供了更直接的分配函數,
//例如以太網卡,可用用下面的宏函數進行分配:
//include/linux/etherdevice.h     
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)           
#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)
//其實最終調用是alloc_etherdev_mqs


//....
//其實這個函數只是做了簡單的封裝  net/ethernet/eth.c
struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,       
                      unsigned int rxqs)                                        
{                                                                               
    return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs);     
}                                                                               
EXPORT_SYMBOL(alloc_etherdev_mqs);                                              
//最終調用還是alloc_netdev_mqs 只不過名字是eth開頭,%d會在后面解析出來。


//.......
//ether_setup 函數,以太網初始化函數    net/ethernet/eth.c
/**                                                                             
 * ether_setup - setup Ethernet network device                                  
 * @dev: network device                                                         
 * Fill in the fields of the device structure with Ethernet-generic values.     
 */                                                                           
void ether_setup(struct net_device *dev)                                        
{                                                                               
    dev->header_ops     = &eth_header_ops;                                      
    dev->type       = ARPHRD_ETHER;                                             
    dev->hard_header_len    = ETH_HLEN;                                         
    dev->mtu        = ETH_DATA_LEN;                                             
    dev->addr_len       = ETH_ALEN;                                             
    dev->tx_queue_len   = 1000; /* Ethernet wants good queues */                
    dev->flags      = IFF_BROADCAST|IFF_MULTICAST;                              
    dev->priv_flags     |= IFF_TX_SKB_SHARING;                                  
                                                                                
    memset(dev->broadcast, 0xFF, ETH_ALEN);                                     
                                                                                
}                                                                               
EXPORT_SYMBOL(ether_setup);                                                     





struct net_device_ops

    和字符設備有一定的相似之處,網絡設備也有相關的操作函數。
    他包含在net_device 結構體中的struct net_device_ops。
    他的原型如下:
struct net_device_ops {                                                         
    int         (*ndo_init)(struct net_device *dev);
                /* 該函數將在設備注冊時,
                調用(即調用register_netdev()時)來做一些基本的初始化工作。 */                            
    void        (*ndo_uninit)(struct net_device *dev);                      
    int         (*ndo_open)(struct net_device *dev);
                /* 該函數在網絡設備被激活變為up狀態時被調用  */                            
    int         (*ndo_stop)(struct net_device *dev);
                /* 變為down狀態時被調用  */                            
    netdev_tx_t     (*ndo_start_xmit) (struct sk_buff *skb,                     
                           struct net_device *dev);
                    /* 當上層協議需要發送數據時,調用該函數
                    需要返回NETDEV_TX_OK 或NET_TX_BUSY來確認結果 */                             
    u16             (*ndo_select_queue)(struct net_device *dev,                     
                            struct sk_buff *skb);  
                    /* 呼叫然后決定哪個隊列當設備支持多重傳輸隊列的時候 */                             
    void            (*ndo_change_rx_flags)(struct net_device *dev,              
                               int flags);
                    /* 調用這個函數允許設備接收器更改配置當運行多路傳輸的時候  */                                      
    void            (*ndo_set_rx_mode)(struct net_device *dev);
                    /* 當調用這個函數改變地址過濾
                    如果驅動沒有設置地址過濾,那個這個標志要設置為IFF_UNICAST_FLT    */
    int             (*ndo_set_mac_address)(struct net_device *dev,                  
                               void *addr);
                    /* 調用設置MAC地址  */                                     
    int             (*ndo_validate_addr)(struct net_device *dev);
                    /* 測試多媒體訪問地址是否有效   */                 
    int             (*ndo_do_ioctl)(struct net_device *dev,                         
                            struct ifreq *ifr, int cmd);  
                    /* 當用戶請求一個ioctl,如果ioctl沒有相對應的接口函數,則返回not supported error code    */                     
    int             (*ndo_set_config)(struct net_device *dev,                       
                              struct ifmap *map);                               
                    /* 用它設置網絡設備總線接口參數
                    保留這個接口的原因是因為新的設備要用PCI為了低水平的管理*/
    int             (*ndo_change_mtu)(struct net_device *dev,                       
                          int new_mtu); 
                    /*  使用這個函數該表最大傳輸單元,
                    如果沒有定義,那么任何請求改變MTU的請求都會報錯 */         
    int             (*ndo_neigh_setup)(struct net_device *dev,                      
                           struct neigh_parms *);
                                                   
    void            (*ndo_tx_timeout) (struct net_device *dev);                 
                    /* 當傳送器沒有任何操作超時調用   */                                                           
    struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,        
                             struct rtnl_link_stats64 *storage);                
    struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); 
                    /*  上面兩個函數必須定義其中一個,這是用戶想獲取幫助的所調用的 */         
                                                                                
    void            (*ndo_vlan_rx_add_vid)(struct net_device *dev,              
                               unsigned short vid);  
                    /* 當設備支持VLAN過濾的時候,這個函數在一個VLAN ID 被注冊時候調用  */       
    void            (*ndo_vlan_rx_kill_vid)(struct net_device *dev,             
                                unsigned short vid);                     
                    /* 當設備支持VLAN過濾的時候,這個函數在一個VLAN ID 被注銷時候調用   */       
#ifdef CONFIG_NET_POLL_CONTROLLER                                       
    void            (*ndo_poll_controller)(struct net_device *dev);
                      
    int             (*ndo_netpoll_setup)(struct net_device *dev,                    
                             struct netpoll_info *info);                        
    void            (*ndo_netpoll_cleanup)(struct net_device *dev);             
#endif                  
                /* SR-IOV management functions */                                                           
    int         (*ndo_set_vf_mac)(struct net_device *dev,                       
                          int queue, u8 *mac);                                  
    int         (*ndo_set_vf_vlan)(struct net_device *dev,                      
                           int queue, u16 vlan, u8 qos);                        
    int         (*ndo_set_vf_tx_rate)(struct net_device *dev,                   
                              int vf, int rate);                                
    int         (*ndo_set_vf_spoofchk)(struct net_device *dev,                  
                               int vf, bool setting);                           
    int         (*ndo_get_vf_config)(struct net_device *dev,                    
                             int vf,                                            
                             struct ifla_vf_info *ivf);                         
    int         (*ndo_set_vf_port)(struct net_device *dev,                      
                           int vf,                                              
                           struct nlattr *port[]);                              
    int         (*ndo_get_vf_port)(struct net_device *dev,                      
                           int vf, struct sk_buff *skb);                        
    int         (*ndo_setup_tc)(struct net_device *dev, u8 tc); 
                /*  調用這個函數設置tc 數字關於net設備的傳輸類別 
                        這個允許網絡設備安全的管理隊列  */                
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)                         
    int         (*ndo_fcoe_enable)(struct net_device *dev); 
                /*  當FCoE協議棧使用LLD,所以下面的設備需要配置或者初始化關於FCoE傳輸的加速。
                    這時就調用這個函數  */                    
    int         (*ndo_fcoe_disable)(struct net_device *dev);
                /*  與上面那個函數剛好相反  */
                /*   .........*/
    int         (*ndo_fcoe_ddp_setup)(struct net_device *dev,                   
                              u16 xid,                                          
                              struct scatterlist *sgl , unsigned int sgc);
                /*  當FCoE初始化想初始一個IO因為有個可能的候選人為直接的數據放置,成功在這個IO執行PPD這個函數返回1, 失敗返回0  */                          
    int         (*ndo_fcoe_ddp_done)(struct net_device *dev,                    
                             u16 xid);          
                /*  當FCoE目標已經完成,這時候要釋放這個資源以便下次請求這個資源   */              
    int         (*ndo_fcoe_ddp_target)(struct net_device *dev,                  
                               u16 xid,                                         
                               struct scatterlist *sgl,                         
                               unsigned int sgc);                               

#endif                                                                          
                                                                                
#if defined(CONFIG_LIBFCOE) || defined(CONFIG_LIBFCOE_MODULE)                   
#define NETDEV_FCOE_WWNN 0                                                      
#define NETDEV_FCOE_WWPN 1                                                      
    int         (*ndo_fcoe_get_wwn)(struct net_device *dev,                     
                            u64 *wwn, int type);                                
#endif                                                                          
                                                                                
#ifdef CONFIG_RFS_ACCEL                                                         
    int         (*ndo_rx_flow_steer)(struct net_device *dev,                    
                             const struct sk_buff *skb,                         
                             u16 rxq_index,                                     
                             u32 flow_id); 
                 /* 設置硬件過濾為RFS */                                     
#endif                                                                          
    int         (*ndo_add_slave)(struct net_device *dev,                        
                         struct net_device *slave_dev);
                 /* 添加一個網絡設備的從設備 */        
    int         (*ndo_del_slave)(struct net_device *dev,                        
                         struct net_device *slave_dev);
                 /* 刪除  */                         
    u32         (*ndo_fix_features)(struct net_device *dev,                     
                            u32 features);
                 /* 調整請求特征標志通過設備專用的 約束,返回標志結果,不能改變設備的狀態*/                                      
    int         (*ndo_set_features)(struct net_device *dev,                     
                            u32 features);  
                 /* 升級設備新的配置   */                                    
};                                                                              

                              

sk_buff

    sk_buff 在include/linux/skbuff.h 里面被聲明
/**                                                                             
 *  struct sk_buff - socket buffer                                              
 *  @next: Next buffer in list                                                  
 *  @prev: Previous buffer in list                                              
 *  @tstamp: Time we arrived                                                    
 *  @sk: Socket we are owned by                                                 
 *  @dev: Device we arrived on/are leaving by                                   
 *  @cb: Control buffer. Free for use by every layer. Put private vars here     
 *  @_skb_refdst: destination entry (with norefcount bit)                       
 *  @sp: the security path, used for xfrm                                       
 *  @len: Length of actual data                                                 
 *  @data_len: Data length                                                      
 *  @mac_len: Length of link layer header                                       
 *  @hdr_len: writable header length of cloned skb                              
 *  @csum: Checksum (must include start/offset pair)                            
 *  @csum_start: Offset from skb->head where checksumming should start          
 *  @csum_offset: Offset from csum_start where checksum should be stored        
 *  @priority: Packet queueing priority                                         
 *  @local_df: allow local fragmentation                                        
 *  @cloned: Head may be cloned (check refcnt to be sure)                       
 *  @ip_summed: Driver fed us an IP checksum                                    
 *  @nohdr: Payload reference only, must not modify header                      
 *  @nfctinfo: Relationship of this skb to the connection                       
 *  @pkt_type: Packet class                                                     
 *  @fclone: skbuff clone status                                                
 *  @ipvs_property: skbuff is owned by ipvs                                     
 *  @peeked: this packet has been seen already, so stats have been              
 *      done for it, don't do them again                                        
 *  @nf_trace: netfilter packet trace flag                                      
 *  @protocol: Packet protocol from driver                                      
 *  @destructor: Destruct function                                              
 *  @nfct: Associated connection, if any                                        
 *  @nfct_reasm: netfilter conntrack re-assembly pointer                        
 *  @nf_bridge: Saved data about a bridged frame - see br_netfilter.c           
 *  @skb_iif: ifindex of device we arrived on                                   
 *  @tc_index: Traffic control index                                            
 *  @tc_verd: traffic control verdict                                           
 *  @rxhash: the packet hash computed on receive                                
 *  @queue_mapping: Queue mapping for multiqueue devices                        
 *  @ndisc_nodetype: router type (from link layer)                              
 *  @ooo_okay: allow the mapping of a socket to a queue to be changed           
  *  @ndisc_nodetype: router type (from link layer)                              
 *  @ooo_okay: allow the mapping of a socket to a queue to be changed           
 *  @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport      
 *      ports.                                                                  
 *  @dma_cookie: a cookie to one of several possible DMA operations             
 *      done by skb DMA functions                                               
 *  @secmark: security marking                                                  
 *  @mark: Generic packet mark                                                  
 *  @dropcount: total number of sk_receive_queue overflows                      
 *  @vlan_tci: vlan tag control information                                     
 *  @transport_header: Transport layer header                                   
 *  @network_header: Network layer header                                       
 *  @mac_header: Link layer header                                              
 *  @tail: Tail pointer                                                         
 *  @end: End pointer                                                           
 *  @head: Head of buffer                                                       
 *  @data: Data head pointer                                                    
 *  @truesize: Buffer size                                                      
 *  @users: User count - see {datagram,tcp}.c                                   
 */

//這個結構體里面所有的成員如上注釋 
//其中重要的有如下幾個着重解釋一下:
struct sk_buff 
{                                                                
    /* These two members must be first. */                                      
    struct sk_buff      *next;         /* 指向下一個的sk_buff  */                                         
    struct sk_buff      *prev;         /* 指向前一個的sk_buff  */                                  

    struct sock *sk;                   /*  該sk_buff 擁有的套接字   */
    struct net_device  *dev;           /*  處理該包的設備 */
    
    __be16          protocol;          /*  該包所屬的協議類型  */
    unsigned int        len,                                                    
                data_len;              /*  有效數據的長度以及數據總長度   */
    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;                         /* 有效數據的開始 */                                                 
                                                                                  
}
//sk_buff中定義了4個指向數據包緩沖區不同位置的指針head、data、tail、end、
//.......
//sk_buff 的基本操作函數

static inline struct sk_buff *__dev_alloc_skb(unsigned int length,   <-------------|          
                          gfp_t gfp_mask)                                          | 
{                                                                                  | 
    struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask);  ---          | 
    if (likely(skb))                                                    |          | 
        skb_reserve(skb, NET_SKB_PAD);                                  |          | 
    return skb;                                                         |          | 
}                                                                       |          | 
                                                                        |          | 
extern struct sk_buff *dev_alloc_skb(unsigned int length);              |          |     
/*                                                                      |          |               
struct sk_buff *dev_alloc_skb(unsigned int length)     //最開始位置     |          | 
{                                                                       |          |                                     
     * There is more code here than it seems:                           |          | 
     * __dev_alloc_skb is an inline                                     |          |                               
     */                                                                 |          |                   
    return __dev_alloc_skb(length, GFP_ATOMIC);    --------------------------------                     |                                     
}                                                                       |                                                                         
EXPORT_SYMBOL(dev_alloc_skb);                                           |          
*/              |                                                       |   
                                                                        |         
extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev,       |         
        unsigned int length, gfp_t gfp_mask);                           |         
                                                                        | 
                                                                        | 
                                                                        | 
extern struct sk_buff *__alloc_skb(unsigned int size,                   |         
                   gfp_t priority, int fclone, int node);               |         
static inline struct sk_buff *alloc_skb(unsigned int size,    <—————             
                    gfp_t priority)                                             
{                                                                               
    return __alloc_skb(size, priority, 0, NUMA_NO_NODE);  -----                      
}                                                              |                 
//最終調用__alloc_skb進行申請一個sk_buff結構體                 |
//他的函數原型在net/core/skbuff.c                              |
/**                                                            |                 
 *  __alloc_skb -   allocate a network buffer     <____________|                             
 *  @size: size to allocate     長度                                                
 *  @gfp_mask: allocation mask  掩碼                                             
 *  @fclone: allocate from fclone cache instead of head cache                   
 *      and allocate a cloned (child) skb                                       
 *  @node: numa node to allocate memory on                                      
 *                                                                              
 *  Allocate a new &sk_buff. The returned buffer has no headroom and a          
 *  tail room of size bytes. The object has a reference count of one.           
 *  The return is the buffer. On a failure the return is %NULL.                 
 *                                                                              
 *  Buffers may only be allocated from interrupts using a @gfp_mask of          
 *  %GFP_ATOMIC.                                                                
 */                                                                             
struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,                  
                int fclone, int node)
{
//......
}                                           


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM