1. 程式人生 > >struct net_device網路裝置結構體詳解

struct net_device網路裝置結構體詳解

在linux中使用struct net_device結構體來描述每一個網路裝置。同時這個用來刻畫網路裝置的struct net_device結構體包含的欄位非常的多,以至於核心的開發者都覺得在現在的linux核心中,這個struct net_device是一個大的錯誤。
在本篇文章中,只介紹struct net_device中的一些欄位,其他的欄位在以後使用的時候再說。

#define IFNAMSIZ 32
   struct net_device
   {
       //用於存放網路裝置的裝置名稱;
       char name[IFNAMSIZ];

       //網路裝置的別名;
char *ifalias; //網路裝置的介面索引值,獨一無二的網路裝置識別符號; int ifindex; //這個欄位用於構建網路裝置名的雜湊散列表,而struct net中的 //name_hlist就指向每個雜湊散列表的連結串列頭; struct hlist_node name_hlist; //用於構建網路裝置的介面索引值雜湊散列表,在struct net中的 //index_hlist用於指向介面索引值雜湊散列表的連結串列頭; struct hlist_node index_hlist; //用於將每一個網路裝置加入到一個網路名稱空間中的網路裝置雙鏈表中
struct list_head dev_list; //網路裝置介面的識別符號,其狀態型別被定義在<linux/if.h>之中; unsigned int flags; //網路裝置介面的識別符號,但對使用者空間不可見; unsigned short priv_flags; //介面硬體型別,在<if_arp.h>中定義了每一個介面硬體型別; unsigned short type; //網路裝置介面的最大傳輸單元; unsigned mtu; //硬體介面頭長度;
unsigned short hard_header_len; //網路裝置介面的MAC地址; unsigned char *dev_addr; //網路裝置介面的單播模式 int uc_promisc; //網路裝置介面的混雜模式; unsigned int promiscuity; //網路裝置介面的全組播模式; unsigend int allmulti; //secondary unicast mac address struct netdev_hw_addr_list uc; //list of device hw address; struct netdev_hw_addr_list dev_addrs; //hw broadcast address; unsigned char broadcast[MAX_ADDR_LEN]; //multicast mac address; struct dev_addr_list *mac_list; //網路裝置介面的資料包接收佇列; struct netdev_queue rx_queue; //網路裝置介面的資料包傳送佇列; struct netdev_queue *tx; //Number of TX queues allocated at alloc_netdev_mq() time unsigned int num_tx_queues; //Number of TX queues currently active in device; unsigned int real_num_tx_queues; //Max frame per queue allowned; unsigned long tx_queue_len; //網路裝置介面的狀態; unsigned long state; //網路裝置介面的統計情況; struct net_device_state states; //用於執行網路裝置所在的名稱空間; struct net *nd_net; }

下面的這幅圖用於展示linux核心如何利用struct net和struct net_device來構成一個網路名稱空間:
這裡寫圖片描述

1.分配一個網路裝置函式,即分配一個struct net_device結構體:alloc_netdev(sizeof_priv, name, setup);

這個alloc_netdev()函式本質上是一個巨集定義:

    #define alloc_netdev(sizeof_priv, name, setup) \
 alloc_netdev_mq(sizeof_priv, name, setup, 1)

struct net_device *alloc_netdev_mq(int sizeof_priv,
    const char *name, void(*setup)(struct net_device*),
    unsigned int queue_count)
 EXPORT_SYMBOL(alloc_netdev_mq)  

引數介紹:
- sizeof_priv:為分配給網路裝置私有空間的大小;
- name :網路裝置的名稱;
- setup:對分配的網路裝置進行初始化的回撥函式;
- queue_count:分配給網路裝置的子佇列數;

struct net_device *alloc_netdev_mq( int sizeof_priv, const char *name, 
            void (*setup)( struct net_device *), unsigned int queue_count )
{
       struct net_device *dev ;

       struct netdev_queue *tx ;

       int alloc_size ;

       alloc_size  = sizeof(struct net_device);

       dev = kzalloc(alloc_size, GFP_KERNEL);

       tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);

       dev_addr_init(dev);//對struct net_device中的dev_addrs成員進行初始化;

       dev_unicast_init(dev); //對struct net_device中的uc成員進行初始化; 

       dev_net_set(dev, &init_net);//對網路裝置的名稱空間進行初始化,預設為init_net;

       dev->_tx = tx ;//設定網路裝置的傳送佇列;
       dev->num_tx_queues = queue_count ;
       dev->real_num_tx_queues = queue_count ;

       netdev_init_queues(dev);//對struct net_device中的rx_queue成員進行初始化;

       setup(dev); //對struct net_device結構體進行初始化;

       strcpy(dev->name, name);//設定網路裝置的裝置名稱;   

}

EXPORT_SYMBOL(alloc_netdev_mq);

2.釋放一個網路裝置:

void free_netdev(struct net_device *dev);
EXPORT_SYMBOL(free_netdev);

