第二章 背景知識介紹
2.1 核心程式與使用者程式間的行程通訊機制
Linux 作業系統透過權限做管理,將作業系統化分為 kernel-space 與 user space,這兩者間最大的差異即是 user-space 程式無法直接存取到 kernel-space 的 記憶體[1]。主要的原因就在於作業系統對運行於 kernel-space 的程式做保護。簡 而言之,kernel-space 的程式具有較高的權限,而 user-space 的程式則具有較低 的權限。但是,兩者之間還是存在有適當的通訊機制可以用來做溝通與管理。 static int myioctl (structinode*inode, structfile*file, unsigned int cmd,
ulong arg)
static struct file_operations my_fops = {
owner: THIS_MODULE, ioctl : myioctl, };
static devfs_handle_t devfs_handle;
static int __init my_init(void) {
int ret;
ret = register_chrdev(“my_ioctl”, &my_fops);
return 0;
}
能在使用者程式當中,調用驅動程式中的 ioctl 函數。
int main(int argc, char*argv[]) {
static struct proc_dir_entry *proc_ func = NULL;
static int read_func_state (char* page, char **start, off_t offset, int count,int *eof, void *data)
{
static int __init my_init(void) {
proc_ func = create_proc_entry("mydebug", 0644,NULL);
if (proc_func) {
proc_func->read_proc = my_read;
} }
# cat /proc/mydebug
# This is linux kernel.
#
#
做緩存,這個多餘的拷貝動作會浪廢許多 CPU 資源。
MMAP (Memory MAP)記憶體映射機制,是 Linux 上一種非常有趣的功能,
主要是透過「shared file」來做訊息的資料傳遞,在程式當中將檔案 mapping 到 自己的記憶體空間(process address space)時,mmap system call 便會建立相對 應的 VMA[4] 區段;觀念上來說,只要透過 mmap system call 將檔案 mapping 到記憶體,便會產生對應的 VMA 區段。VMA (Virtal Memory Area) 主要是為 了讓 Linux 能夠有效率地管理記憶體,而從 paging 系統發展而來。VMA 可以讓 Linux 以 process 的角度來管理虛擬位址空間,有可能執行記憶體需求超過可用 實體記憶體的應用程式。而將 shared file mapping 到 process address space 的 system call 為 'mmap()'。
此種方法也可被應用來提供使用者程式直接存取裝置記憶體(device memory) 的能力,讓行程可以共用一個程式庫或記憶體區塊。以下是其中一個簡單的範 例:
Table 2-5 使用者程式使用 MMAP 範例 void main (void)
{
int RxCount = 0, TxCount = 0, mfd = -1;
size_t size = BUFFERSIZE; /* 2MB */
char * mptr;
mfd = open("/dev/bridge", O_RDWR | O_SYNC);
mptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, mfd, 0);
memcpy (&RxCount,mptr,2);
memcpy (&TxCount,mptr+2,2);
}
Table 2-6 註冊 MMAP 函數至檔案操作元
使用 MMAP,除了在使用者程式中必須呼叫記憶體映射的 API 之外,在裝置 驅動程式上也必須對檔案操作結構中的 MMAP 指標做註冊的動作。
Table 2-7 MMAP 函數原型
addr 參數提供給 Linux Kernel 最佳的檔案對應位址,用以告訴 Linux Kernel 從那個起始位址開始映射檔案。一般情況都是填 ’0’ ,此函數將回傳指向映射 區域的真實起始位址。
len 參數表示欲映射多少 Byte 的記憶體長度。
port 參數描述用何種方式來對映射區域做記憶體保護,MMAP 提供如下幾種 記憶體保護機制:
PROT_EXEC – 分頁記憶體可被執行 PROT_READ - 分頁記憶體可被讀取。
PROT_WRITE - 分頁記憶體可被寫入。
PROT_NONE - 分頁記憶體不可被存取。
flag 參數用來描述檔案對應的類型,MMAP 提供如下幾種記憶體映射方式:
MAP_FIXED - 強制 mmap( ) 要遵守 addr 的設定,如果無法對應至該位 struct file_operations my_fops = {
.mmap = my_mmap, };
static int my_mmap(struct file * filp, struct vm_area_struct * vma) {
int ret = remap_pfn_range(vma, vma->vm_start,
virt_to_phys((void*)((ulong) buffer_area)) >> PAGE_SHIFT, vma->vm end-vma->vm start, PAGE SHARED);
#include <sys/mman.h>
void * mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
址,則呼叫失敗。
MAP_SHARED – 當指定為以 MAP_SHARED 作映射時,則使用者程式對映 射記憶體的改動將會使的被映射到的實體記憶體內容,一 併被修改。
MAP_PRIVATE -當指定為以 MAP_ PRIVATE 作映射時,程式間的對應狀態 無法分享,該檔案會對應至一個副本,使用者程式對映射 記憶體的改動將不會更動到實體記憶體內容,
fd 參數指到欲映射的檔案。
offset 參數一般設為 0,表示從檔頭開始映射。
當使用者程式將實體記憶體 mapping 到虛擬記憶體空間(Process address space)時,mmap system call 便會建立起相對應的 VMA 區段。
Figure 2-1 觀察使用者程式內的虛擬記憶體區段配置
採用 MMAP 做行程通訊的一個顯而易見的好處是效率高,因為使用者程式 可以直接讀寫核心程式所配置的記憶體,而不需要做任何資料的拷貝。對於像 IOCTL 或 /PROC 檔案系統等方式在做行程通訊時,皆須將資料寫入共享記憶 體,然後才能將資料從共享記憶體讀出或寫入目的記憶體,這樣的拷貝動作會 影響到系統效能,所以 MMAP 會比較滿足本論文的需求。
Netlink Socket 訊息交換機制,Netlink 是 Linux 作業系統上一種特有的使用者
空間與核心空間的訊息交換機制。類似於 BSD 中的 AF_RUTE,目前的 Linux Kernel 使用 netlink 的範圍很廣,包括 Routing,Firewall,Netfilter,IPSec …等 等,都有使用 netlink 來和使用者程式做互動。Netlink 是一種在 kernel space 與 user space 之間進行雙向資料傳輸非常好的方式,使用者只要使用標準的 socket API 就可以使用 netlink 提供的強大功能,Kernel 則需要使用專門的內核 API 來使用 netlink。
相較於 IOCTL 以及 /PROC 而言,netlink 具備的優點如下:
(1)可以發送 Broadcast packet 給不同的使用者行程。
(2)Kernel 可以使用 netlink 首先發起對話,但 IOCTL 以及/PROC 只能由使 用者程式發起調用。
(3)使用方便,用戶僅需要在 include/linux/netlink.h 中增加一個新的 netlink 協定定義即可,核心程式和用戶程式就可以立即通過 socket API 使用該 netlink 協定類型進行資料交換。
2.2 Libpcap 封包截取函數庫
libpcap 是 unix/linux/Solaris/BSD/Mac OS X/HP-UX 平臺下的封包截取函式 庫,libpcap 是由 Lawrence Berkeley National Laboratory (LBNL) 所開發而成的封 包 截 取 函 數 庫 。 目 前 市 面 上 大 多 數 網 路 監 控 軟 體 都 是 以 它 為 基 礎 。 如 : TCPDUMP、Ethereal、Wireshark[5]、Sniffer[6] …等等。主要是因為 Libpcap 可 以在絕大多數的 Linux/Unix 平臺下工作,簡單、容易使用也是它之所以被廣泛 採用的原因。
本論文即是使用此函數庫,來對進出 Linux 作業系統的 Ethernet 封包作攔截 與過濾,再搭配上客制化的 Protocol Analyzer,即可對 IEEE 802.3/802.11 的封包 內容做解析,以提供使用者從 Layer 2 至 Layer 7 重要的參考資訊。
Libpcap 0.9.8 目前版本提供了 20 多個 API 函數,利用這些 API 函數即可完 成本論文中封包截取工具所需要的網路封包監聽功能。
2.3 PTHREAD 執行緒
在 Linux 作業系統上,執行緒被用來解決多工與獨立運作的問題。在目前的 Linux 版本當中,最常被使用的執行緒函數庫為符合 POSIX 1003.1c 執行緒標準 的 Pthreads 執行緒程式庫。POSIX 1003.1c 執行緒標準是由 IEEE 作業系統技術 委員會於 1995 年所訂定而成的,在這個程式庫中的函數都是以 pthread 字串開 頭。如:pthread_create 用來創建新的執行緒,pthread_exit 用來退出執行緒。其 函數原型與說明如下:
Table 2-8 pthread_create 函數原型
在 Linux 系統中,在建立新的執行緒時必須呼叫 pthread_create API。
pthread_create 總共有四個參數。第一個參數為 thread,thread 參數為 pthread_t 型別物件的參照。當成功完成 pthread_create 呼叫之後,*thread 將會參照一個唯 一的整數執行緒 ID 數值。如果此值被設定為 NULL,當函數返回時並不會回傳 執行緒 ID。第二個參數為*attr,它參照到 pthread 動態屬性結構。pthread 結構屬 性如下:
Table 2-9 執行緒的屬性
一般而言,第二個參數都是填入 NULL,表示使用 pthread 的執行緒屬性初始 值 , 在 某 些 情 況 下 , 如 果 希 望 改 變 執 行 緒 屬 性 的 設 定 , 這 時 後 可 以 使 用
#include <pthread.h>
int pthread_create (pthread_t *restrict thread, const pthread_attr_t *restrict attr, void*(*start_routine)(void*), void*restrict arg);
Typedef struct __pthread_attr_s { int __detastate;
pthread_attr_init 函數來作屬性變更,其函數的原型如下:
Table 2-10 pthread_attr_init 函數
在此須注意的是,新建立的執行緒與原有的行程是共享行程記憶體的。具體 的範例程式如下:
Table 2-11 pthread 使用範例 最後,程式碼在做編譯時也必須連結到 pthread 函數庫。
#include <pthread.h>
int pthread_attr_init (pthread_attr_t * attr);
#include <pthread.h>
void * PacketProcess(void) {
/* Put your packet process handler in here */
}
int main (void) {
int ret;
pthread_t thread_sniffer;
ret = pthread_create(&thread_sniffer, NULL, (void *)&PacketProcess, NULL);
}
第三章 相關研究
本章將會介紹本論文的相關研究,包括了(1)網路通訊協定堆疊之分析 - 藉 由在 Linux Kernel 安插探針(probe)的動作,快速地顯示出網路通訊協定堆疊內的 核心函式。(2)網路事件通知機制 - 透過 Netlink 來獲取網路通訊協定堆疊內的 重要資訊,如:網卡的 Register、Unregister、IP address changed、routing table changed、MAC address changed…等等(3)封包擷取工具。
3.1 網路通訊協定堆疊之分析
指出封包目前所在的核心函式為何?以及替封包標上一個 Sequence number,以 方便與 Ethereal 資料做對照。/* linux\net\core\dev.c */
int (*dev_queue_xmit_Func_Start)(struct sk_buff *skb)=0;
EXPORT_SYMBOL(dev_queue_xmit_Func_Start);
int dev_queue_xmit(struct sk_buff *skb) {
struct net_device *dev = skb->dev;
struct Qdisc *q;
int rc = -ENOMEM;
if (dev_queue_xmit_Func_Start) dev_queue_xmit_Func_Start (skb);
所有的日誌資料都是儲存在驅動程式裡面事先配置好的陣列當中,陣列的容 Kernel Patch 前與 Kernel Patch 後的源始碼來做參考。
Table 3-2 Linux Kernel Patch 前
static int rtnetlink_event(struct notifier_block
*this, ulong event, void *ptr) {
struct net_device *dev = ptr;
switch (event) {
case NETDEV_UNREGISTER:
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
break;
case NETDEV_REGISTER:
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
break;
case NETDEV_UP:
case NETDEV_DOWN:
rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|
IFF_RUNNING);
break;
case NETDEV_CHANGE:
case NETDEV_GOING_DOWN:
break;
default:
rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
break;
}
return NOTIFY_DONE;
}
Table 3-3 Linux Kernel Patch 後
Libpcap 是 unix/linux/Solaris/BSD/Mac OS X/HP-UX 平臺下的封包截取函式 庫,目前市面上大多數網路監控軟體都是以它為基礎來做開發。Libpcap 在效能 上原先存在有短封包效能不好的問題,因為大量的短封包傳輸會造就更頻繁的 資料搬移發生,使得效能受到極大的影響。近年來由於運用了新的處理技術,
static int rtnetlink_event(struct notifier_block *this, ulong event, void *ptr) {
struct net_device *dev = ptr;
switch (event) {
case NETDEV_UNREGISTER:
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
win_rtmsg_ifinfo(event, RTM_SYSTEM_EVENT, dev, ~0U);
break;
case NETDEV_REGISTER:
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
win_rtmsg_ifinfo(event, RTM_SYSTEM_EVENT, dev, ~0U);
break;
case NETDEV_UP:
case NETDEV_DOWN:
rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
win_rtmsg_ifinfo(event, RTM_DRIVER_EVENT, dev, ~0U);
break;
case NETDEV_CHANGENAME:
rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
win_rtmsg_ifinfo(event, RTM_SYSTEM_EVENT, dev, ~0U);
break;
原有的問題已獲得了實質上的改善。主要的改進方法在於使用 MMAP 將網卡上 的 ring buffer 映射到使用者程式中做處理,而不需要經過額外的搬移與拷貝動 作,來達到將 Ethernet Packet Buffer 從 kernel space 到 user space 來到「零拷貝」
的目標了。
其動作原理詳述如下。一般而言,網路卡介面皆具有 Descriptor 暫存器可以 用來指向存放網路封包的網路封包緩衝區記憶體位址,驅動程式即是事先先將 記憶體指標存放在此結構當中。每當網卡接收中斷發生時,驅動程式即可在中 斷控制程式內去驅動 DMA 將網卡上的封包搬進 Descriptor 所指向的記憶體位 址。簡而言之,如果可以事先配置好固定位址的記憶體供網卡使用,使用者程 式當然也可以透過 MMAP 將此塊記憶體映射到使用者程式去做處理。
第四章 Linux 核心網路追蹤工具 之設計與系統架構
本章將介紹論文中 Linux 核心網路通訊協定堆疊追蹤工具(Linux kernel network protocol stack tracing tool)的設計架構。首先會先對此工具的設計概念及 目標做介紹,之後在對整個系統架構詳加說明。
4.1 設計概念及目標
隨著經濟的快速起飛,網路產品供應商在產品開發上講求快速整合,以因應
隨著經濟的快速起飛,網路產品供應商在產品開發上講求快速整合,以因應