Try   HackMD

K08: ktcp

主講人: jserv / 課程討論區: 2022 年系統軟體課程

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
返回「Linux 核心設計」課程進度表

解說錄影

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
預期目標

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
kecho: 執行在 Linux 核心模式的 TCP 伺服器

取得 kecho 原始程式碼並編譯:

$ git clone https://github.com/sysprog21/kecho
$ cd kecho
$ make

預期會見到以下:

  • 執行檔: benchuser-echo-server
  • 核心模組 kecho.kodrop-tcp-socket.ko

接著可進行測試:

$ make check

參考輸出:

Preparing...
Send message via telnet
Progress : [########################################] 100%
Complete

該操作由以下動作組成:

$ sudo insmod kecho.ko
$ telnet localhost 12345

會出現以下輸出:

Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

可輸入任何字元 (記得按下 Enter),然後就會看到 telnet 回應你剛才輸入的字元。

按下 Ctrl] 組合鍵,之後按下 q,即可離開 telnet 畫面。接著可以試著在 $ telnet localhost 12345 時不要輸入任何字元,只是等待,會看到以下的 kernel 訊息 (可用 $ dmesg 觀察):

                 cope
                 le:	    4404 kB
                 RssShmem:	       0 kB
                 VmData:	     880 kB
                 VmStk:	     132 kB
                 VmExe:	     136 kB
                 VmLib:	    6336 kB
                 VmPTE:	     212 kB
                 VmSwap:	       0 kB
                 HugetlbPages:	       0 kB
                 CoreDumping:	0
                 Threads:	1
                 SigQ:	0/31543

kecho 掛載時可指定 port 號碼: (預設是 port=12345)

$ sudo insmod kecho.ko port=1999

修改或測試 kecho 的過程,可能因為 TIME-WAIT sockets 持續佔用,導致 rmmod 無法成功,這時可透過給定的 drop-tcp-socket 核心模組來剔除特定的 TCP 連線。請詳細閱讀 kecho 以得知必要的設定和準備工作。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
user-echo-server: 執行於使用者層級的 TCP 伺服器

user-echo-serverkecho 的使用者層級的實作,可對照功能和比較效能,運用 epoll 系統呼叫,會傾聽 port 12345。

不管是 user-echo-server 抑或 kecho,都可搭配給定的 bench 程式來分析效能。請詳細閱讀 kecho 以得知必要的設定和準備工作。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
電腦網路概論

預習 CS:APP 第 11 章: Network Programming,搭配閱讀:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
kHTTPd: 執行在 Linux 核心模式的 Web 伺服器

取得 kHTTPd 原始程式碼並編譯:

$ git clone https://github.com/sysprog21/khttpd
$ cd khttpd
$ make

預期會見到執行檔 htstress 和核心模組 khttpd.ko。接著可進行測試:

$ make check

參考輸出:

0 requests
10000 requests
20000 requests
30000 requests
40000 requests
50000 requests
60000 requests
70000 requests
80000 requests
90000 requests

requests:      100000
good requests: 100000 [100%]
bad requests:  0 [0%]
socker errors: 0 [0%]
seconds:       4.722
requests/sec:  21177.090

這台電腦的實驗結果顯示,我們的 kHTTPd 每秒可處理超過 20K 個 HTTP 請求。上述實驗透過修改過的 htstress 工具得到,我們可拿來對 http://www.google.com 網址進行測試:

$ ./htstress -n 1000 -c 1 -t 4 http://www.google.com/

參考輸出:

requests:      1000
good requests: 1000 [100%]
bad requests:  0 [0%]
socker errors: 0 [0%]
seconds:       17.539
requests/sec:  57.015

kHTTPd 掛載時可指定 port 號碼: (預設是 port=8081)

$ sudo insmod khttpd.ko port=1999

除了用網頁瀏覽器開啟,也可用 wget 工具:

$ wget localhost:1999

參考 wget 執行輸出:

Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:1999... failed: Connection refused.
Connecting to localhost (localhost)|127.0.0.1|:1999... connected.
HTTP request sent, awaiting response... 200 OK
Length: 12 [text/plain]
Saving to: 'index.html'