3.註冊一個網路裝置,只有對一個網路裝置進行註冊以後,這個網路裝置才會在核心中起作用:

 int register_netdev(struct net_device *dev)
EXPORT_SYMBOL(register_netdev);   

返回值:
- 0:表示註冊成功;
- a negative errno code :表示註冊失敗;

int register_netdev(struct net_device *dev)
{
    struct hlist_head *head;
    struct hlist_node *p;
    int ret;
    struct net *net = dev_net(dev); // 獲取網路裝置所在的名稱空間;
    rtnl_lock();//獲取rtnl訊號量;

    if(!dev_valid_name(dev->name)) //判斷網路裝置的裝置名是否有效;
    {}  

    dev->ifindex = dev_new_index(net); //從網路裝置所在的名稱空間中找到一個全域性唯一的網路
                                       //介面索引值;
    dev->iflink = dev->ifindex ;

    //用於判斷網路名稱空間中是否有相同名字的網路裝置存在;
    head = dev_name_hash(net, dev->name);
    hlist_for_each(p,head)
    {
       struct net_device *d = hlist_entry(p, struct net_device, name_hlist);
       if(!strncmp(d->name, dev->name, 32))
          {
             ret = -EEXIST ;
          }
    }

    set_bit(__LINK_STATE_PRESENT, &dev->state);//設定網路裝置的狀態;
    list_netdevice(dev); //將網路裝置叫入到相應的名稱空間之中;
}
EXPORT_SYMBOL(register_netdev);

3.登出一個網路裝置結構體:

void unregister_netdev(struct net_device *dev);
EXPORT_SYMBOL(unregister_netdev);

4.設定一個網路裝置的MAC地址:

int dev_set_mac_address(struct net_device *dev, 
                    struct sockaddr *sa);
EXPORT_SYMBOL(dev_set_mac_address);

5.設定一個網路裝置的最大傳輸單元:

int dev_set_mtu(struct net_device *dev, int new_mtu);
EXPORT_SYMBOL(dev_set_mtu);

6.改變一個網路裝置的flag識別符號:

int dev_change_flags(struct net_device *dev, unsigend flags);
EXPORT_SYMBOL(dev_change_flags);

7.獲取一個網路裝置的flag識別符號:

unsigned dev_get_flags(struct net_device *dev);
EXPORT_SYMBOL(dev_get_flags);

8.給網路裝置新增一個單播MAC地址,當網路裝置在傳送單播時使用單播MAC地址

int dev_unicast_add(struct net_device *dev, void *addr);
EXPORT_SYMBOL(dev_unicast_add);

9.刪除網路裝置中的單播MAC地址:

int dev_unicast_delete(struct net_device *dev, void *addr);
EXPORT_SYMBOL(dev_unicast_delete);

10.給網路裝置新增一個裝置地址:

int dev_addr_add(struct net_device *dev, unsigned char *addr,
                  unsigned char addr_type)
EXPORT_SYMBOL(dev_addr_add);
addr_type : address type;

11.刪除網路裝置中的一個裝置地址:

int dev_addr_del(struct net_device *dev, unsigend char *addr,
                  unsigned char addr_type);
EXPORT_SYMBOL(dev_addr_del);

12.設定網路裝置的介面為混雜模式:

 int dev_set_promiscuity(struct net_device *dev, int inc);
 EXPORT_SYMBOL(dev_set_promiscuity);

當 inc > 0 將網路裝置設定為混雜模式;
當 inc = 0 將網路裝置設定為正常模式;
當 inc < 0 將去掉網路裝置的混雜模式;

13.設定網路裝置的介面為allmulticast模式:

 int dev_set_allmulti(struct net_device *dev, int inc);
 EXPORT_SYMBOL(dev_set_allmulti);
 inc 含義同上;

14.在給一個網路裝置的裝置名稱進行賦值時,先要檢測這個名字是否有效:

 int dev_valid_name(const char *name);
 EXPORT_SYMBOL(dev_valid_name);

返回:
1 :表示有效;
0 :表示無效;

15.通過裝置的MAC地址以及裝置型別來獲取網路裝置的裝置結構體:

  struct net_device *dev_getbyhwaddr(struct net *net,
              unsigned short type, char *hwaddr);
 EXPORT_SYMBOL(dev_getbyhwaddr);

net : 網路名稱空間;
type: media type of device;
hwaddr:hardware address;
通過memcmp(dev->dev_addr, hwaddr, dev->addr_len)來實現;

16.通過網路裝置的介面索引值來獲取網路裝置結構體:

 struct net_device *dev_get_by_index(struct net *net, int ifindex);
 EXPORT_SYMBOL(dev_get_by_index);

17.通過網路裝置的裝置名來獲取網路裝置結構體:

struct net_device *dev_get_by_name(struct net *net, const char *name);
  EXPORT_SYMBOL(dev_get_by_name);

以上所介紹的所有函式位於/net/core/dev.c之中;