引言
內(nèi)核研究與開發(fā)是計(jì)算機(jī)底層處于與硬件打交道的部位暖哨,ebpf可以理解為是內(nèi)核開發(fā)的一個(gè)模塊。在研究ebpf開發(fā)之前需要對(duì)計(jì)算機(jī)的一些基礎(chǔ)知識(shí)學(xué)習(xí)了解珍手,懂得計(jì)算機(jī)的基本組成和操作系統(tǒng)的基本原理和運(yùn)行機(jī)制真竖,了解Linux內(nèi)核設(shè)計(jì)的機(jī)制和相關(guān)源碼的閱讀與理解荐开,再深入內(nèi)核模塊觀察ebpf的設(shè)計(jì)思路模孩,進(jìn)而做到對(duì)ebpf的開發(fā)與實(shí)現(xiàn)尖阔。
在此之前贮缅,首先需要儲(chǔ)備一些基本的計(jì)算機(jī)知識(shí)。
基礎(chǔ)知識(shí)儲(chǔ)備
計(jì)算機(jī)組成原理
學(xué)習(xí)計(jì)算機(jī)組成原理可以對(duì)計(jì)算機(jī)的基礎(chǔ)架構(gòu)有所理解介却,了解計(jì)算機(jī)中常見的術(shù)語和概念谴供。
計(jì)算機(jī)組成原理知識(shí)要點(diǎn)見:計(jì)算機(jī)組成原理學(xué)習(xí)筆記
操作系統(tǒng)
操作系統(tǒng)作為人和計(jì)算機(jī)交互的橋梁,理解其工作原理對(duì)后續(xù)內(nèi)核開發(fā)有很好的幫助齿坷,對(duì)操作系統(tǒng)的術(shù)語了解知道其背后的道理是開發(fā)的基礎(chǔ)桂肌。
操作系統(tǒng)知識(shí)要點(diǎn)見:操作系統(tǒng)學(xué)習(xí)筆記
C語言
C語言是Linux內(nèi)核開發(fā)主要使用的編程語言和開發(fā)工具,需要熟悉其基本語法和結(jié)構(gòu)永淌。
Linux基礎(chǔ)
了解Linux基本組成和常用的shell命令崎场,熟悉Linux的文件架構(gòu)。
FHS(Filesystem Hierarchy Standard):
FHS依據(jù)文件系統(tǒng)使用的頻繁與否與是否允許使用者隨意更動(dòng), 而將目錄定義成為四種交互作用的形態(tài),用表格來說有點(diǎn)像底下這樣:
無法復(fù)制加載中的內(nèi)容
可分享的:可以分享給其他系統(tǒng)掛載使用的目錄,所以包括執(zhí)行文件與用戶的郵件等數(shù)據(jù), 是能夠分享給網(wǎng)絡(luò)上其他主機(jī)掛載用的目錄遂蛀;
不可分享的:自己機(jī)器上面運(yùn)作的裝置文件或者是與程序有關(guān)的socket文件等, 由于僅與自身機(jī)器有關(guān),所以當(dāng)然就不適合分享給其他主機(jī)了.
不變的:有些數(shù)據(jù)是不會(huì)經(jīng)常變動(dòng)的,跟隨著distribution而不變動(dòng). 例如函式庫谭跨、文件說明文件、系統(tǒng)管理員所管理的主機(jī)服務(wù)配置文件等等答恶;
可變動(dòng)的:經(jīng)常改變的數(shù)據(jù),例如登錄文件饺蚊、一般用戶可自行收受的新聞組等.
事實(shí)上,FHS針對(duì)目錄樹架構(gòu)僅定義出三層目錄底下應(yīng)該放置什么數(shù)據(jù)而已,分別是底下這三個(gè)目錄的定義:
- / (root, 根目錄):與開機(jī)系統(tǒng)有關(guān)萍诱;
- /usr (unix software resource):與軟件安裝/執(zhí)行有關(guān)悬嗓;
- /var (variable):與系統(tǒng)運(yùn)作過程有關(guān).
根目錄 (/) 的意義與內(nèi)容:
概要:
所有的目錄都是由根目錄衍生出來的(根目錄是整個(gè)系統(tǒng)最重要的一個(gè)目錄)
與開機(jī)/還原/系統(tǒng)修復(fù)等動(dòng)作有關(guān). (由于系統(tǒng)開機(jī)時(shí)需要特定的開機(jī)軟件、核心文件裕坊、開機(jī)所需程序包竹、 函式庫等等文件數(shù)據(jù),若系統(tǒng)出現(xiàn)錯(cuò)誤時(shí),根目錄也必須要包含有能夠修復(fù)文件系統(tǒng)的程序才行)
FHS標(biāo)準(zhǔn)建議:根目錄(/)所在分割槽應(yīng)該越小越好, 且應(yīng)用程序所安裝的軟件最好不要與根目錄放在同一個(gè)分割槽內(nèi),保持根目錄越小越好.(因?yàn)樵酱蟮姆指畈蹔厱?huì)放入越多的數(shù)據(jù),如此一來根目錄所在分割槽就可能會(huì)有較多發(fā)生錯(cuò)誤的機(jī)會(huì),如此不但效能較佳,根目錄所在的文件系統(tǒng)也較不容易發(fā)生問題.)
根目錄(/)底下目錄FHS定義的說明:
無法復(fù)制加載中的內(nèi)容
除上 FHS 中定義的目錄說明外, 底下是幾個(gè)在Linux當(dāng)中非常重要的目錄:
無法復(fù)制加載中的內(nèi)容
不可與根目錄分開的目錄(與開機(jī)過程有關(guān)):
根目錄與開機(jī)有關(guān),開機(jī)過程中僅有根目錄會(huì)被掛載, 其他分割槽則是在開機(jī)完成之后才會(huì)持續(xù)的進(jìn)行掛載的行為.就是因?yàn)槿绱?因此根目錄下與開機(jī)過程有關(guān)的目錄, 就不能夠與根目錄放到不同的分割槽去!
/etc:配置文件
/bin:重要執(zhí)行檔
/dev:所需要的裝置文件
/lib:執(zhí)行檔所需的函式庫與核心所需的模塊
/sbin:重要的系統(tǒng)執(zhí)行文件
/usr 的意義與內(nèi)容:
概要:
依據(jù)FHS的基本定義,/usr里面放置的數(shù)據(jù)屬于可分享的與不可變動(dòng)的(shareable, static), 如果你知道如何透過網(wǎng)絡(luò)進(jìn)行分割槽的掛載,那么/usr確實(shí)可以分享給局域網(wǎng)絡(luò)內(nèi)的其他主機(jī)來使用籍凝!
usr(Unix Software Resource 即Unix操作系統(tǒng)軟件資源) FHS建議所有軟件開發(fā)者,應(yīng)該將他們的數(shù)據(jù)合理的分別放置到這個(gè)目錄下的次目錄,而不要自行建立該軟件自己獨(dú)立的目錄.
所有系統(tǒng)默認(rèn)的軟件(distribution發(fā)布者提供的軟件)都會(huì)放置到/usr底下,因此這個(gè)目錄有點(diǎn)類似Windows 系統(tǒng)的『C:\Windows\ + C:\Program files\』這兩個(gè)目錄的綜合體,系統(tǒng)剛安裝完畢時(shí),這個(gè)目錄會(huì)占用最多的硬盤容量.
一般來說,/usr的次目錄建議有底下這些:
無法復(fù)制加載中的內(nèi)容
/var 的意義與內(nèi)容:
概要:
/var目錄主要針對(duì)常態(tài)性變動(dòng)的文件,包括緩存(cache)周瞎、登錄檔(log file)以及某些軟件運(yùn)作所產(chǎn)生的文件, 包括程序文件(lock file, run file),或者例如MySQL數(shù)據(jù)庫的文件等等. 所以/var在系統(tǒng)運(yùn)作后才會(huì)漸漸占用硬盤容量的目錄
常見的次目錄有:
無法復(fù)制加載中的內(nèi)容
針對(duì)FHS,各家distributions的異同:
由于FHS僅是定義出最上層(/)及次層(/usr, /var)的目錄內(nèi)容應(yīng)該要放置的文件或目錄數(shù)據(jù), 因此,在其他次目錄層級(jí)內(nèi),就可以隨開發(fā)者自行來配置了.舉例來說,CentOS的網(wǎng)絡(luò)設(shè)定數(shù)據(jù)放在 /etc/sysconfig/network-scripts/ 目錄下,但是SuSE則是將網(wǎng)絡(luò)放置在 /etc/sysconfig/network/ 目錄下,目錄名稱可是不同的呢!不過只要記住大致的FHS標(biāo)準(zhǔn),差異性其實(shí)有限啦饵蒂!
Linux 命令大全查詢表
無法復(fù)制加載中的內(nèi)容
Linux內(nèi)核
Linux內(nèi)核學(xué)習(xí)策略
Linux學(xué)習(xí)建議配套遠(yuǎn)古版本的Linux內(nèi)核源碼學(xué)習(xí)声诸,有助于幫助理解內(nèi)核設(shè)計(jì)的思路,下載并閱讀Linux內(nèi)核1.0版本的源碼去學(xué)習(xí)退盯,該版本基本包含了內(nèi)核基本部件彼乌,后續(xù)的版本都是在此基礎(chǔ)上擴(kuò)充功能,但是基本的內(nèi)在沒有變化渊迁。
內(nèi)核源碼不同版本間的閱讀與對(duì)比可參考Bootlin慰照,其中1.0源碼目錄結(jié)構(gòu)如下,其中對(duì)主要文件目錄進(jìn)行解釋:
無法復(fù)制加載中的內(nèi)容
對(duì)照著內(nèi)核設(shè)計(jì)的源代碼進(jìn)行學(xué)習(xí)琉朽,會(huì)從根源上思考這樣設(shè)計(jì)的目的是什么毒租。
Linux內(nèi)核開發(fā)環(huán)境配置
內(nèi)核開發(fā)環(huán)境和源碼安裝配置:Linux內(nèi)核開發(fā)環(huán)境配置
Linux內(nèi)核簡(jiǎn)介
Linux 內(nèi)核的用途是什么?
Linux 內(nèi)核有 4 項(xiàng)工作:
- 內(nèi)存管理:追蹤記錄有多少內(nèi)存存儲(chǔ)了什么以及存儲(chǔ)在哪里
- 進(jìn)程管理:確定哪些進(jìn)程可以使用中央處理器(CPU)箱叁、何時(shí)使用以及持續(xù)多長時(shí)間
- 設(shè)備驅(qū)動(dòng)程序:充當(dāng)硬件與進(jìn)程之間的調(diào)解程序/解釋程序
- 系統(tǒng)調(diào)用和安全防護(hù):從流程接受服務(wù)請(qǐng)求
在正確實(shí)施的情況下墅垮,內(nèi)核對(duì)于用戶是不可見的惕医,它在自己的小世界(稱為內(nèi)核空間)中工作,并從中分配內(nèi)存和跟蹤所有內(nèi)容的存儲(chǔ)位置算色。用戶所看到的內(nèi)容(例如 Web 瀏覽器和文件)則被稱為用戶空間曹锨。這些應(yīng)用通過系統(tǒng)調(diào)用接口(SCI)與內(nèi)核進(jìn)行交互。
舉例來說剃允,內(nèi)核就像是一個(gè)為高管(硬件)服務(wù)的忙碌的個(gè)人助理沛简。助理的工作就是將員工和公眾(用戶)的消息和請(qǐng)求(進(jìn)程)轉(zhuǎn)交給高管,記住存放的內(nèi)容和位置(內(nèi)存)斥废,并確定在任何特定的時(shí)間誰可以拜訪高管椒楣、會(huì)面時(shí)間有多長。
Linux內(nèi)核學(xué)習(xí)路線和框架圖
Linux Security Coaching
Linux內(nèi)核基礎(chǔ)學(xué)習(xí)資料
Linux內(nèi)核與系統(tǒng)驅(qū)動(dòng)保護(hù)入口
該視頻資料詳細(xì)介紹了Linux內(nèi)核的知識(shí)點(diǎn)及其在內(nèi)核中的實(shí)現(xiàn)進(jìn)行比對(duì)牡肉,很有參考價(jià)值捧灰。
MakeFile詳解
Makefile 可以簡(jiǎn)單的認(rèn)為是一個(gè)工程文件的編譯規(guī)則,描述了整個(gè)工程的編譯和鏈接等規(guī)則统锤。詳細(xì)介紹如下:
Makefile文件負(fù)責(zé)編寫程序的編譯與運(yùn)行規(guī)則毛俏,免去命令行使用Clang去逐步編譯分析。
GDB詳解
GDB是一個(gè)強(qiáng)大的調(diào)試工具饲窿,通過它可以實(shí)現(xiàn)C程序代碼bug的調(diào)試煌寇。
Linux崩潰調(diào)試
Linux內(nèi)核Crash下的問題解決方案:
EBPF基礎(chǔ)
什么是ebpf?
Linux 內(nèi)核一直是實(shí)現(xiàn)監(jiān)控/可觀測(cè)性逾雄、網(wǎng)絡(luò)和安全功能的理想地方阀溶。 不過很多情況下這并非易事,因?yàn)檫@些工作需要修改內(nèi)核源碼或加載內(nèi)核模塊鸦泳, 最終實(shí)現(xiàn)形式是在已有的層層抽象之上疊加新的抽象银锻。 eBPF 是一項(xiàng)革命性技術(shù),它能在內(nèi)核中運(yùn)行沙箱程序(sandbox programs)做鹰, 而無需修改內(nèi)核源碼或者加載內(nèi)核模塊击纬。
eBPF 催生了一種全新的軟件開發(fā)方式〖佤铮基于這種方式更振,我們不僅能對(duì)內(nèi)核行為進(jìn)行 編程,甚至還能編寫跨多個(gè)子系統(tǒng)的處理邏輯喂走,而傳統(tǒng)上這些子系統(tǒng)是完全獨(dú)立殃饿、 無法用一套邏輯來處理的。
安全:
觀測(cè)和理解所有的系統(tǒng)調(diào)用的能力芋肠,以及在 packet 層和 socket 層審視所有的網(wǎng)絡(luò)操作的能力乎芳, 這兩者相結(jié)合,為系統(tǒng)安全提供了革命性的新方法。 以前奈惑,系統(tǒng)調(diào)用過濾吭净、網(wǎng)絡(luò)層過濾和進(jìn)程上下文跟蹤是在完全獨(dú)立的系統(tǒng)中完成的; eBPF 的出現(xiàn)統(tǒng)一了可觀測(cè)性和各層面的控制能力肴甸,使我們有更加豐富的上下文和更精細(xì)的控制能力寂殉, 因而能創(chuàng)建更加安全的系統(tǒng)。
網(wǎng)絡(luò):
eBPF 的兩大特色 —— 可編程和高性能 —— 使它能滿足所有的網(wǎng)絡(luò)包處理需求原在。 可編程意味著無需離開內(nèi)核中的包處理上下文友扰,就能添加額外的協(xié)議解析器或任何轉(zhuǎn)發(fā)邏輯, 以滿足不斷變化的需求庶柿。高性能的 JIT 編譯器使 eBPF 程序能達(dá)到幾乎與原生編譯的內(nèi)核態(tài)代碼一樣的執(zhí)行性能村怪。
跟蹤 & 性能分析:
eBPF 程序能夠加載到 trace points、內(nèi)核及用戶空間應(yīng)用程序中的 probe points浮庐, 這種能力使我們對(duì)應(yīng)用程序的運(yùn)行時(shí)行為(runtime behavior)和系統(tǒng)本身 (system itself)提供了史無前例的可觀測(cè)性甚负。應(yīng)用端和系統(tǒng)端的這種觀測(cè)能力相結(jié)合, 能在排查系統(tǒng)性能問題時(shí)提供強(qiáng)大的能力和獨(dú)特的信息审残。BPF 使用了很多高級(jí)數(shù)據(jù)結(jié)構(gòu)梭域, 因此能非常高效地導(dǎo)出有意義的可觀測(cè)數(shù)據(jù),而不是像很多同類系統(tǒng)一樣導(dǎo)出海量的原始采樣數(shù)據(jù)搅轿。
觀測(cè) & 監(jiān)控:
相比于操作系統(tǒng)提供的靜態(tài)計(jì)數(shù)器(counters病涨、gauges),eBPF 能在內(nèi)核中收集和聚合自定義 metric介时, 并能從不同數(shù)據(jù)源來生成可觀測(cè)數(shù)據(jù)没宾。這既擴(kuò)展了可觀測(cè)性的深度凌彬,也顯著減少了整體系統(tǒng)開銷沸柔, 因?yàn)楝F(xiàn)在可以選擇只收集需要的數(shù)據(jù),并且后者是直方圖或類似的格式铲敛,而非原始采樣數(shù)據(jù)褐澎。
Linux驅(qū)動(dòng)模塊開發(fā)
簡(jiǎn)介
Linux 內(nèi)核的整體結(jié)構(gòu)已經(jīng)非常龐大,而其包含的組件也非常多。這會(huì)導(dǎo)致兩個(gè)問題,一是生成的內(nèi)核會(huì)很大,二是如果我們要在現(xiàn)有的內(nèi)核中新增或刪除功能,將不得不重新編譯內(nèi)核伐蒋。Linux 提供了這樣的一種機(jī)制,這種機(jī)制被稱為模塊(Module)工三。使得編譯出的內(nèi)核本身并不需要包含所有功能,而在這些功能需要被使用的時(shí)候,其對(duì)應(yīng)的代碼被動(dòng)態(tài)地加載到內(nèi)核中。
舉例
先來看一個(gè)最簡(jiǎn)單的內(nèi)核模塊“Hello World”先鱼,代碼如下:
#include <linux/init.h>
#include <linux/module.h>
static int hello_init(void) /初始化函數(shù)/
{
printk(KERN_INFO " Hello World enter\n");
return 0;
}
static void hello_exit(void) /卸載函數(shù)/
{
printk(KERN_INFO " Hello World exit\n ");
}
module_init(hello_init); /模塊初始化/
module_exit(hello_exit); /卸載模塊/
MODULE_LICENSE("Dual BSD/GPL"); /許可聲明/
MODULE_AUTHOR("Linux");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("a simplest module");
這個(gè)模塊定義了兩個(gè)函數(shù), 一個(gè)在模塊加載到內(nèi)核時(shí)被調(diào)用( hello_init )以及一個(gè)在模塊被去除時(shí)被調(diào)用( hello_exit ). moudle_init 和 module_exit 這幾行使用了特別的內(nèi)核宏來指出這兩個(gè)函數(shù)的角色. 另一個(gè)特別的宏 (MODULE_LICENSE) 是用來告知內(nèi)核, 該模塊帶有一個(gè)自由的許可證.
注:內(nèi)核模塊中用于輸出的函數(shù)是內(nèi)核空間的 printk()而非用戶空間的 printf()俭正,具體用法參考附件 printk函數(shù)介紹。
幾個(gè)常用命令
加載模塊
通過“insmod ./hello.ko”命令可以加載焙畔,加載時(shí)輸出“Hello World enter”掸读。
卸載模塊
通過“rmmod hello”命令可以卸載,卸載時(shí)輸出“Hello World exit”。
查看系統(tǒng)中已經(jīng)加載的模塊列表
在Linux中儿惫,使用lsmod命令可以獲得系統(tǒng)中加載了的所有模塊以及模塊間的依賴關(guān)系澡罚,例如:
root@imx6:~$ lsmod
Module Size Used by
hello 1568 0
ohci1394 32716 0
ide_scsi 16708 0
ide_cd 39392 0
cdrom 36960 1 ide_cd
查看某個(gè)具體模塊的詳細(xì)信息
使用modinfo <模塊名>命令可以獲得模塊的信息,包括模塊作者、模塊的說明肾请、模塊所支持 的參數(shù)以及 vermagic:
root@imx6:~$ modinfo hello.ko
filename: hello.ko
license: Dual BSD/GPL
author: Song Baohua
description: A simple Hello World Module
alias: a simplest module
vermagic: 2.6.15.5 686 gcc-3.2
depends:
Linux 內(nèi)核模塊程序的結(jié)構(gòu)
一個(gè)Linux內(nèi)核模塊主要由如下幾個(gè)部分組成:
1留搔、模塊加載函數(shù)(一般需要) 當(dāng)通過insmod或modprobe命令加載內(nèi)核模塊時(shí),模塊的加載函數(shù)會(huì)自動(dòng)被內(nèi)核執(zhí)行铛铁,完成本模塊的相關(guān)初始化工作隔显。
2、模塊卸載函數(shù)(一般需要) 當(dāng)通過rmmod命令卸載某模塊時(shí)饵逐,模塊的卸載函數(shù)會(huì)自動(dòng)被內(nèi)核執(zhí)行荣月,完成與模塊卸載函數(shù)相反的功能。
3梳毙、模塊許可證聲明(必須) 許可證(LICENSE)聲明描述內(nèi)核模塊的許可權(quán)限哺窄,如果不聲明LICENSE,模塊被加載時(shí)账锹,將收到內(nèi)核被污染 (kernel tainted)的警告萌业。在Linux 2.6內(nèi)核中,可接受的LICENSE包括“GPL”奸柬、“GPL v2”生年、“GPL and additional rights”、“Dual BSD/GPL”廓奕、“Dual MPL/GPL”和“Proprietary”抱婉。大多數(shù)情況下,內(nèi)核模塊應(yīng)遵循GPL兼容許可權(quán)桌粉。Linux 2.6內(nèi)核模塊最常見的是以MODULE_LICENSE( “Dual BSD/GPL” )語句聲明模塊采BSD/GPL雙LICENSE蒸绩。
4、模塊參數(shù)(可選) 模塊參數(shù)是模塊被加載的時(shí)候可以被傳遞給它的值铃肯,它本身對(duì)應(yīng)模塊內(nèi)部的全局變量患亿。
5、模塊導(dǎo)出符號(hào)(可選) 內(nèi)核模塊可以導(dǎo)出符號(hào)(symbol押逼,對(duì)應(yīng)于函數(shù)或變量)步藕,這樣其它模塊可以使用本模塊中的變量或函數(shù)。
6挑格、模塊作者等信息聲明(可選) 用于申明模塊作者的相關(guān)信息咙冗,一般用于備注作者姓名、郵箱等漂彤。
模塊加載函數(shù)
Linux 內(nèi)核模塊加載函數(shù)一般以_ _init 標(biāo)識(shí)聲明,典型的模塊加載函數(shù)如下:
static int _ _init initialization_function(void)
{
/* 初始化代碼 */
}
module_init(initialization_function);
模塊加載函數(shù)必須以“module_init(函數(shù)名)”的形式被指定雾消。它返回整型值,若初始化成功,應(yīng)返回 0瞬逊。而在初始化失敗時(shí),應(yīng)該返回錯(cuò)誤編碼。在 Linux 內(nèi)核里,錯(cuò)誤編碼是一個(gè)負(fù)值仪或。
在 Linux 2.6 內(nèi)核中,可以使用 request_module(const char *fmt, …)函數(shù)加載內(nèi)核模塊,驅(qū)動(dòng)開發(fā)人員可以通過調(diào)用确镊。
request_module(module_name);
/**** 或者 ****/
request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));
注意:在 Linux 中,所有標(biāo)識(shí)為_ init 的函數(shù)在連接的時(shí)候都放在.init.text 這個(gè)區(qū)段內(nèi),此外,所有的 init 函數(shù)在區(qū)段.initcall.init 中還保存了一份函數(shù)指針,在初始化時(shí)內(nèi)核會(huì)通過這些函數(shù)指針調(diào)用這些 _init 函數(shù),并在初始化完成后,釋放 init 區(qū)段(包括.init.text、.initcall.init 等)范删。
模塊卸載函數(shù)
static void _ _exit cleanup_function(void)
{
/* 釋放代碼 */
}
module_exit(cleanup_function);
模塊卸載函數(shù)在模塊卸載的時(shí)候執(zhí)行,不返回任何值,必須以“module_exit(函數(shù)名)”的形式來指定蕾域。通常來說,模塊卸載函數(shù)要完成與模塊加載函數(shù)相反的功能,如下所示。
若模塊加載函數(shù)注冊(cè)了 XXX,則模塊卸載函數(shù)應(yīng)該注銷 XXX到旦。
若模塊加載函數(shù)動(dòng)態(tài)申請(qǐng)了內(nèi)存,則模塊卸載函數(shù)應(yīng)釋放該內(nèi)存旨巷。
若模塊加載函數(shù)申請(qǐng)了硬件資源(中斷、DMA 通道添忘、I/O 端口和 I/O 內(nèi)存等)的占用,則模塊卸載函數(shù)應(yīng)釋放這些硬件資源采呐。
若模塊加載函數(shù)開啟了硬件,則卸載函數(shù)中一般要關(guān)閉之。
模塊參數(shù)
用“module_param(參數(shù)名,參數(shù)類型,參數(shù)讀/寫權(quán)限)”為模塊定義一個(gè)參數(shù),例如下列代碼定義了 1 個(gè)整型參數(shù)和 1 個(gè)字符指針參數(shù):
static char *book_name = " dissecting Linux Device Driver ";
static int num = 4 000;
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);
參數(shù)類型可以是 byte搁骑、short斧吐、ushort、int仲器、uint煤率、long、ulong乏冀、charp(字符指針)蝶糯、bool 或 invbool(布爾的反),在模塊被編譯時(shí)會(huì)將 module_param 中聲明的類型與變量定義的類型進(jìn)行比較,判斷是否一致。
在裝載內(nèi)核模塊時(shí),用戶可以向模塊傳遞參數(shù),形式為“insmode(或 modprobe)模塊名 參數(shù)名=參數(shù)值”,如果不傳遞,參數(shù)將使用模塊內(nèi)定義的缺省值辆沦。
內(nèi)核模塊的符號(hào)導(dǎo)出
模塊可以使用如下宏導(dǎo)出符號(hào)到內(nèi)核符號(hào)表:
EXPORT_SYMBOL(符號(hào)名);
EXPORT_SYMBOL_GPL(符號(hào)名);
導(dǎo)出的符號(hào)將可以被其他模塊使用,使用前聲明一下即可昼捍。EXPORT_SYMBOL_GPL()只適用于包含 GPL 許可權(quán)的模塊。
模塊聲明與描述
在Linux內(nèi)核模塊中肢扯,我們可以用MODULE_AUTHOR妒茬、MODULE_DESCRIPTION、MODULE_VERSION鹃彻、MODULE_DEVICE_TABLE郊闯、MODULE_ALIAS分別聲明模塊的作者、描述蛛株、版本、設(shè)備表和別名育拨,例如:
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);
對(duì)于USB谨履、PCI等設(shè)備驅(qū)動(dòng),通常會(huì)創(chuàng)建一個(gè)MODULE_DEVICE_TABLE熬丧。
MakeFile
Kernel modules
obj-m += hello.o
Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules #modules表示編譯成模塊的意思
#CURDIR是make的內(nèi)嵌變量笋粟,自動(dòng)設(shè)置為當(dāng)前目錄
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
該 Makefile 文件應(yīng)該與源代碼 hello.c 位于同一目錄,開啟其中的 EXTRA_CFLAGS=-g -O0可以得到包含調(diào)試信息的 hello.ko 模塊。運(yùn)行 make 命令得到的模塊可直接在 PC 上運(yùn)行。
注:uname 的更多用法詳見附件
如果一個(gè)模塊包括多個(gè).c 文件(如 file1.c害捕、file2.c),則應(yīng)該以如下方式編寫 Makefile:
obj-m := modulename.o
modulename-objs := file1.o file2.o
obj-m是個(gè)makefile變量绿淋,它的值可以是一串.o文件的表列
EBPF詳解
ebpf詳細(xì)學(xué)習(xí)筆記和記錄:
EBPF(Berkeley Packet Filter)學(xué)習(xí)記錄
在這里不贅述ebpf的歷史等沒有太多學(xué)習(xí)意義的信息,主要從實(shí)際開發(fā)角度需要去展開必要介紹尝盼。
Seccross項(xiàng)目理解
開發(fā)記錄及相關(guān)源碼分析記錄: