]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: fill SOCK.NETNS column for tuntap
authorMasatake YAMATO <yamato@redhat.com>
Wed, 4 Feb 2026 21:14:52 +0000 (06:14 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Tue, 24 Feb 2026 18:23:29 +0000 (03:23 +0900)
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 <yamato@redhat.com>
lsfd-cmd/cdev.c
lsfd-cmd/lsfd.1.adoc
lsfd-cmd/lsfd.h
lsfd-cmd/sock.c
tests/expected/lsfd/mkfds-cdev-tun-domestic-socknetns [new file with mode: 0644]
tests/expected/lsfd/mkfds-cdev-tun-foreign-socknetns [new file with mode: 0644]
tests/ts/lsfd/mkfds-cdev-tun

index a1e12e031458c83e672da5309025400c5a239ec4..d5dcc5569f04504d8550a230f7a924958903ecf2 100644 (file)
@@ -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,
index f15f2340d05810b13d4e52dc70d832d1c1ffea04..a17084374f514a36730594a716d02c16e4187e53 100644 (file)
@@ -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_]]
index 3a7e186890c0fea4cf76ee3dfe3537b41a665d02..35b2bcd24e510f6ab74745b6c9dd356280445740 100644 (file)
@@ -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
index 6a1b3b99491d609482143474a97df3926ce687e2..31c575eb4670b945d953984817f66d55caca3600 100644 (file)
@@ -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 (file)
index 0000000..d126a17
--- /dev/null
@@ -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 (file)
index 0000000..d126a17
--- /dev/null
@@ -0,0 +1 @@
+SOCK.NETNS: 0
index f6987401066266ba809255c48b3d1da605d734be..7d1be284a21ee3ecde60e72400aed8bb05c3310b 100755 (executable)
@@ -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]}"