Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions unix/linux/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ struct termios2 {
#include <linux/nexthop.h>
#include <linux/nfc.h>
#include <linux/nl80211.h>
#include <linux/nsfs.h>
#include <linux/openat2.h>
#include <linux/perf_event.h>
#include <linux/pps.h>
Expand Down Expand Up @@ -537,6 +538,16 @@ struct my_ptp_perout_request {
unsigned int flags;
struct ptp_clock_time on;
};

// the one defined in linux/nsfs.h has anonymous nested struct
struct my_ns_id_req {
__u32 size;
__u32 spare;
__u64 ns_id;
__u32 ns_type;
__u32 spare2;
__u64 user_ns_id;
};
*/
import "C"

Expand Down Expand Up @@ -1090,6 +1101,22 @@ type OpenHow C.struct_open_how

const SizeofOpenHow = C.sizeof_struct_open_how

type NsIdReq C.struct_my_ns_id_req

const (
NS_ID_REQ_SIZE_VER0 = C.NS_ID_REQ_SIZE_VER0
LISTNS_CURRENT_USER = C.LISTNS_CURRENT_USER

TIME_NS = C.TIME_NS
MNT_NS = C.MNT_NS
CGROUP_NS = C.CGROUP_NS
UTS_NS = C.UTS_NS
IPC_NS = C.IPC_NS
USER_NS = C.USER_NS
PID_NS = C.PID_NS
NET_NS = C.NET_NS
)

const (
RESOLVE_BENEATH = C.RESOLVE_BENEATH
RESOLVE_IN_ROOT = C.RESOLVE_IN_ROOT
Expand Down
1 change: 1 addition & 0 deletions unix/syscall_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2032,6 +2032,7 @@ func Getrandom(buf []byte, flags int) (n int, err error) {
//sysnb Kill(pid int, sig syscall.Signal) (err error)
//sys Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG
//sys Lgetxattr(path string, attr string, dest []byte) (sz int, err error)
//sys Listns(req *NsIdReq, nsIds []uint64, flags uint) (n int, err error)
//sys Listxattr(path string, dest []byte) (sz int, err error)
//sys Llistxattr(path string, dest []byte) (sz int, err error)
//sys Lremovexattr(path string, attr string) (err error)
Expand Down
102 changes: 102 additions & 0 deletions unix/syscall_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,108 @@ func TestIoctlRetInt(t *testing.T) {
}
}

func TestListns(t *testing.T) {
callListns := func(tb testing.TB, req *unix.NsIdReq, nsIDs []uint64, flags uint, context string) int {
tb.Helper()
n, err := unix.Listns(req, nsIDs, flags)
if err != nil {
if errors.Is(err, unix.ENOSYS) {
tb.Skipf("listns syscall is not available (need Linux >= 6.19), skipping test: %v", err)
}
if errors.Is(err, unix.EPERM) || errors.Is(err, unix.EACCES) {
tb.Skipf("listns requires additional privileges in this environment, skipping test: %v", err)
}
tb.Fatalf("%s: Listns failed: %v", context, err)
}
if n < 0 || n > len(nsIDs) {
tb.Fatalf("%s: Listns returned unexpected count %d, want [0, %d]", context, n, len(nsIDs))
}
return n
}

t.Run("all namespaces", func(t *testing.T) {
req := &unix.NsIdReq{
Size: unix.NS_ID_REQ_SIZE_VER0,
Ns_id: 0,
Ns_type: 0,
User_ns_id: 0,
}
ids := make([]uint64, 64)
callListns(t, req, ids, 0, "all namespaces")
})

t.Run("network namespaces only", func(t *testing.T) {
req := &unix.NsIdReq{
Size: unix.NS_ID_REQ_SIZE_VER0,
Ns_id: 0,
Ns_type: uint32(unix.NET_NS),
User_ns_id: 0,
}
ids := make([]uint64, 64)
callListns(t, req, ids, 0, "network namespaces only")
})

t.Run("current user namespace owner", func(t *testing.T) {
req := &unix.NsIdReq{
Size: unix.NS_ID_REQ_SIZE_VER0,
Ns_id: 0,
Ns_type: 0,
User_ns_id: unix.LISTNS_CURRENT_USER,
}
ids := make([]uint64, 64)
callListns(t, req, ids, 0, "current user namespace owner")
})

t.Run("network and mount namespaces", func(t *testing.T) {
req := &unix.NsIdReq{
Size: unix.NS_ID_REQ_SIZE_VER0,
Ns_id: 0,
Ns_type: uint32(unix.NET_NS | unix.MNT_NS),
User_ns_id: 0,
}
ids := make([]uint64, 64)
callListns(t, req, ids, 0, "network and mount namespaces")
})

t.Run("pagination via ns_id", func(t *testing.T) {
const pageSize = 10
req := &unix.NsIdReq{
Size: unix.NS_ID_REQ_SIZE_VER0,
Ns_id: 0,
Ns_type: 0,
User_ns_id: 0,
}
ids := make([]uint64, pageSize)

total := 0
for {
n := callListns(t, req, ids, 0, "pagination")
if n == 0 {
break
}

// Continue from the last seen namespace ID.
last := ids[n-1]
if last == req.Ns_id {
t.Fatalf("pagination did not advance: last=%d", last)
}
total += n
req.Ns_id = last

// Partial batch means we've exhausted all results.
if n < pageSize {
break
}
}

t.Logf("total ns: %d", total)
if total == 0 {
t.Fatalf("pagination should return at least one namespace")
}
})

}

func TestIoctlGetRTCTime(t *testing.T) {
f, err := os.Open("/dev/rtc0")
if err != nil {
Expand Down
17 changes: 17 additions & 0 deletions unix/zsyscall_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions unix/ztypes_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.