虛擬網絡卡 TUN TAP 驅動程式設計原理

2021-10-21 11:08:03 字數 4458 閱讀 3047

虛擬網絡卡tun/tap驅動是乙個開源專案,支援很多的類unix平台,openvpn和vtun都是基於它實現隧道包封裝。本文將介紹tun/tap驅動的使用並分析虛擬網絡卡tun/tap驅動程式在linux環境下的設計思路。

tun/tap驅動程式實現了虛擬網絡卡的功能,tun表示虛擬的是點對點裝置,tap表示虛擬的是乙太網裝置,這兩種裝置針對網路包實施不同的封裝。利用tun/tap驅動,可以將tcp/ip協議棧處理好的網路分包傳給任何乙個使用tun/tap驅動的程序,由程序重新處理後再發到物理鏈路中。開源專案openvpn( 和vtun( 都是利用tun/tap驅動實現的隧道封裝。

在linux 2.4核心版本及以後版本中,tun/tap驅動是作為系統預設預先編譯進核心中的。在使用之前,確保已經裝載了tun/tap模組並建立裝置檔案:

#modprobe tun

#mknod /dev/net/tun c 10 200

引數c表示是字元裝置, 10和200分別是主裝置號和次裝置號。

這樣,我們就可以在程式中使用該驅動了。

使用tun/tap裝置的示例程式(摘自openvpn開源專案 檔案)

int open_tun (const char *dev, char *actual, int size)

else if (!strncmp (dev, "tap", 3))

else

if (strlen (dev) > 3)      /* unit number specified? */

strncpy (ifr.ifr_name, dev, ifnamsiz);

if (ioctl (fd, tunsetiff, (void *) &ifr) < 0) //開啟虛擬網絡卡

msg (m_err, "cannot ioctl tunsetiff %s", dev);

set_nonblock (fd);

msg (m_info, "tun/tap device %s opened", ifr.ifr_name);

strncpynt (actual, ifr.ifr_name, size);

return fd;

}

呼叫上述函式後,就可以在shell命令列下使用ifconfig 命令配置虛擬網絡卡了,通過生成的字元裝置描述符,在程式中使用read和write函式就可以讀取或者傳送給虛擬的網絡卡資料了。

做為虛擬網絡卡驅動,tun/tap驅動程式的資料接收和傳送並不直接和真實網絡卡打交道,而是通過使用者態來轉交。在linux下,要實現核心態和使用者態資料的互動,有多種方式:可以通用socket建立特殊套接字,利用套接字實現資料互動;通過proc檔案系統建立檔案來進行資料互動;還可以使用裝置檔案的方式,訪問裝置檔案會呼叫裝置驅動相應的例程,裝置驅動本身就是核心態和使用者態的乙個介面,tun/tap驅動就是利用裝置檔案實現使用者態和核心態的資料互動。

從結構上來說,tun/tap驅動並不單純是實現網絡卡驅動,同時它還實現了字元裝置驅動部分。以字元裝置的方式連線使用者態和核心態。下面是示意圖:

tun/tap驅動程式中包含兩個部分,一部分是字元裝置驅動,還有一部分是網絡卡驅動部分。利用網絡卡驅動部分接收來自tcp/ip協議棧的網路分包並傳送或者反過來將接收到的網路分包傳給協議棧處理,而字元驅動部分則將網路分包在核心與使用者態之間傳送,模擬物理鏈路的資料接收和傳送。tun/tap驅動很好的實現了兩種驅動的結合。

下面是定義的tun/tap裝置結構:

struct tun_struct ;

struct net_device結構是linux核心提供的統一網路裝置結構,定義了系統統一的訪問介面。

tun/tap驅動中實現的網絡卡驅動的處理例程:

static int tun_net_open(struct net_device *dev);

static int tun_net_close(struct net_device *dev);

static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev);//資料報傳送例程

static void tun_net_mclist(struct net_device *dev);//設定多點傳輸的位址鍊錶

static struct net_device_stats *tun_net_stats(struct net_device *dev);//當乙個應用程式需要知道 網路介面的一些統計資料時,可呼叫該函式,如ifconfig、netstat等。

int tun_net_init(struct net_device *dev);//網路裝置初始例程

字元裝置部分:

