從零開始的內(nèi)核ebpf開發(fā)之旅

引言


內(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ǔ)。

清華大學(xué)操作系統(tǒng)課程入口

操作系統(tǒng)知識(shí)要點(diǎn)見:操作系統(tǒng)學(xué)習(xí)筆記

C語言

C語言是Linux內(nèi)核開發(fā)主要使用的編程語言和開發(fā)工具,需要熟悉其基本語法和結(jié)構(gòu)。

C語言中文網(wǎng)入口

C語言API入口

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). 例如函式庫(kù)、文件說明文件、系統(tǒng)管理員所管理的主機(jī)服務(wù)配置文件等等;

  • 可變動(dòng)的:經(jīng)常改變的數(shù)據(jù),例如登錄文件、一般用戶可自行收受的新聞組等.

事實(shí)上,FHS針對(duì)目錄樹架構(gòu)僅定義出三層目錄底下應(yīng)該放置什么數(shù)據(jù)而已,分別是底下這三個(gè)目錄的定義:

  1. / (root, 根目錄):與開機(jī)系統(tǒng)有關(guān);
  2. /usr (unix software resource):與軟件安裝/執(zhí)行有關(guān);
  3. /var (variable):與系統(tǒng)運(yùn)作過程有關(guān).

根目錄 (/) 的意義與內(nèi)容:

概要:

  1. 所有的目錄都是由根目錄衍生出來的(根目錄是整個(gè)系統(tǒng)最重要的一個(gè)目錄)

  2. 與開機(jī)/還原/系統(tǒng)修復(fù)等動(dòng)作有關(guān). (由于系統(tǒng)開機(jī)時(shí)需要特定的開機(jī)軟件、核心文件、開機(jī)所需程序、 函式庫(kù)等等文件數(shù)據(jù),若系統(tǒng)出現(xiàn)錯(cuò)誤時(shí),根目錄也必須要包含有能夠修復(fù)文件系統(tǒng)的程序才行)

  3. 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í)行檔所需的函式庫(kù)與核心所需的模塊

  • /sbin:重要的系統(tǒng)執(zhí)行文件

/usr 的意義與內(nèi)容:

概要:

  1. 依據(jù)FHS的基本定義,/usr里面放置的數(shù)據(jù)屬于可分享的與不可變動(dòng)的(shareable, static), 如果你知道如何透過網(wǎng)絡(luò)進(jìn)行分割槽的掛載,那么/usr確實(shí)可以分享給局域網(wǎng)絡(luò)內(nèi)的其他主機(jī)來使用!

  2. usr(Unix Software Resource 即Unix操作系統(tǒng)軟件資源) FHS建議所有軟件開發(fā)者,應(yīng)該將他們的數(shù)據(jù)合理的分別放置到這個(gè)目錄下的次目錄,而不要自行建立該軟件自己獨(dú)立的目錄.

  3. 所有系統(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ù)庫(kù)的文件等等. 所以/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)工作:

  1. 內(nèi)存管理:追蹤記錄有多少內(nèi)存存儲(chǔ)了什么以及存儲(chǔ)在哪里
  2. 進(jìn)程管理:確定哪些進(jìn)程可以使用中央處理器(CPU)、何時(shí)使用以及持續(xù)多長(zhǎng)時(shí)間
  3. 設(shè)備驅(qū)動(dòng)程序:充當(dāng)硬件與進(jìn)程之間的調(diào)解程序/解釋程序
  4. 系統(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í)間有多長(zhǎng)。

Linux內(nèi)核學(xué)習(xí)路線和框架圖

image

Linux Security Coaching

image

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詳解

Makefile文件負(fù)責(zé)編寫程序的編譯與運(yùn)行規(guī)則,免去命令行使用Clang去逐步編譯分析。

GDB詳解


GDB是一個(gè)強(qiáng)大的調(diào)試工具,通過它可以實(shí)現(xiàn)C程序代碼bug的調(diào)試。

GDB詳解

Linux崩潰調(diào)試


Linux內(nèi)核Crash下的問題解決方案:

Linux調(diào)試之崩潰

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)核模塊。

image

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)源碼分析記錄:

SECCROSS項(xiàng)目解讀

開發(fā)記錄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容