得到的 index.html 內容就是 Hello World! 字串。

下方命令可追蹤 kHTTPd 傾聽的 port 狀況:

$ sudo netstat -apn | grep 8081

注意,在多次透過網頁瀏覽器存取 kHTTPd 所建立的連線後,可能在 module unload 時,看到 dmesg 輸出以下:

CPU: 37 PID: 78277 Comm: khttpd Tainted: G      D WC OE K  4.15.0-91-generic #92-Ubuntu
Hardware name: System manufacturer System Product Name/ROG STRIX X399-E GAMING, BIOS 0808 10/12/2018
RIP: 0010:0xffffffffc121b845                                                                                                                                  
RSP: 0018:ffffabfc9cf47d68 EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff8f1bc898a000 RCX: 0000000000000218
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff84c5107f
RBP: ffffabfc9cf47dd8 R08: ffff8f14c7e34e00 R09: 0000000180400024
R10: ffff8f152697cfc0 R11: 000499a097a8e100 R12: ffff8f152697cfc0
R13: ffffabfc9a6afe10 R14: ffff8f152697cfc0 R15: ffff8f1d4a5f8000
FS:  0000000000000000(0000) GS:ffff8f154f540000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffffffffc121b845 CR3: 000000138b00a000 CR4: 00000000003406e0
Call Trace:
  ? __schedule+0x256/0x880
  ? kthread+0x121/0x140
  ? kthread_create_worker_on_cpu+0x70/0x70
  ? ret_from_fork+0x22/0x40
Code:  Bad RIP value.
RIP: 0xffffffffc121b845 RSP: ffffabfc9cf47d68
CR2: ffffffffc121b845
---[ end trace 76d6d2ce81c97c71 ]---

核心 API

許多 Linux 裝置驅動程式或子系統會透過 kernel threads(簡稱kthread),在背景執行提供特定服務,然後等待特定 events 的發生。等待的過程中,kthread 會進入 sleep 狀態,當 events 發生時,kthread 會被喚醒執行一些耗時的工作,如此一來,可防止 main thread 被 blocked。
使用示範: kernel-threads.c

kthread_run 巨集在 Linux v5.5 的定義 include/linux/kthread.h :

#define kthread_run(threadfn, data, namefmt, ...)		      \
({	 							      \
    struct task_struct *__k					      \
        = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
    if (!IS_ERR(__k))						      \
        wake_up_process(__k);					      \
    __k;							      \
})

可見到 kthread_create 成功時直接 wake_up_process,回傳值為 task_struct

下方命令可查閱系統上的 kthread:

$ ps -ef

預期可見:

root         2     0  0 Feb17 ?        00:00:01 [kthreadd]

PPID 為 2 的都屬於 kthread,而 $ ps auxf 可見樹狀結構。
參考輸出結果:

0:01 /usr/sbin/sshd -D
0:00  \_ sshd: jserv [priv]
0:05  |   \_ sshd: jserv@pts/11
0:03  |       \_ -bash
0:00  |           \_ ps auxf
0:00  |           \_ less

尋找剛才載入的 khttpd 核心模組:

$ ps -ef | grep khttpd

預期可見以下:

root     18147     2  0 14:13 ?        00:00:00 [khttpd]
  • kthread_stop()
    通知 kthread 準備關閉(將 kernel_should_stop 旗標設為 true),並等待直到 threadfn 結束(由此可知 threadfn 中需要有一直驗證停止旗標的實做)。其中會把 kthread->kthread_should_stop 設為 true。此函式也用於喚醒 kthread。
  • schedule() 運作方式
    首先使用 set_current_state() 將 kthread 的 state 改成 TASK_INTERRUPTIBLE,使得稍後可被移出 run queue (排程器排程時會從 run queue 挑出任務),接著呼叫 schedule(),告知排程器可切換到其他任務,即讓出 CPU 資源,至此該 kthread 即開始睡眠。假如要喚醒這個 kthread,我們可用 wake_up_process() (帶入參數為目標 kthread 的 task_struct *),這個函式會將 kthread 的 state 切換回 TASK_RUNNING ,並將其放回 run queue,接著就等待排程器下一次排程。
  • TCP backlog
    accept() 成功前 queue 中最大能存放的連線要求。
  • sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)
    • PF_INET(protocol family) : 使用 IPv4
    • SOCK_STREAM : 提供一個序列化以及可靠的 byte stream
    • IPPROTO_TCP : 指定使用 TCP 協定
  • kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *) &opt, sizeof(opt))
  • kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr))
    • 綁定一個網路位址
  • kernel_listen(sock, DEFAULT_BACKLOG)
    • DEFAULT_BACKLOG : 紀錄 pending connection 資訊(因為 client 端有可能在 server 呼叫 accept() 之前就呼叫 connect())
  • kthread_run(echo_server_daemon, &param, MODULE_NAME)
    • 建立一個 kernel thread 並執行它
  • kernel_accept(param->listen_sock, &sock, 0)
    • 等待 client 端請求一個連線

出處: CS:APP 第 11 章

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
自我檢查清單

  • 參照 Linux 核心模組掛載機制,解釋 $ sudo insmod khttpd.ko port=1999 這命令是如何讓 port=1999 傳遞到核心,作為核心模組初始化的參數呢?

    過程中也會參照到 你所不知道的 C 語言:連結器和執行檔資訊

  • 參照 CS:APP 第 11 章,給定的 kHTTPd 和書中的 web 伺服器有哪些流程是一致?又有什麼是你認為 kHTTPd 可改進的部分?
  • htstress.c 用到 epoll 系統呼叫,其作用為何?這樣的 HTTP 效能分析工具原理為何?
  • 給定的 kecho 已使用 CMWQ,請陳述其優勢和用法
  • 核心文件 Concurrency Managed Workqueue (cmwq) 提到 "The original create_*workqueue() functions are deprecated and scheduled for removal",請參閱 Linux 核心的 git log (不要用 Google 搜尋!),揣摩 Linux 核心開發者的考量
  • 解釋 user-echo-server 運作原理,特別是 epoll 系統呼叫的使用
  • 是否理解 bench 原理,能否比較 kechouser-echo-server 表現?佐以製圖
  • 解釋 drop-tcp-socket 核心模組運作原理。TIME-WAIT sockets 又是什麼?

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
作業要求

  • 回答上述「自我檢查清單」的所有問題,需要附上對應的參考資料和必要的程式碼,以第一手材料 (包含自己設計的實驗) 為佳

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    如果你在 2022 年 4 月 19 日前,已從 GitHub sysprog21/kechokhttpd 進行 fork,請依據 Alternatives to forking into the same account 一文,對舊的 repository 做對應處置,然後重新 fork
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    2022 年的作業要求和 2020 年不同,請留意!

  • 在 GitHub 上 fork kecho,目標是修正 kecho 的執行時期的缺失,提升效能和穩健度 (robustness)
    • 若使用者層級的程式頻繁傳遞過長的字串給 kecho 核心模組,會發生什麼事?
    • 參照 kecho pull request #1,嘗試比較 kthread 為基礎的實作和 CMWQ,指出兩者效能的落差並解釋
    • 如果使用者層級的程式建立與 kecho 核心模組的連線後,就長期等待,會導致什麼問題?
    • 研讀 Linux Applications Performance: Introduction,嘗試將上述實作列入考量,比較多種 TCP 伺服器實作手法的效能表現
  • 在 GitHub 上 fork khttpd,目標是提供檔案存取功能和修正 khttpd 的執行時期缺失。過程中應一併完成以下:

繳交方式

編輯 Homework6 作業區共筆,將你的觀察、上述要求的解說、應用場合探討,以及各式效能改善過程,善用 gnuplot 製圖,紀錄於新建立的共筆

截止日期

  • May 10, 2022 (含) 之前

越早在 GitHub 上有動態、越早接受 code review,評分越高

作業觀摩