目的: 檢驗學員對 LKMPG 及 CPU 排程器的認知
1
第一份作業提及修改過的 tiny-web-server
,讓學員及早理解電腦網路通訊、客戶—伺服器通訊模型,還有相關的 socket 程式設計 (對照 CS:APP 第 11 章)。為了檢驗學員對於 LKMPG 的認知,我們開發一套 Linux 核心模式的網頁伺服器 (in-kernel web server),命名為 kweb
,展示如何在 Linux 核心內部直接建立 TCP 伺服器。
kweb
在指定的埠號(port number,預設 9999
)進行監聽,並在接收到連線後提供簡易的 HTTP 回應。其主要流程如下:
__sock_create()
(或 sock_create_kern()
)在指定網路名稱空間(net namespace)中建立 TCP socketkernel_listen()
進行監聽sk_data_ready
函式觸發 work item,負責呼叫 kernel_accept()
來接受連線kernel_accept()
取得新的 client_sock
,並將其包裝在一個工作結構(struct client_work_queue
)中schedule_work()
將實際處理客戶端的流程排入系統工作佇列,使每個連線皆可在獨立的 work context 處理client_handler()
中,kweb
使用 sock_sendmsg()
或 kernel_sendpage()
傳送固定的 HTTP 回應給客戶端HTTP/1.1 200 OK
)以及測試訊息;另外也加入了 Content-Length
等標頭,使其符合標準的 HTTP 格式kweb
會在 /sys/kernel/webserver/net/data/status
建立一個屬性檔 (attribute),並以讀寫檔案的方式來啟用或停用伺服器。netns_subsys_ops
配合 Linux 的 per-net 機制,在不同的網路名稱空間中維持獨立的伺服器實例 (instance)unshare -t net
建立新 netns,並在該空間中掛載 sysfs 後,使用同樣的啟停方式來管理伺服器。以下為使用 kweb 的範例操作方式,並以繁體中文進行說明。此範例以預設的埠號 9999 舉例,您可在載入模組時透過參數改成其他埠號。
考慮以下 Makefile
內容: (注意 tab)
編譯核心模組: make
,完成後會產生一個名為 kweb.ko
的可載入模組檔 (LKM)。隨後使用以下命令將 kweb
模組載入核心:
host
:要綁定的 IP 位址(若不指定,預設為 0.0.0.0
,表示在所有網卡監聽)port
:要監聽的 TCP 埠號(若不指定,預設為 9999)載入後,kweb
會在 /sys/kernel/webserver/net/data
中建立名為 status
的屬性檔案,用來控制伺服器的啟用與停用。
echo 1 | sudo tee /sys/kernel/webserver/net/data/status
nc
(netcat)或 curl
進行測試。例如 nc 127.0.0.1 9999
。若成功連線,應可看到包含 HTTP/1.1 200 OK
與訊息內容的回應echo 0 | sudo tee /sys/kernel/webserver/net/data/status
Namespace 使用方式:
ip a
查看新 netns 裡可用的網路介面。如果還沒啟用 lo(127.0.0.1),可以:
/mnt/sysfs/kernel/webserver/net/data/status
找到相同的 status
屬性檔。當您不再需要此網頁伺服器時,可用以下命令將模組從核心卸載,並同時停止所有網路名稱空間中的 kweb
伺服器:
此動作也會移除 /sys/kernel/webserver
相關路徑。
kweb.c
的主要程式碼可見 kweb.c。作答規範:
AAAA
, BBBB
, CCCC
, DDDD
皆為有效的 C 語言表示式,且該依循一致的程式碼風格 (注意空白字元!)AAAA
(第 158 行) 和 DDDD
(第 208 行) 包含 container_of
巨集BBBB
和 CCCC
該使用 Linux workqueue 提供的函式呼叫;
) 並以最精簡的形式書寫延伸問題: