天天看點

OpenWrt核心子產品開發(十)-linux核心多核處理資料封包流程分析 多核接口

文章目錄

    • linux核心多核機制
      • 資料轉發流程
      • 硬體中斷
      • CPU親和性
      • 軟體中斷
      • 核心cpu api
      • 源碼
      • 運作結果
    • 作者簡介
    • 源碼和文檔

linux核心多核機制

資料轉發流程

在協定棧資料封包轉發過程中,資料封包可能是來自cpu的不同核處理,當然前提是系統開啟了多核并且硬體支援。

這裡我們主要講解多核在資料轉發中的應用

先看看資料轉發基本流程:

OpenWrt核心子產品開發(十)-linux核心多核處理資料封包流程分析 多核接口

硬體中斷

中斷指當出現需要時,CPU暫時停止目前程式的執行轉而執行處理新情況的程式和執行過程。即在程式運作過程中,系統出現了一個必須由CPU立即處理的情況,此時,CPU暫時中止程式的執行轉而處理這個新的情況的過程就叫做中斷。

硬體中斷是一個異步信号, 表明需要注意, 或需要改變在執行一個同步事件.硬體中斷是由與系統相連的外設(比如網卡 硬碟 鍵盤等)自動産生的. 每個裝置或裝置集都有他自己的IRQ(中斷請求), 基于IRQ, CPU可以将相應的請求分發到相應的硬體驅動上(注: 硬體驅動通常是核心中的一個子程式, 而不是一個獨立的程序). 比如當網卡受到一個資料包的時候, 就會發出一個中斷.

  • 中斷表檢視

    在linux系統中,網卡收到資料封包後會通過硬體中斷通知cpu,并且資料通過DMA方式存放到緩沖區。網卡的IRQ cpu是固定的,可以通過/proc/interrupts檢視中斷數統計。

[email protected]:~# cat /proc/interrupts 
           CPU0       CPU1       
  0:          5          0   IO-APIC   2-edge      timer
  1:        677          0   IO-APIC   1-edge      i8042
  4:         18          0   IO-APIC   4-edge      ttyS0
  8:          0          1   IO-APIC   8-edge      rtc0
  9:          0          0   IO-APIC   9-fasteoi   acpi
 12:          0          5   IO-APIC  12-edge      i8042
 14:          0          0   IO-APIC  14-edge      ata_piix
 15:          0          0   IO-APIC  15-edge      ata_piix
 16:      72987        170   IO-APIC  16-fasteoi   eth1
 17:          0    1786766   IO-APIC  17-fasteoi   ioc0, ehci_hcd:usb1, eth2
 18:         65          0   IO-APIC  18-fasteoi   uhci_hcd:usb2
 56:          0          0   PCI-MSI 129024-edge      vmw_vmci
           

CPU親和性

雖然中斷cpu固定,當然我們也可以檢視和修改目前綁定的cpu

首先我們找到網絡接口eth1的中斷号,比如16

然後通過 /proc/irq/16/smp_affinity_list指令檢視目前綁定的cpu

[email protected]:~# cat /proc/irq/16/smp_affinity_list 
0-1
[email protected]:~# 
           

0-1表示目前綁定的cpu為cpu0和cpu1,包括兩個cpu

那現在如何讓eth1隻綁定到cpu0呢?

修改方式:設定/proc/irq/16/smp_affinity值

首先檢視目前值,目前為3(前面的0先不用管),3的二進制表示為11,表示0位和1為置為1,

也就是綁定了cpu0和cpu1。

[email protected]:~# cat /proc/irq/16/smp_affinity
00000000,00000003
[email protected]:~# 
           

那現在我們修改為cpu0的話,隻需要修改為1即可,對應的字元串為00000000,00000001

[email protected]:~# 
[email protected]:~# cat /proc/irq/16/smp_affinity
00000000,00000003
[email protected]:~# 
[email protected]:~# 
[email protected]:~# echo "00000000,00000001" >/proc/irq/16/smp_affinity
[email protected]:~# cat /proc/irq/16/smp_affinity
00000000,00000001
[email protected]:~# cat /proc/irq/16/smp_affinity_list 
0
[email protected]:~# 
           

通過以上操作,可以看到成功将eth1(中斷号16)綁定到了cpu 0,也就是通過硬體中斷上來的資料包都是通過cpu0處理(這裡還隻是資料處理的一部分,硬體中斷隻相當于上半部,下半部是軟中斷處理)。

軟體中斷

軟中斷的處理類似于硬中斷. 但是軟中斷僅僅由目前運作的程序産生.通常軟中斷是對一些I/O的請求.軟中斷僅與核心相聯系, 而核心主要負責對需要運作的任何其他程序進行排程.軟中斷不會直接中斷CPU, 也隻有目前正在運作的代碼(或程序)才會産生軟中斷. 軟中斷是一種需要核心為正在運作的程序去做一些事情(通常為I/O)的請求.有一個特殊的軟中斷是Yield調用, 它的作用是請求核心排程器去檢視是否有一些其他的程序可以運作.

