species

package
v0.20.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2021 License: Apache-2.0 Imports: 3 Imported by: 5

Documentation

Overview

Package species defines the type constants and type names of the currently 8 Linux kernel namespace types ("species"). Furthermore, this package also defines how to represent namespace identifiers: they consist of not only an inode number, but also the device ID where a namespace inode is located on (but see the next section below). The species package also converts between the namespace type names (such as "mnt", "net", and so on) and their corresponding (Linux kernel) constants (CLONE_NEWxxx), as well as between the internal and textual representations of namespace identifiers.

Namespace Identifiers

Caveat: currently, the textual representation of namespace identifiers employed by the Linux kernel and CLI tools ignores the device ID part of a complete namespace identifier, but uses only the inode number.

Internally, all lxkns packages work with both the inode number as well as the device ID of a namespace. Please see also the notes below.

Namespace Type Constants

While Golang's x/sys/unix package finally defines even the formerly missing CLONE_NEWCGROUP constant (which was missing from the syscall package), this package still redefines the namespace-related CLONE_NEWxxx identifiers to be type-safe. This way, they cannot accidentally be mixed with other CLONE_xxx constants, or the CLONE_xxx flags in general.

To provide backwards compatibility with older Go versions, namely Go 1.13, this package defines CLONE_NEWTIME itself when there is no underlying unix.CLONE_NEWTIME available. Applications using lxkns should thus only use species. CLONE_NEWTIME in order to be shielded from variations in Go's unix package.

Index

Examples

Constants

View Source
const (
	CLONE_NEWNS     = NamespaceType(unix.CLONE_NEWNS)
	CLONE_NEWCGROUP = NamespaceType(unix.CLONE_NEWCGROUP)
	CLONE_NEWUTS    = NamespaceType(unix.CLONE_NEWUTS)
	CLONE_NEWIPC    = NamespaceType(unix.CLONE_NEWIPC)
	CLONE_NEWUSER   = NamespaceType(unix.CLONE_NEWUSER)
	CLONE_NEWPID    = NamespaceType(unix.CLONE_NEWPID)
	CLONE_NEWNET    = NamespaceType(unix.CLONE_NEWNET)
	CLONE_NEWTIME   = NamespaceType(cloneNewtime)
)

The 8 type of Linux namespaces defined at this time (sic!). Please note that the 8th namespace is only supported since Kernel 5.6+.

These constants are used with several of the namespace-related functions, such as clone() in particular, but also setns(), unshare(), and the NS_GET_NSTYPE ioctl(). The origin for their definitions is: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/sched.h

Oh, forgo golint with its "helicopter parents" attitude patronizing us about how names of Linux kernel definitions have to look like. Go for something grown up, such as golangci-lint, and many more, which hide the totally childish behavior of golint.

AllNS is the OR-ed bitmask of all currently defined (8) Linux-kernel namespace type constants.

Variables

View Source
var NoneID = NamespaceID{}

NoneID is a convenience for signalling an invalid or non-existing namespace identifier.

Functions

func IDwithType

func IDwithType(s string) (id NamespaceID, t NamespaceType)

IDwithType takes a string representation of a namespace instance, such as "net:[1234]", and returns the ID together with the type of the namespace (but see note below). In case the string is malformed or contains an unknown namespace type, IDwithType returns (NoneID, NaNS).

There is an important gotcha to be aware of: the Linux kernel only uses a namespace's inode number in its textual format, dropping the device ID where the namespace is located on. To work around this oversight and to allow for namespace IDs to be comparable using "==", IDwithType adds the missing device ID by guessing it from the net namespace of the current process at the time of its startup.

Example
id, t := IDwithType("mnt:[12345678]")
fmt.Printf("%q %d\n", t.Name(), id.Ino)
// "nonsense" namespace textual representations return an identifier of
// NoneID and a type of NaNS (not a namespace).
id, t = IDwithType("foo:[-1]")
fmt.Printf("%v %v\n", t, id)
Output:

"mnt" 12345678
NaNS NoneID

Types

type NamespaceID

type NamespaceID struct {
	Dev uint64 `json:"dev"` // device ID maintaining the namespace (Golang insists on uint64)
	Ino uint64 `json:"ino"` // inode number of this namespace.
}

NamespaceID represents a Linux kernel namespace identifier. NamespaceIDs can be compared for equality or inequality using Golang's "==" and "!=" operators. However, namespaceIDs are not ordered, so they cannot compared according to their order (they don't possess) using "<", et cetera.

While namespace identifiers currently use only 32bit values, we're playing safe here and keep with the 64bit-ness of inode numbers, as which they originally appear. Additionally, we also adhere to http://man7.org/linux/man-pages/man7/namespaces.7.html and also take the device a namespace inode lives on into consideration, to cover for a potential future with multiple namespace filesystems, as opposed to the single "nsfs" namespace filesystem of today.

Note, there are some caveats to watch for, such as that the current textual format used by the Linux kernel when rendering namespaces (references) as text does not cater for the device ID, but only a namespace's inode. The textual conversions in this package work around these limitations.

func NamespaceIDfromInode

func NamespaceIDfromInode(ino uint64) NamespaceID

NamespaceIDfromInode is an inconvenience helper that caters for the current chaos in that several sources of inodes, such as the kernel's own textual references and 3rd party CLI tools such as "lsns", only give a namespace's inode number, but not its device ID. It does so by glancing the missing device ID from one of our own process' net namespace (at the startup time) and then adds that in the hope that things still work correctly for the moment.

func (NamespaceID) String

func (nsid NamespaceID) String() string

String returns the namespace identifier in form of "NamespaceID(dev,#no)" as text, or "NoneID", if it is invalid. Please note that String on purpose does not use the text format used in the Linux kernel, as a namespace identifier has no namespace type information attached to it. Besides, not least it is used by Golang debuggers when rendering values, so we here follow Golang (tooling) convention.

type NamespaceType

type NamespaceType uint64

NamespaceType mirrors the data type used in the Linux kernel for the namespace type constants. These constants are actually part of the clone() syscall options parameter.

const NaNS NamespaceType = 0

NaNS identifies an invalid namespace type.

func NameToType

func NameToType(name string) NamespaceType

NameToType returns the namespace type value (constant CLONE_NEWNS, ...) corresponding to the specified namespace type name (such as "mnt", "net", et cetera).

Example
for _, name := range []string{
	"mnt", "cgroup", "uts", "ipc", "user", "pid", "net", "spam",
} {
	fmt.Printf("0x%08x\n", uint64(NameToType(name)))
}
Output:

0x00020000
0x02000000
0x04000000
0x08000000
0x10000000
0x20000000
0x40000000
0x00000000

func (NamespaceType) Name

func (nstype NamespaceType) Name() string

Name returns the type name string (such as "mnt", "net", ...) of a namespace type value.

Example
fmt.Println(CLONE_NEWCGROUP.Name())
Output:

cgroup

func (NamespaceType) String

func (nstype NamespaceType) String() string

String returns the Linux kernel namespace constant name for a given namespace type value.

Example
for _, t := range []NamespaceType{
	CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
	CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET,
} {
	fmt.Println(t.String())
}
Output:

CLONE_NEWNS
CLONE_NEWCGROUP
CLONE_NEWUTS
CLONE_NEWIPC
CLONE_NEWUSER
CLONE_NEWPID
CLONE_NEWNET

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL