深入理解Linux網絡隨筆(七):容器網絡虛擬化--Veth設備對

深入理解Linux網絡隨筆(七):容器網絡虛擬化

微服務架構中服務被拆分成多個獨立的容器,docker網絡虛擬化的核心技術為:Veth設備對、Network Namespace、Bridg。

Veth設備對

veth設備是一種 成對 出現的虛擬網絡接口,作用是 在 Linux 網絡命名空間或不同網絡棧之間建立一個虛擬的點對點連接,實現數據通信。例如實現容器與宿主機間的通信、不同neths間傳遞流量。

如圖所示:

虛擬網絡設備并不會直接連接物理網絡設備,而是一端連接到協議棧,另一端連接到另一個 veth 設備。從一對 veth 設備中發出的數據包會直接傳送到另一個 veth 設備。每個 veth 設備都可以配置 IP 地址,并作為 路由的一個接口,可以進行IP層通信。
在這里插入圖片描述

特點:

(1)成對出現:創建時總是 兩個設備*成對出現,例如 veth0veth1,它們之間類似于一條網絡隧道

(2)工作方式:一端發送的流量會從另一端收到,就像網線直連一樣

(3)不處理 L2/L3 轉發:veth 設備 不會執行交換、路由*等功能,只是簡單地在兩端傳輸數據包

底層源碼分析

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

veth設備的初始化通過函數veth_init進行。

static __init int veth_init(void)
{//注冊veth_link_ops veth設備的操作方法return rtnl_link_register(&veth_link_ops);
}

veth_link_ops中定義了veth設備的操作回調函數。

static struct rtnl_link_ops veth_link_ops = {.kind		= DRV_NAME,//設備類型.priv_size	= sizeof(struct veth_priv),//私有數據大小.setup		= veth_setup,//設備啟動.validate	= veth_validate,//檢查netlink請求參數的合法性.newlink	= veth_newlink,//處理新建的veth設備回調函數.dellink	= veth_dellink,//處理刪除的veth設備回調函數.policy		= veth_policy,//netlink配置參數解析策略.maxtype	= VETH_INFO_MAX,// netlink 解析時允許的最大屬性編號.get_link_net	= veth_get_link_net,// 獲取 veth 設備所在的網絡命名空間.get_num_tx_queues	= veth_get_num_queues,// 獲取設備的 TX 隊列數.get_num_rx_queues	= veth_get_num_queues,// 獲取設備的 RX 隊列數
};

veth設備創建調用veth_newlink函數。

static int veth_newlink(struct net *src_net, struct net_device *dev,struct nlattr *tb[], struct nlattr *data[],struct netlink_ext_ack *extack)
{int err;struct net_device *peer;struct veth_priv *priv;char ifname[IFNAMSIZ];struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;unsigned char name_assign_type;struct ifinfomsg *ifmp;struct net *net;.....//創建peer設備peer = rtnl_create_link(net, ifname, name_assign_type,&veth_link_ops, tbp, extack);if (IS_ERR(peer)) {put_net(net);return PTR_ERR(peer);}....//注冊peer設備err = register_netdevice(peer);...//獲取dev的私有數據privpriv = netdev_priv(dev);//將dev的指針賦值給peer的私有數據peer->priv,建立連接,通過dev訪問peer設備rcu_assign_pointer(priv->peer, peer);//初始化dev的TX、RX隊列err = veth_init_queues(dev, tb);if (err)goto err_queues;//獲取 peer 設備的 priv 結構體priv = netdev_priv(peer);//讓 peer->priv->peer 指向 dev,建立 veth 設備對的雙向連接rcu_assign_pointer(priv->peer, dev);//初始化peer設備的隊列err = veth_init_queues(peer, tb);if (err)goto err_queues;.....
}

啟動veth設備,通過veth_netdev_ops操作表找到發送過程中的回調函數veth_xmit。

