---
# System prepended metadata

title: 2020-10-08 kernel network stack reading - network namespace -

---

---
lang: ja
breaks: false
---

<style>
.ui-infobar, #doc.markdown-body { max-width: 1100px; }
</style>

# 2020-10-08 kernel network stack reading - network namespace -

- 参加者: hayakawa, kawakami, taguchi, saito
- kernel: `5.6.6`
- ドライバー: hayakawa
- 今回のテーマ
    - network nemespaceの実態を知る
        - どんなリソースがnamespacingされているのか
        - どうやってnamespaceを識別するのか
        - ip netns addすると何が起こるのか？
        - ip link set netnsはなにをするのか？
        - ip netns execは何をするのか？
        - etc...


## 使用マシン
- 早川のローカルマシンのVagrant
- fedora/32-cloud-base
- Vagrant環境の構築方法は9/4に記載されている通り
    - https://hackmd.io/iMc0OpUESIWCNSr9DBC_sg?both#tinet%E3%81%A8ipftrace2%E7%92%B0%E5%A2%83%E3%81%AE%E6%A7%8B%E7%AF%89

## 現状わかっていること

- `struct net` が実質的なnetnsの実体らしい
- namespacingされるリソース
    - routing table
    - netfilter
    - procfs?
    - sysfs?
- unshare(2)

## メモ
- struct net
    - http://elixir-referencer.dev.linecorp.com/linux/latest/source/include/net/net_namespace.h#L56
- namespacingされているリソース
    - mib知らなかった
- Unix network namespaceとは？
- netns_ipv4/v6みたいなのがアドレスファミリーごとにある？
    - sysctlの設定もここに入ってる
    - http://elixir-referencer.dev.linecorp.com/linux/latest/source/include/net/netns/ipv4.h#L43
    - http://elixir-referencer.dev.linecorp.com/linux/latest/source/include/net/netns/ipv6.h#L56
- struct pernet_operations
- init_net => root namespace?
- per-process namespace => nsproxy
- struct proc_ns_operations
- unshareとsetnsの違い
    - unshareはnamespaceを作成して移動
    - setnsは指定されたnamespaceに移動

## ip netns addのstrace

```
getuid()                                = 0
socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE) = 3
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [32768], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1048576], 4) = 0
setsockopt(3, SOL_NETLINK, NETLINK_EXT_ACK, [1], 4) = 0
bind(3, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 0
getsockname(3, {sa_family=AF_NETLINK, nl_pid=3937, nl_groups=00000000}, [12]) = 0
setsockopt(3, SOL_NETLINK, NETLINK_DUMP_STRICT_CHK, [1], 4) = 0
openat(AT_FDCWD, "/proc/self/ns/net", O_RDONLY) = 4
sendto(3, {{len=28, type=RTM_GETNSID, flags=NLM_F_REQUEST, seq=0, pid=0}, {rtgen_family=AF_UNSPEC}, {{nla_len=8, nla_type=NETNSA_FD}, 4}}, 28, 0, NULL, 0) = 28
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{len=28, type=RTM_NEWNSID, flags=0, seq=0, pid=3937}, {rtgen_family=AF_UNSPEC}, {{nla_len=8, nla_type=NETNSA_NSID}, -1}}, iov_len=16384}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 28
close(4)                                = 0
socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE) = 4
setsockopt(4, SOL_SOCKET, SO_SNDBUF, [32768], 4) = 0
setsockopt(4, SOL_SOCKET, SO_RCVBUF, [1048576], 4) = 0
setsockopt(4, SOL_NETLINK, NETLINK_EXT_ACK, [1], 4) = 0
bind(4, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 0
getsockname(4, {sa_family=AF_NETLINK, nl_pid=-57337353, nl_groups=00000000}, [12]) = 0
mkdir("/var/run/netns", 0755)           = -1 EEXIST (File exists)
mount("", "/var/run/netns", 0x5566641d767f, MS_REC|MS_SHARED, NULL) = 0
openat(AT_FDCWD, "/var/run/netns/bazbaz", O_RDONLY|O_CREAT|O_EXCL, 000) = 5
close(5)                                = 0
openat(AT_FDCWD, "/proc/self/ns/net", O_RDONLY|O_CLOEXEC) = 5                          <= 現在のnamepaceを保持 fd=5
unshare(CLONE_NEWNET)                   = 0                                            <= 新しいnamespaceを作成し，新しいnamespaceに移動
mount("/proc/self/ns/net", "/var/run/netns/bazbaz", 0x5566641d767f, MS_BIND, NULL) = 0 <= 作成したnamespaceをmountし固定
setns(5, CLONE_NEWNET)                  = 0                                            <= 元のnamespaceに復帰 fd=5
close(5)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
```

## ip link set netnsの中身
- dev_change_net_namespaceが大事
- ifindexは可能な限り元のnamespaceでのifindexと同じにしようとする


## ip netns exec
- setns -> close -> unshare
- sysfsをマウントし直してくれる
- /etc/netns/NAME 以下にファイルを作るとマウントしてくれたりする


## nsenter 
- setns

## /etc/netns/NETNS_NAME
- このディレクトリに配置したファイルは、netns毎の`/etc`にマウントされる (bind mount)
- resolv.confをnetns毎に配置するのに使える


## 参考

- https://man7.org/linux/man-pages/man8/ip-netns.8.html
- https://www.man7.org/linux/man-pages/man2/unshare.2.html
- https://man7.org/linux/man-pages/man2/setns.2.html

