TAP / TUNデバイスを使用しているプロセスに正しく一致させたいのですが。外部ioctl()
これらのプロセスはTAP / TUNデバイスを使用します(つまり、プロセス自体内の特定のファイル記述子にアクセスできないため、sを実行できません)。
私は次の質問に対する答えを知っていますタブインターフェイスとそのファイル記述子間の接続を見つけるには?つまり、対応するTAP / TUNネットワークインターフェイスの名前を提供する追加のキーと値の/proc/[PID]/fdinfo/[FD]
ペアがあります。iff:
ただし、ネットワークネームスペースには問題があります。特に、ユーザー空間プロセスがネットワーク名前空間に接続された後、TAP / TUNネットワークインタフェースがネットワーク名前空間内を移動する場合に問題があります。これにはtapclient
単純なバリエーションがあります。a34729ttunclient.c
、タブネットワーク名を受け入れて追加します):
$ sudo ip tuntap add tap123 mode tap
$ sudo tapclient tap123 &
$ sudo ip netns add fooz
$ sudo ip link set tap123 netns fooz
$ PID=$(ps faux | grep tapclient | grep -v -e sudo -e grep | awk '{print $2}')
$ sudo cat /proc/$PID/fdinfo/3
...その後、以下を提供します。iff: tap123
- ただし、tap123
ネットワークインターフェイスが現在配置されているネットワークネームスペースではありません。
もちろん、tap123
すべてのネットワーク名前空間を繰り返して、それらの1つで一致するネットワークインターフェイスを見つけてそれを見つけることができます。残念ながら、tap123
最初の名前を上記のネットワークネームスペースに移動したfooz
後、ホストネームスペースに別の名前を作成した場合など、重複した名前がある可能性があります。
$ sudo ip tuntap add tap123 mode tap
$ ip link show tap123
$ sudo ip netns exec fooz ip link show tap123
だから私たちは今二つ tap123
は別々のネットワークネームスペースにあり、fdinfo
あいまいですiff: tap123
。
残念ながら、Tapclientのネットワークネームスペースを調べることは/proc/$PID/ns/net
役に立ちません。現在のネットワーク名前空間と一致しなくなったためですtap123
。
$ findmnt -t nsfs | grep /run/netns/fooz
$ sudo readlink /proc/$PID/ns/net
たとえば、これはnet:[4026532591]
vs。net:[4026531993]
tapclient
プロセスが接続されている正しいネットワークインターフェイスインスタンスと明示的に一致する方法はありますか?tap123
答え1
名前の代わりにハードウェアアドレスでtunインターフェースを一致させることができます(ioctl(SIOCGIFHWADDR)
tun / tapファイル記述子からアドレスを取得できます)。
これより簡単なことはないと思います。それ以外の場合、最近の変更は次のとおりです。これ(これにより、tun fdを介してインターフェイスのネットワークネームスペースを取得する必要がなくなり、許容される可能性が高くなります。
答え2
残念ながら、user313992のヒントSIOCGSKNS
は非常にソケットに便利SIOCGSKNS
、TAP/TUNファイル記述子の実装は次のとおりです。奇妙な:TAP / TUNが元々作成されたネットワークネームスペースのfdを返します。現在は該当しませんnetdevネットワークネームスペース。
もっと見る__tun_chr_ioctl
実装された場合、SIOCGSKNS
非常に有望であることがわかりました。TUNGETDEVNETNS
ioctlアクション:最終的にTAP / TUNデバイスのネットワーク名前空間を取得して返します。
次のユニットテストコードは、初期ネットワークネームスペースにTAPデバイスを作成し、新しいネットワークネームスペースを作成し、TAP netdevをこの新しいネットワークネームスペースに移動します。その後、ioctlは、TUNGETDEVNETNS
TAP netdevが移動された新しいネットワーク名前空間を参照するfdを正しく返します。
package main
import (
"os"
"runtime"
"github.com/thediveo/notwork/link"
"github.com/thediveo/notwork/netns"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/thediveo/success"
)
const tapNamePrefix = "tap-"
// Ugly IOCTL stuff; copied from github.com/thediveo/lxkns/ops/ioctl.go
const _IOC_NRBITS = 8
const _IOC_TYPEBITS = 8
const _IOC_SIZEBITS = 14
const _IOC_NRSHIFT = 0
const _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
const _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
const _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
const _IOC_NONE = uint(0)
func _IOC(dir, ioctype, nr, size uint) uint {
return (dir << _IOC_DIRSHIFT) | (ioctype << _IOC_TYPESHIFT) | (nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT)
}
func _IO(ioctype, nr uint) uint {
return _IOC(_IOC_NONE, ioctype, nr, 0)
}
func getTapNetdevNetnsFd(fd int) (int, error) {
return unix.IoctlRetInt(fd, _IO('T', 227))
}
var _ = Describe("TAP/TUN netns", func() {
It("finds namespace of TAP/TUN netdev", func() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
By("creating a TAP netdev")
tt := netlink.Tuntap{
Mode: netlink.TUNTAP_MODE_TAP,
Queues: 1,
}
tap := link.NewTransient(&tt, tapNamePrefix).(*netlink.Tuntap)
Expect(tap.Fds).NotTo(BeEmpty())
for _, fd := range tap.Fds {
DeferCleanup(func() { fd.Close() })
}
By("creating a new transient network namespace")
newnetnsfd := netns.NewTransient()
By("moving the TAP netdev into the new network namespace")
Expect(netlink.LinkSetNsFd(tap, newnetnsfd)).To(Succeed())
Expect(netlink.LinkList()).NotTo(ContainElement(
HaveField("Attrs().Name", tap.Name)))
nlh := netns.NewNetlinkHandle(newnetnsfd)
defer func() {
Expect(nlh.LinkSetNsPid(tap, os.Getpid())).To(Succeed())
nlh.Close()
}()
Expect(nlh.LinkList()).To(ContainElement(
HaveField("Attrs().Name", tap.Name)))
By("querying the network namespace of the TAP netdev")
tapnetnsfd := Successful(getTapNetdevNetnsFd(int(tap.Fds[0].Fd())))
defer unix.Close(tapnetnsfd)
Expect(netns.Ino(tapnetnsfd)).NotTo(Equal(netns.CurrentIno()))
Expect(netns.Ino(tapnetnsfd)).To(Equal(netns.Ino(newnetnsfd)))
})
})