static void veth_setup(struct net_device *dev)
{ether_setup(dev);dev->priv_flags &= ~IFF_TX_SKB_SHARING;dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;dev->priv_flags |= IFF_NO_QUEUE;dev->priv_flags |= IFF_PHONY_HEADROOM;//veth操作列表dev->netdev_ops = &veth_netdev_ops;dev->ethtool_ops = &veth_ethtool_ops;dev->features |= NETIF_F_LLTX;dev->features |= VETH_FEATURES;dev->vlan_features = dev->features &~(NETIF_F_HW_VLAN_CTAG_TX |NETIF_F_HW_VLAN_STAG_TX |NETIF_F_HW_VLAN_CTAG_RX |NETIF_F_HW_VLAN_STAG_RX);dev->needs_free_netdev = true;dev->priv_destructor = veth_dev_free;dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;dev->max_mtu = ETH_MAX_MTU;dev->hw_features = VETH_FEATURES;dev->hw_enc_features = VETH_FEATURES;dev->mpls_features = NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE;netif_set_tso_max_size(dev, GSO_MAX_SIZE);
}
static const struct net_device_ops veth_netdev_ops = {.ndo_init            = veth_dev_init,.ndo_open            = veth_open,.ndo_stop            = veth_close,.ndo_start_xmit      = veth_xmit,//veth發送函數.ndo_get_stats64     = veth_get_stats64,.ndo_set_rx_mode     = veth_set_multicast_list,.ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER.ndo_poll_controller	= veth_poll_controller,
#endif.ndo_get_iflink		= veth_get_iflink,.ndo_fix_features	= veth_fix_features,.ndo_set_features	= veth_set_features,.ndo_features_check	= passthru_features_check,.ndo_set_rx_headroom	= veth_set_rx_headroom,.ndo_bpf		= veth_xdp,.ndo_xdp_xmit		= veth_ndo_xdp_xmit,.ndo_get_peer_dev	= veth_peer_dev,
};
通信過程

數據包發送過程中到達網絡設備層會進入dev_hard_start_xmit函數,遍歷鏈表上的所有skb包調用xmit_one發送數據包。

//網絡設備數據包發送路徑(TX Path) 的關鍵部分,負責調用底層驅動的 ndo_start_xmit() 發送數據包
static int xmit_one(struct sk_buff *skb, struct net_device *dev,struct netdev_queue *txq, bool more)
{unsigned int len;int rc;//監測是否有協議棧上層監聽if (dev_nit_active(dev))//AF_PACKET 套接字正在監聽,發送數據包副本給監聽進程dev_queue_xmit_nit(skb, dev);
//記錄數據包長度len = skb->len;//觸發tracepoint機制,記錄數據包發送開始trace_net_dev_start_xmit(skb, dev);//調用底層驅動的ndo_start_xmit()方法發送數據包rc = netdev_start_xmit(skb, dev, txq, more);trace_net_dev_xmit(skb, rc, dev, len);return rc;
}

獲取驅動設備回調函數集合ops,結構體net_device_ops,調用__netdev_start_xmit發送數據包。

static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev,struct netdev_queue *txq, bool more)
{const struct net_device_ops *ops = dev->netdev_ops;netdev_tx_t rc;//發送數據包rc = __netdev_start_xmit(ops, skb, dev, more);if (rc == NETDEV_TX_OK)txq_trans_update(txq);return rc;
}

在這里會首先判斷當前cpu發送隊列是否還有數據待處理,然后調用驅動的ndo_start_xmit函數發送數據包,回調函數veth_xmit,lo是loopback_xmit。也就是在veth啟動的時候注冊的回調函數。

static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,struct sk_buff *skb, struct net_device *dev,bool more)
{__this_cpu_write(softnet_data.xmit.more, more);return ops->ndo_start_xmit(skb, dev);
}

veth_xmit核心是獲取veth設備數據,將數據發送到對端設備。

static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{struct veth_priv *rcv_priv, *priv = netdev_priv(dev);struct veth_rq *rq = NULL;int ret = NETDEV_TX_OK;struct net_device *rcv;int length = skb->len;bool use_napi = false;int rxq;rcu_read_lock();//獲取veth設備rcv = rcu_dereference(priv->peer);...//獲取rcv設備私有數據rcv_priv = netdev_priv(rcv);//獲取skb隊列索引rxq = skb_get_queue_mapping(skb);if (rxq < rcv->real_num_rx_queues) {rq = &rcv_priv->rq[rxq];//rq綁定了napi,且數據包適合GRO,開啟NAPI機制輪詢數據包use_napi = rcu_access_pointer(rq->napi) &&veth_skb_is_eligible_for_gro(dev, rcv, skb);}skb_tx_timestamp(skb);//嘗試將skb轉發到對端veth設備if (likely(veth_forward_skb(rcv, skb, rq, use_napi) == NET_RX_SUCCESS)) {//未使用NAPI機制,更新統計信息if (!use_napi)dev_sw_netstats_tx_add(dev, 1, length);} else {
.....
}