在linux中,字元裝置和塊裝置統一以檔案的方式訪問,訪問它們的介面是統一的,都是使用open()函式開啟裝置檔案或普通檔案,用read()和write()函式實現讀寫檔案等等。tun/tap驅動定義的字元裝置的訪問介面如下:

static struct file_operations tun_fops = ;

在核心中利用misc_register() 函式將該驅動註冊為非標準字元裝置驅動,提供字元裝置具有的各種程式介面。**摘自linux-2.4.20\linux-2.4.20\drivers\net\tun.c

static struct miscdevice tun_miscdev=

;

int __init tun_init(void)

return 0;

}

當開啟乙個tun/tap裝置時,open 函式將呼叫tun_chr_open()函式,其中將完成一些重要的初始化過程,包括設定網絡卡驅動部分的初始化函式以及網路緩衝區鍊錶的初始化和等待佇列的初始化。tun/tap驅動中網絡卡的註冊被嵌入了字元驅動的ioctl例程中,它是通過對字元裝置檔案描述符利用自定義的ioctl設定標誌tunsetiff完成網絡卡的註冊的。下面是函式呼叫關係示意圖:

使用ioctl()函式操作字元裝置檔案描述符,將呼叫字元裝置中tun_chr_ioctl 來設定已經open好的tun/tap裝置,如果設定標誌為tunsetiff,則呼叫tun_set_iff() 函式,此函式將完成很重要的一步操作,就是對網絡卡驅動進行註冊register_netdev(&tun->dev),網絡卡驅動的各個處理例程的掛接在open操作時由tun_chr_open()函式初始化好了。

tun/tap裝置的工作過程:

tun/tap裝置提供的虛擬網絡卡驅動,從tcp/ip協議棧的角度而言,它與真實網絡卡驅動並沒有區別。從驅動程式的角度來說,它與真實網絡卡的不同表現在tun/tap裝置獲取的資料不是來自物理鏈路,而是來自使用者區,tun/tap裝置驅動通過字元裝置檔案來實現資料從使用者區的獲取。傳送資料時tun/tap裝置也不是傳送到物理鏈路,而是通過字元裝置傳送至使用者區,再由使用者區程式通過其他渠道傳送。

傳送過程:

使用tun/tap網絡卡的程式經過協議棧把資料傳送給驅動程式,驅動程式呼叫註冊好的hard_start_xmit函式傳送,hard_start_xmit函式又會呼叫tun_net_xmit函式,其中skb將會被加入skb鍊錶,然後喚醒被阻塞的使用tun/tap裝置字元驅動讀資料的程序,接著tun/tap裝置的字元驅動部分呼叫其tun_chr_read()過程讀取skb鍊錶,並將每乙個讀到的skb發往使用者區,完成虛擬網絡卡的資料傳送。

接收資料的過程:

當我們使用write()系統呼叫向tun/tap裝置的字元裝置檔案寫入資料時,tun_chr_write函式將被呼叫,它使用tun_get_user從使用者區接受資料,其中將資料存入skb中,然後呼叫關鍵的函式netif_rx(skb) 將skb送給tcp/ip協議棧處理,完成虛擬網絡卡的資料接收。

相關主題

虛擬網絡卡 TUN TAP 驅動程式設計原理

http www.ibm.com developerworks cn linux l tuntap index.html 簡介 虛擬網絡卡tun tap驅動是乙個開源專案,支援很多的類unix平台,openvpn和vtun都是基於它實現隧道包封裝。本文將介紹tun tap驅動的使用並分析虛擬網絡卡t...

虛擬網絡卡TUN TAP驅動程式設計原理

虛擬網絡卡tun tap驅動是乙個開源專案,支援很多的類unix平台,openvpn和vtun都是基於它實現隧道包封裝。本文將介紹tun tap驅動的使用並分析虛擬網絡卡tun tap驅動程式在linux環境下的設計思路。tun tap 驅動程式實現了虛擬網絡卡的功能,tun表示虛擬的是點對點裝置,...

虛擬網絡卡 TUN TAP 驅動程式設計原理

虛擬網絡卡tun tap驅動是乙個開源專案,支援很多的類unix平台,openvpn和vtun都是基於它實現隧道包封裝。本文將介紹tun tap驅動的使用並分析虛擬網絡卡tun tap驅動程式在linux環境下的設計思路。tun tap 驅動程式實現了虛擬網絡卡的功能,tun表示虛擬的是點對點裝置,...