iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0
自我挑戰組

Linux Kernel 網路巡禮系列 第 3

網路命名空間介紹

  • 分享至 

  • xImage
  •  

我們先回顧一下平常是如何使用 ip 指令來操作 network namespaceinterface

首先我們要先回憶一下,我們平常使用ip指令來操作network namespace和interface的方式

  • 使用 ip netns add <namespace_name> 指令來建立一個新的 network namespace。
  • 使用 ip netns exec <namespace_name> <command> 在指定的 network namespace 中執行指令。
  • 使用 ip link set <interface_name> netns <namespace_name>,將某個網路介面移動到指定的 network namespace。

netnet_device 資料結構

接下來,我們進入 Linux Kernel 的網路子系統,這看看兩個與 network namespaceinterface 密切相關的重要資料結構:struct netstruct net_device

邊提到的網路子系統主要對應到 source code 中的兩個部分,網路命名空間與網路設備。

https://ithelp.ithome.com.tw/upload/images/20240917/201527036iQkQpTe8v.png

net 資料結構代表了 Linux 中的 network namespace。當我們使用容器時,會利用 network namespace 來隔離容器網路,並提供獨立的網路堆疊。在 Linux Kernel 中,network namespace 是透過 net 結構來管理的。

net_device 資料結構則代表網路設備,也就是我們常說的介面(interface)。當我們使用 ip link list 指令列出所有的網路設備時,這些資訊就是從 net_device 結構中讀取出來的。

net_device 會在後續進行介紹,今天只會聚焦在 net結構上。

net 的結構

https://ithelp.ithome.com.tw/upload/images/20240917/20152703G0H1nKL25Y.png

在 Linux Kernel 中,所有的 net 結構會被串成一個雙向鏈結串列 double linked list,透過我們在前一天介紹過的 list_head 來維護。在 net 結構中,我們可以看到 struct list_head list; 這個欄位,它用來串連所有的 network namespace

// include/net/net_namespace.h
struct net {
    ...
    struct list_head	list;		/* list of network namespaces */
    ...
    struct list_head   dev_base_head;
    ...
    struct hlist_head 	*dev_name_head;
	struct hlist_head	*dev_index_head;
    ...
    struct net_device       *loopback_dev;          /* The loopback */
    ...
}

管理 net_device

net 結構中,有三個欄位用來保存 network namespace 中的網路設備(net_device):

  • dev_base_head:double link list,用來保存所有的網路設備。
  • dev_name_headdev_index_head:這兩個欄位則是使用 hash list 來維護網路設備,因為在日常操作中,我們經常需要透過網路介面的名稱或 Index 來查找設備。Linux Kernel 提供了 dev_get_by_namedev_get_by_index 這兩個函數,分別用來透過名稱或索引值查找網路設備,並使用 hash list 優化查找速度。

另外,我們還可以看到一個特殊的指標 loopback_dev,它指向了 lo 這個特殊的 loopback 介面。

https://ithelp.ithome.com.tw/upload/images/20240917/20152703s5tAFPDyeE.png

ns_common

// include/net/net_namespace.h
struct net {
    ...
    struct ns_common	ns;
    ...
}

// include/linux/ns_common.h
struct ns_common {
	atomic_long_t stashed;
	const struct proc_ns_operations *ops;
	unsigned int inum;
	refcount_t count;
};

net 裡面有一個特殊的子結構 struct ns_common nsns_common 是所有 Linux namespace (包含網路、mount, cgroup, ...) 都會使用到的一個通用結構。ns_common 保存了用於 /proc 檔案系統的資料,透過 ls /proc/<pid>/ns -l,我們可以看到每個 process 使用的不同 Linux namespace。每個 namespace 的檔案都會有一個 id,比如下列範例中 cgroup 的 id 是 4026531835,這個 id 便是保存在 ns_common.inum 這個欄位的數值。

> ls /proc/1/ns -l
lrwxrwxrwx 1 root root 0  九  15 16:28 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0  九  15 16:28 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0  九  15 16:28 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0  九  15 16:28 net -> 'net:[4026531992]'
lrwxrwxrwx 1 root root 0  九  15 16:28 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0  九  15 16:28 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0  九  15 16:28 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0  九  15 16:28 uts -> 'uts:[4026531838]'

ns_common/proc 的 ns 檔案是 user space 的 application 要操作 network namespace 時很重要的一個方式。下列是一個範例的程式碼,它打開了 process 123 的 network namespace 檔案,並呼叫 setns 這個函數。這個程式使用的 network namespace 就會被切換成與 process 123 相同的。

int main() {
    int fd = open("/proc/123/ns/net", O_RDONLY | O_CLOEXEC);
    setns(fd, CLONE_NEWNET);
    /* 做點甚麼 */
    return 0;
}

這邊先提到 struct ns_common ns 這個欄位的存在,後面我們會聊到這個切換機制是如何實現的,到時候這個欄位就會再次出現。

結論

今天我們初步介紹了 netnet_device 這兩個在 Linux Kernel 中極為重要的資料結構,以及 net 結構如何在 Kernel 內部組織與運作。接下來的幾天,我們將深入探討 net 結構的建立與管理。


上一篇
小試身手 - Double Linked List
下一篇
網路命名空間的建立
系列文
Linux Kernel 網路巡禮30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言