veth_forward_skb會根據數據包選擇不同路徑,數據包轉發到對端設備dev_forward_skb,對端開啟XDP則調用veth_xdp_rx,普通數據包調用netif_rx

static int veth_forward_skb(struct net_device *dev, struct sk_buff *skb,struct veth_rq *rq, bool xdp)
{return __dev_forward_skb(dev, skb) ?: xdp ?veth_xdp_rx(rq, skb) :__netif_rx(skb);
}

函數調用關系:__dev_forward_skb-->__dev_forward_skb2-->____dev_forward_skb

//處理dev設備的轉發數據包
static int __dev_forward_skb2(struct net_device *dev, struct sk_buff *skb,bool check_mtu)
{//實際數據包轉發處理int ret = ____dev_forward_skb(dev, skb, check_mtu);if (likely(!ret)) {//將skb所屬設備設置成剛才取到的veth對端設備rcvskb->protocol = eth_type_trans(skb, dev);//修正skb校驗和skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);}return ret;
}

eth_type_trans設置完成會繼續執行__netif_rx路徑,函數調用邏輯netif_rx_internal-->enqueue_to_backlog,在這里獲取每個CPU核心對應的softnet_data數據結構,將skb添加到等待隊列input_pkt_queue,在函數__test_and_set_bit檢查sd->backlog.state是否已包含 NAPI_STATE_SCHEDNAPI_STATE_SCHED是NAPI輪詢處理的一個 狀態標志位防止同一個 NAPI 任務被重復調度,未設置調用napi_schedule_rps觸發NAPI調度,觸發軟中斷 NET_RX_SOFTIRQ

static int enqueue_to_backlog(struct sk_buff *skb, int cpu,unsigned int *qtail)
{enum skb_drop_reason reason;struct softnet_data *sd;unsigned long flags;unsigned int qlen;//丟包原因:未指定reason = SKB_DROP_REASON_NOT_SPECIFIED;sd = &per_cpu(softnet_data, cpu);if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state))napi_schedule_rps(sd);
.....
}

在這里根據是否開啟RPS機制走不同的路徑,RPS 是 Linux 內核的一種 多核負載均衡機制將收到的數據包分配到多個 CPU 進行處理,避免所有網絡流量只由單個 CPU 處理,減少 CPU 瓶頸,在這里通過rps_ipi_list將數據包從一個CPU轉發到另外一個CPU上,提高多核環境下的負載均衡,減少CPU之間的競爭。如果沒有開啟RPS機制,數據包會在當前CPU軟中斷上下文中處理NAP任務。

static int napi_schedule_rps(struct softnet_data *sd)
{struct softnet_data *mysd = this_cpu_ptr(&softnet_data);
// RPS將接收的數據包調度到 不同的 CPU 進行處理
#ifdef CONFIG_RPS
//sd不等于mysd,說明要在另一個 CPU 上執行 NAPI 任務,而不是本 CPU 處理if (sd != mysd) {//rps_ipi_list 負責存儲要在其他 CPU 處理的 softnet_data 隊列,并通過 NET_RX_SOFTIRQ 觸發軟中斷來完成調度。sd->rps_ipi_next = mysd->rps_ipi_list;mysd->rps_ipi_list = sd;//出發軟中斷,處理softnet_data隊列的NAPI任務__raise_softirq_irqoff(NET_RX_SOFTIRQ);return 1;}
//本地CPU處理
#endif /* CONFIG_RPS */
//直接調度 mysd->backlog 設備的 NAPI 任務,并安排 net_rx_action() 來執行數據包處理。__napi_schedule_irqoff(&mysd->backlog);return 0;
}

實踐操作

Linux 中創建 veth 設備對,設備名veth,指定的虛擬網卡類型為veth,創建的另一端設備名為veth1。

ip link add veth0 type veth peer name veth1

使用ip link show可以看到veth0veth1 設備已創建,但還未啟用。

在這里插入圖片描述

veth設備需要配置IP地址才能進行通信,為veth0veth1 設備配置ip。

sudo ip addr add 192.168.1.1/24 dev veth0
sudo ip addr add 192.168.1.2/24 dev veth1

啟動設備

sudo ip link set veth1 up
sudo ip link set veth0 up

使用ip link show可以看到veth0veth1 設備狀態已變成開啟

在這里插入圖片描述

為了使veth設備之間能夠順利通信,需要關閉反向路徑過濾(rp_filter)并設置允許接收本機數據包。root角色下修改系統配置如下:

