From: Masatake YAMATO Date: Wed, 4 Feb 2026 21:14:52 +0000 (+0900) Subject: lsfd: fill SOCK.NETNS column for tuntap X-Git-Tag: v2.43-devel~46^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6fbf7a6de59fda8d8b98518ff4b6d38e1b4a5784;p=thirdparty%2Futil-linux.git lsfd: fill SOCK.NETNS column for tuntap There are two network namespaces associated with a file descriptor opening /dev/net/tun. One is the device network namespace (devnetns). A tun/tap file descriptor is associated with a network device, and the devnetns is the namespace in which that device exists. lsfd already provides this information via the TUN.DEVNETNS column. The other is the socket network namespace (socknetns). A tun/tap file descriptor is also associated with a socket, and the socknetns is the namespace in which that socket was created. lsfd already has the SOCK.NETNS column for reporting this information, but it was not filled for file descriptors opening /dev/net/tun. Signed-off-by: Masatake YAMATO --- diff --git a/lsfd-cmd/cdev.c b/lsfd-cmd/cdev.c index a1e12e031..d5dcc5569 100644 --- a/lsfd-cmd/cdev.c +++ b/lsfd-cmd/cdev.c @@ -382,6 +382,7 @@ static struct cdev_ops cdev_misc_ops = { struct tundata { const char *iff; ino_t devnetns; /* 0 implies no value given. */ + ino_t socknetns; }; static bool cdev_tun_probe(struct cdev *cdev) @@ -417,11 +418,13 @@ static char * cdev_tun_get_name(struct cdev *cdev) if (tundata == NULL || tundata->iff == NULL) return NULL; + xasprintf(&str, "iface=%s", tundata->iff); if (tundata->devnetns) - xasprintf(&str, "iface=%s devnetns=%llu", - tundata->iff, (unsigned long long)tundata->devnetns); - else - xasprintf(&str, "iface=%s", tundata->iff); + xstrfappend(&str, " devnetns=%llu", + (unsigned long long)tundata->devnetns); + if (tundata->socknetns) + xstrfappend(&str, " socknetns=%llu", + (unsigned long long)tundata->socknetns); return str; } @@ -454,6 +457,12 @@ static bool cdev_tun_fill_column(struct proc *proc __attribute__((__unused__)), return true; } break; + case COL_SOCK_NETNS: + if (tundata && tundata->socknetns) { + xasprintf(str, "%llu", (unsigned long long)tundata->socknetns); + return true; + } + break; } return false; } @@ -469,25 +478,20 @@ static int cdev_tun_handle_fdinfo(struct cdev *cdev, const char *key, const char return 0; } -#ifdef TUNGETDEVNETNS static bool cdev_tun_needs_target_fd(struct cdev *cdev) { struct tundata *tundata = cdev->cdev_data; return (tundata->iff != NULL); } -#else -static bool cdev_tun_needs_target_fd(struct cdev *cdev __attribute__((__unused__))) -{ - return false; -} -#endif /* TUNGETDEVNETNS */ -#ifdef TUNGETDEVNETNS static void cdev_tun_inspect_target_fd(struct cdev *cdev, int fd) { struct tundata *tundata = cdev->cdev_data; + tundata->socknetns = get_netns_from_socket(fd); + +#ifdef TUNGETDEVNETNS int nsfd = ioctl(fd, TUNGETDEVNETNS); struct stat sb; @@ -500,14 +504,8 @@ static void cdev_tun_inspect_target_fd(struct cdev *cdev, int fd) } close(nsfd); -} -#else -static void cdev_tun_inspect_target_fd(struct cdev *cdev __attribute__((__unused__)), - int fd __attribute__((__unused__))) -{ - /* Do nothing */ -} #endif /* TUNGETDEVNETNS */ +} static struct cdev_ops cdev_tun_ops = { .parent = &cdev_misc_ops, diff --git a/lsfd-cmd/lsfd.1.adoc b/lsfd-cmd/lsfd.1.adoc index f15f2340d..a17084374 100644 --- a/lsfd-cmd/lsfd.1.adoc +++ b/lsfd-cmd/lsfd.1.adoc @@ -307,7 +307,7 @@ inotify::: inodes=_INOTIFY.INODES_ + misc:tun::: -iface=_TUN.IFACE_[ devnetns=_TUN.DEVNETNS_] +iface=_TUN.IFACE_[ devnetns=_TUN.DEVNETNS_][ socknetns=_SOCK.NETNS_] + NETLINK::: protocol=_NETLINK.PROTOCOL_[ lport=_NETLINK.LPORT_[ group=_NETLINK.GROUPS_]] diff --git a/lsfd-cmd/lsfd.h b/lsfd-cmd/lsfd.h index 3a7e18689..35b2bcd24 100644 --- a/lsfd-cmd/lsfd.h +++ b/lsfd-cmd/lsfd.h @@ -328,6 +328,7 @@ void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns); bool is_nsfs_dev(dev_t dev); void load_fdsk_xinfo(ino_t netns_ino, int netns_fd); +ino_t get_netns_from_socket(int sk); /* * POSIX Mqueue diff --git a/lsfd-cmd/sock.c b/lsfd-cmd/sock.c index 6a1b3b994..31c575eb4 100644 --- a/lsfd-cmd/sock.c +++ b/lsfd-cmd/sock.c @@ -145,7 +145,7 @@ static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), } -static ino_t get_netns_from_socket(int sk) +ino_t get_netns_from_socket(int sk) { int nsfd; struct stat sb; diff --git a/tests/expected/lsfd/mkfds-cdev-tun-domestic-socknetns b/tests/expected/lsfd/mkfds-cdev-tun-domestic-socknetns new file mode 100644 index 000000000..d126a17e5 --- /dev/null +++ b/tests/expected/lsfd/mkfds-cdev-tun-domestic-socknetns @@ -0,0 +1 @@ +SOCK.NETNS: 0 diff --git a/tests/expected/lsfd/mkfds-cdev-tun-foreign-socknetns b/tests/expected/lsfd/mkfds-cdev-tun-foreign-socknetns new file mode 100644 index 000000000..d126a17e5 --- /dev/null +++ b/tests/expected/lsfd/mkfds-cdev-tun-foreign-socknetns @@ -0,0 +1 @@ +SOCK.NETNS: 0 diff --git a/tests/ts/lsfd/mkfds-cdev-tun b/tests/ts/lsfd/mkfds-cdev-tun index f69874010..7d1be284a 100755 --- a/tests/ts/lsfd/mkfds-cdev-tun +++ b/tests/ts/lsfd/mkfds-cdev-tun @@ -28,6 +28,8 @@ ts_check_test_command "$TS_HELPER_MKFDS" ts_check_test_command "$TS_CMD_UNSHARE" ts_check_test_command "$TS_CMD_LSNS" +ts_check_prog "ip" + ts_cd "$TS_OUTDIR" PID= @@ -39,12 +41,41 @@ if [[ -z "$MYNETNS" ]]; then ts_skip "the current netns is unknown" fi +cdev_tun_test_socknetns() +{ + local -r altnetns_name=mkfds-dev-tun-$$ + + local -r ifname=$1 + local -r pid=$2 + local -r expr=$3 + local -r localnetns=$4 + local altnetns + local socknetns + + # Move the tun device to another net namespace + if ip netns add "$altnetns_name"; then + ip link set dev "$ifname" netns "$altnetns_name" + altnetns=$(ip netns exec "$altnetns_name" stat -Lc %i /proc/self/ns/net) + socknetns=$(${TS_CMD_LSFD} -p "${pid}" -n --raw -o SOCK.NETNS -Q "${expr}") + ip netns del "$altnetns_name" + + if [[ "$localnetns" == "$socknetns" ]]; then + echo 'SOCK.NETNS': 0 + else + echo 'SOCK.NETNS': 1 + echo "expected SOCK.NETNS: $localnetns" + echo "actual SOCK.NETNS: $socknetns" + fi + fi +} + cdev_tun_test() { local unshare=$1 local tname local devnetns_available local netns + local output if [[ -z "$unshare" ]]; then tname=domestic @@ -108,6 +139,12 @@ cdev_tun_test() fi ts_finalize_subtest + ts_init_subtest "$tname"-socknetns + if [[ -n "$IFNAME" ]]; then + cdev_tun_test_socknetns \ + "$IFNAME" "${PID}" "${EXPR}" "$netns" > $TS_OUTPUT 2>&1 + fi + ts_finalize_subtest if [[ -n "$PID" ]]; then echo DONE >&"${MKFDS[1]}"