協定的處理都是在軟體中斷環境中,從緩沖隊列中擷取到skb(資料封包)後開始一系列封包解包操作,比如路由、nat、過濾等,我們前面将的netfilter架構也在協定棧中,都是屬于網卡的軟體中斷觸發。

而軟體中斷中同一個接口也可能是不同cpu處理的,通過上面的流程圖應該可以很明确看出。中斷上半部緩存資料封包時,會判斷放在哪個隊列,判斷是有算法支撐的,會盡量保證隊列均衡,隊列個數和cpu個數相同,不同的隊列由不同的cpu處理,這樣就出現了并發的情況,對于臨界資源,需要加鎖處理,否則可能出現資料丢失或者不完整情況,特别是全局資料的操作。

核心cpu api

smp_processor_id 擷取目前處理的cpu id

for_each_possible_cpu(i) 擷取所有的cpu id

cpu_online(i) 檢視目前線上的cpu清單

源碼

#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/types.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("openwrt");
MODULE_DESCRIPTION("packet");

static u_int32_t packet_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
	int cpu = smp_processor_id();
    printk("packet handle cpu core = %d\n", cpu);
	return NF_ACCEPT;
}


static struct nf_hook_ops packet_ops[] __read_mostly = {
	{
		.hook		= packet_hook,
		.pf			= PF_INET,
		.hooknum	= NF_INET_FORWARD,
		.priority	= NF_IP_PRI_MANGLE + 1,
	},
};

static int __init smp_test_init(void)
{
    int cpu = smp_processor_id();
    printk("cur cpu = %d\n", cpu);
    int i;
    int count = 0;
    for_each_possible_cpu(i) {
        if (cpu_online(i)){
            printk("online cpu core: %d\n", i);
            count++;
        }
    }
    printk("total cpu core: %d\n", count);
    nf_register_net_hooks(&init_net, packet_ops, ARRAY_SIZE(packet_ops));
	return 0;
}

static void smp_test_exit(void)
{
    nf_unregister_net_hooks(&init_net, packet_ops, ARRAY_SIZE(packet_ops));
	return ;
}

module_init(smp_test_init);
module_exit(smp_test_exit);
           

運作結果

加載核心子產品列印目前處理的核,并且列出目前裝置所有的線上CPU

[email protected]:/# insmod smp_test.ko 
[email protected]:/# <4>[253513.942540] cur cpu = 1
<4>[253513.943316] online cpu core: 0
<4>[253513.944169] online cpu core: 1
<4>[253513.945158] total cpu core: 2

           

當有資料包轉發時,會列印每個資料包目前處理的cpu核,可以看到不同的資料包處理的核是不一樣的。

[email protected]:/# 
[email protected]:/# <4>[253534.694982] packet handle cpu core = 1
<4>[253534.771213] packet handle cpu core = 1
<4>[253534.772719] packet handle cpu core = 1
<4>[253534.773811] packet handle cpu core = 1
<4>[253534.774995] packet handle cpu core = 1
<4>[253534.859312] packet handle cpu core = 1
<4>[253534.861465] packet handle cpu core = 1
<4>[253534.945897] packet handle cpu core = 1
<4>[253535.151810] packet handle cpu core = 0
<4>[253535.153427] packet handle cpu core = 1
<4>[253535.154753] packet handle cpu core = 1
<4>[253535.157813] packet handle cpu core = 0
<4>[253535.314836] packet handle cpu core = 0
<4>[253535.316588] packet handle cpu core = 1
<4>[253535.317903] packet handle cpu core = 1
<4>[253535.319414] packet handle cpu core = 0
<4>[253536.448938] packet handle cpu core = 0

           

作者簡介

OpenWrt應用過濾插件作者(應用過濾用于控制app聯網,可以過濾遊戲、視訊、聊天等幾百款app)

從事嵌入式Linux開發近10年,主要負責路由器網通産品研發,精通OpenWrt系統,包括luci、消息機制、核心子產品等。擅長子產品:路由器上網行為管理、智能流控、上網認證、防火牆、虛拟伺服器、多wan負載均衡等

開源作品位址:

https://github.com/destan19/OpenAppFilter

源碼和文檔

關注微信公衆号可以擷取更多技術文檔、固件、源碼等

微信掃碼關注:

OpenWrt核心子產品開發(十)-linux核心多核處理資料封包流程分析 多核接口
OpenWrt核心子產品開發(十)-linux核心多核處理資料封包流程分析 多核接口
OpenWrt核心子產品開發(十)-linux核心多核處理資料封包流程分析 多核接口

繼續閱讀