!

ping測試veth0veth1 設備間通信

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73353.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73353.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73353.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

電氣制作行業

電氣制作是一個涉及多種技能和工藝的領域&#xff0c;主要包括電氣設備的組裝、布線、調試等工作。以下是電氣制作的一般流程和相關要點&#xff1a; 設計與規劃 - 需求分析&#xff1a;明確電氣設備的功能、性能要求&#xff0c;以及使用環境、安全標準等因素。 - 電路設計…

【Flutter】數據庫實體類構造函數加密注意事項

源代碼&#xff1a; AccountEntity( {required String account, required String password,}) : account encrypter.encrypt(account,iv: iv).base64, password encrypter.encrypt(password,iv: iv).base64,; 解密代碼&#xff1a; static final encrypter Encrypter(AES…

PMP沖刺每日一題(30)

試題1 標題&#xff1a;在項目執行期間&#xff0c;一名團隊成員識別到由以前未被識別為項目相關方的職能經理提交了新需求。項目經理應該怎么做? A、與項目發起人開會&#xff0c;獲得反饋 B、啟動實施整體變更控制過程 C、對需求執行成本效益分析 D、將該職能經理添加進溝通…

一文講通鎖標記對象std::adopt_lock盲點

一文講通鎖標記對象std::adopt_lock盲點 1. 核心概念2. 代碼詳解1. 單個鎖2. 多重鎖(可以用來預防死鎖)3. 條件變量的互斥控制4. 復雜示例: 多生產者-多消費者模型(超綱了&#xff0c; 可不看&#xff0c;哈哈哈哈) 3. 小結 1. 核心概念 在C中&#xff0c; std::adopt_lock是一…

LVI-SAM、VINS-Mono、LIO-SAM算法的閱讀參考和m2dgr數據集上的復現(留作學習使用)

ROS一鍵安裝參考&#xff1a; ROS的最簡單安裝——魚香一鍵安裝_魚香ros一鍵安裝-CSDN博客 opencv官網下載4.2.0參考&#xff1a;https://opencv.org/releases/page/3/ nvidia驅動安裝:ubuntu18.04 安裝顯卡驅動 - 開始戰斗 - 博客園 cuda搭配使用12 cuda安裝1&#xff1a;Ub…

基于jspm校園安全管理系統(源碼+lw+部署文檔+講解),源碼可白嫖!

摘要 隨著信息時代的來臨&#xff0c;過去信息校園安全管理方式的缺點逐漸暴露&#xff0c;本次對過去的校園安全管理方式的缺點進行分析&#xff0c;采取計算機方式構建校園安全管理系統。本文通過閱讀相關文獻&#xff0c;研究國內外相關技術&#xff0c;提出了一種集安全教…

基于NXP+FPGA軌道交通3U機箱結構牽引控制單元

基于NXPFPGA軌道交通異步電機牽引控制單元(TCU-IM) 異步電機牽引控制單元&#xff08;TCU-IM&#xff09;用于牽引逆變器-異步電機構成的牽引電傳動系統&#xff0c;可采用車控或架控方式。執行高性能異步電機復矢量控制策略&#xff0c;具有響應迅速、有效可靠的防空轉滑行控制…

《CircleCI:CircleCI:解鎖軟件開發持續集成(CI)和持續部署(CD)高效密碼》:此文為AI自動生成

《CircleCI&#xff1a;CircleCI&#xff1a;解鎖軟件開發持續集成&#xff08;CI&#xff09;和持續部署&#xff08;CD&#xff09;高效密碼》&#xff1a;此文為AI自動生成 一、CircleCI 初印象 在當今軟件開發的快節奏賽道上&#xff0c;持續集成&#xff08;CI&#xff…

基于MySQL有用戶管理的音樂播放器

基于MySQL的音樂器 帶有用戶登錄功能驗證用戶身份&#xff0c;用戶注冊等操作還有用戶音樂列表&#xff0c;以及增刪查改操作 INSERT into users(username,passwd,phone_number,created_time,role) VALUES(‘張三’,‘123456’,‘123’,‘2025-3-11’,‘1’) 三張表&#xf…

差分專題練習 ——基于羅勇軍老師的《藍橋杯算法入門C/C++》

一、1.重新排序 - 藍橋云課 算法代碼&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e5 3;int a[N], d[N], cnt[N];int main() {int n; scanf("%d", &n);for (int i 1; i < n; i) scanf("%d", &a[i]);int m…

AI+視頻監控電力巡檢:EasyCVR視頻中臺方案如何賦能電力行業智能化轉型

隨著電力行業的快速發展&#xff0c;電力設施的安全性、穩定性和運維效率變得至關重要。傳統視頻監控系統在實時性、智能化及多系統協同等方面面臨嚴峻挑戰。EasyCVR視頻中臺解決方案作為一種先進的技術手段&#xff0c;在電力行業中得到了廣泛應用&#xff0c;為電力設施的監控…

【哈希表與字符串的算法之路:思路與實現】—— LeetCode

文章目錄 兩數之和面試題01.02.判定是否為字符重排存在重復元素存在重復元素||字母異位詞分組最長公共前綴和最長回文子串二進制求和字符串相乘 兩數之和 這題的思路很簡單&#xff0c;在讀完題目之后&#xff0c;便可以想到暴力枚舉&#xff0c;直接遍歷整個數組兩遍即可&…

RabbitMQ入門:從安裝到高級消息模式

文章目錄 一. RabbitMQ概述1.1 同步/異步1.1.1 同步調用1.1.2 異步調用 1.2 消息中間件1.2.1 概念1.2.2 作用1.2.3 常見的消息中間件1.2.4 其他中間件 1.3 RabbitMQ1.3.1 簡介1.3.2 特點1.3.3 方式1.3.4 架構1.3.5 運行流程 二. 安裝2.1 Docker 安裝 RabbitMQ 三. 簡單隊列&…

kernel與modules解耦

一、耦合&#xff1a; linux的kernel與modules存在耦合版本匹配&#xff0c;在版本不匹配&#xff08;內核重新編譯后&#xff0c;或者驅動模塊編譯依賴的內核版本跟運行版本不匹配&#xff09;時候&#xff0c;會存在insmod 驅動模塊失敗的情形&#xff1b; 二、解耦&#xff…

物理約束神經網絡(PINN)和有限元方法哪個更接近“真正的物理規律”?還是兩者只是不同的數學表達?

物理約束神經網絡(Physics-Informed Neural Networks, PINN)和有限元方法(Finite Element Method, FEM)是兩種在科學計算和工程模擬中廣泛應用的數值方法。PINN 依賴深度學習來近似微分方程的解,并在訓練過程中將物理約束作為損失項融入網絡,而 FEM 通過將連續介質的物理…

UI程序的std::cout重定向輸出到Visual Studio的debug輸出窗口

常用代碼。 UI程序的std::cout重定向輸出到Visual Studio的debug輸出窗口 #include <iostream> #include <streambuf> #include <vector> #include <string> #include <afxwin.h> //MFC// 自定義 streambuf 類&#xff0c;用于重定向輸出到 Vis…

Python開發合并多個PDF文件

前言 在我們的工作中&#xff0c;可能有以下場景需要用到合并多個PDF&#xff1a; 文檔歸檔&#xff1a;在企業或組織中&#xff0c;常常需要將相關的文檔&#xff08;如合同、報告、發票等&#xff09;合并為一個PDF文件&#xff0c;以便于歸檔和管理。 報告生成&#xff1a;在…

DeepSeek 助力 C++ 開發:探索智能編程新境界

這篇文章就會詳細講講 DeepSeek 在 C 開發里到底能怎么用&#xff0c;從上面說的寫代碼、找錯誤、優化性能&#xff0c;到管理項目這些方面&#xff0c;還會給出好多實際的代碼例子&#xff0c;講講實際用起來是啥情況。目的就是給那些做 C 開發的人&#xff0c;一份全面又詳細…

C#-使用VisualStudio編譯C#工程

一.創建csproj文件 二.創建源cs文件 三.生成解決方案 四.運行解決方案 五.VisualStudio功能列表 <1.代碼格式化: CtrlKD完成代碼整體格式化 <2.窗口布局 窗口->重置窗口布局 <3.引用查找&關聯 <4.包管理 <5.日志輸出級別 工具->選項->項目解決方案…

Kafka相關的面試題

以下是150道Kafka相關的面試題及簡潔回答&#xff1a; Kafka基礎概念 1. 什么是Kafka&#xff1f; Kafka是一個分布式、可擴展、容錯的發布-訂閱消息系統&#xff0c;最初由LinkedIn開發&#xff0c;現為Apache項目。它適用于高吞吐量的場景&#xff0c;如大數據處理和實時數據…