Documentation ¶
Overview ¶
Package model defines the core of lxkns information model: Linux kernel namespaces and processes, and how they relate to each other.
Linux namespaces partition certain OS resources and thus come in different types. At the moment, there are namespaces for partitioning cgroups, IPC, mounts, networks, PIDs, (monotonic) time, users, and UTS-related information (hostname, ...).
Namespaces have unique identifiers, but these are not names, but inode numbers (ignoring here the lost cause of device numbers on purpose).
Two types of namespaces are hierarchical: PID and user namespaces; all other types of namespaces are "flat" without any hierarchy defined within namespaces of the same type.
All namespaces are additionally owned by one user namespace or another. In case of user namespaces this ownership actually is the parent-child namespace relationship instead.
Namespaces may exist with processes, but also without any processes. The latter requires references to such a namespace in form of either bind mounts or parent-children relationships.
The lxkns information model shows which processes are currently "attached" to a specific namespace, if any. However, to reduce noise, the information model only references the "top-most" processes attached to a namespace, and leadership is simply based on the process tree. These "top-most" processes are also dubbed "leaders", and there's even a most senior leader process, the "ealdorman", based on its starting time since the Boot Epoch.
All other processes also attached to a specific namespace can then be found by following the process parent-child relationships, starting from the leader processes.
The lxkns information model thus also container the parent-child relationships between processes. In addition, lxkns also models how individual processes are attached to namespaces, so it's easy to quickly navigate forth and back between namespaces and processes. Each process is always attached to exactly one namespace of each type. However, "older" kernels lack time namespace support, so be prepared that references to time namespaces will be nil on these kernels.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var TypeIndexLexicalOrder = [NamespaceTypesCount]NamespaceTypeIndex{ CgroupNS, IPCNS, MountNS, NetNS, PIDNS, TimeNS, UserNS, UTSNS, }
TypeIndexLexicalOrder contains Namespace type indices in lexical order.
var TypesByIndex = [NamespaceTypesCount]species.NamespaceType{ species.CLONE_NEWNS, species.CLONE_NEWCGROUP, species.CLONE_NEWUTS, species.CLONE_NEWIPC, species.CLONE_NEWUSER, species.CLONE_NEWPID, species.CLONE_NEWNET, species.CLONE_NEWTIME, }
TypesByIndex maps Allnamespaces array indices to their corresponding Linux' kernel namespace clone() syscall constants.
Functions ¶
This section is empty.
Types ¶
type AllNamespaces ¶
type AllNamespaces [NamespaceTypesCount]NamespaceMap
AllNamespaces contains separate NamespaceMaps for all types of Linux kernel namespaces. This type allows package functions to work on multiple namespace types simultaneously in order to optimize traversal of the /proc filesystem, bind-mounts, et cetera. AllNamespaces thus stores "all" namespaces that could be discovered in the system, subject to discovery filtering.
func NewAllNamespaces ¶
func NewAllNamespaces() *AllNamespaces
NewAllNamespaces returns a fully initialized AllNamespaces object, ready to be filled with funny namespaces, such as "Kevin" and "Chantal".
type Hierarchy ¶
type Hierarchy interface { // Parent returns the parent user or PID namespace of this user or PID // namespace. If there is no parent namespace or the parent namespace in // inaccessible, then Parent returns nil. Parent() Hierarchy // Children returns a list of child PID or user namespaces for this PID or // user namespace. Children() []Hierarchy }
Hierarchy informs about the parent-child relationships of PID and user namespaces.
type Namespace ¶
type Namespace interface { // ID returns the unique identifier of this Linux-kernel namespace. This // identifier is basically a tuple consisting of an inode number from the // special "nsfs" namespace filesystem inside the Linux kernel, together // with the device ID of that nsfs filesystem. IDs cannot be set as only the // Linux allocates and manages them. ID() species.NamespaceID // Type returns the type of namespace in form of one of the NamespaceType, such // as species.CLONE_NEWNS, species.CLONE_NEWCGROUP, et cetera. Type() species.NamespaceType // Owner returns the user namespace "owning" this namespace. For user // namespaces, Owner always returns nil; use Hierarchy.Parent() instead, as // the owner of a user namespace is its parent user namespace. Owner() Ownership // Ref returns a filesystem path suitable for referencing this namespace. A zero // ref indicates that there is no reference path available: this is the case for // "hidden" PID and user namespaces sandwiched in between PID or user namespaces // where reference paths are available, because these other namespaces have // processes joined to them, or are either bind-mounted or fd-referenced. Hidden // PID namespaces can appear only when there is no process in any of their child // namespaces and the child PID namespace(s) is bind-mounted or fd-references // (the parent PID namespace is then kept alive because the child PID namespaces // are kept alive). Ref() string // Leaders returns an unsorted list of Process-es which are joined to this // namespace and which are the topmost processes in the process tree still // joined to this namespace. Leaders() []*Process // LeaderPIDs returns the list of leader PIDs. This is a convenience method for // those use cases where just a list of leader process PIDs is needed, but not // the leader Process objects themselves. LeaderPIDs() []PIDType // "leader" process PIDs only. // Ealdorman returns the most senior leader process. The "most senior" // process is the one which was created at the earliest, based on the start // times from /proc/[PID]/stat. Me thinks, me has read too many Bernard // Cornwell books. Wyrd bið ful aræd. Ealdorman() *Process // String describes this namespace with type, id, joined leader processes, // and optionally information about owner, children, parent. String() string }
Namespace represents a Linux kernel namespace in terms of its unique identifier, type, owning user namespace, joined (leader) processes, and some more.
type NamespaceMap ¶
type NamespaceMap map[species.NamespaceID]Namespace
NamespaceMap indexes a bunch of Namespaces by their identifiers. Usually, namespace indices will contain only namespaces of the same type.
type NamespaceStringer ¶
type NamespaceStringer interface { fmt.Stringer // TypeIDString describes this instance of a Linux kernel namespace just by // its type and identifier, and nothing else. TypeIDString() string }
NamespaceStringer describes a namespace either in its descriptive form when using the well-known String() method, or in a terse format when going for TypeIDString(), which only describes the type and identifier of a namespace.
type NamespaceTypeIndex ¶
type NamespaceTypeIndex int
NamespaceTypeIndex is an array index type for Linux kernel namespace types. It is used with the AllNamespaces type, which is an array of namespace maps, one map "id->namespace object" for each type of Linux kernel namespace. NamespaceTypeIndex must not be confused with the Linux' kernel namespace clone() syscall constants as typed as NamespaceType instead.
const ( MountNS NamespaceTypeIndex = iota // array index for mount namespaces map CgroupNS // array index for cgroup namespaces map UTSNS // array index for UTS namespaces map IPCNS // array index for IPC namespaces map UserNS // array index for user namespaces map PIDNS // array index for PID namespaces map NetNS // array index for net namespaces map TimeNS // array index for time namespaces map NamespaceTypesCount // number of namespace types )
Set of indices into AllNamespaces arrays, one for each type of Linux kernel namespace.
func TypeIndex ¶
func TypeIndex(nstype species.NamespaceType) NamespaceTypeIndex
TypeIndex returns the AllNamespaces array index corresponding with the specified Linux' kernel clone() syscall namespace constant. For instance, for CLONE_NEWNET the index NetNS is then returned.
type NamespacesSet ¶
type NamespacesSet [NamespaceTypesCount]Namespace
NamespacesSet contains a Namespace reference of each type exactly once. For instance, it represents the set of 7 namespaces a process will always be joined ("attached", ...) to. Processes cannot be not attached to each type of Linux kernel namespace.
type Ownership ¶
type Ownership interface { // UID returns the user ID of the process that created this user namespace. UID() int // Ownings returns all namespaces owned by this user namespace, with the // exception of user namespaces. "Owned" user namespaces are actually child // user namespaces, so they are returned through Hierarchy.Children() // instead. Ownings() AllNamespaces }
Ownership informs about the owning user ID, as well as the namespaces owned by a specific user namespace. Only user namespaces can execute Ownership.
type PIDType ¶
type PIDType int32
PIDType expresses things more clearly. And no, that's not a "PidType" since "PID" is an acronym (https://en.wikipedia.org/wiki/Acronym), but neither an abbreviation, nor an ordinary word (yet/still) in itself.
type Process ¶
type Process struct { PID PIDType `json:"pid"` // this process' identifier. PPID PIDType `json:"ppid"` // parent's process identifier. Parent *Process `json:"-"` // our parent's process description. Children []*Process `json:"-"` // child processes. Name string `json:"name"` // synthesized name of process. Cmdline []string `json:"cmdline"` // command line of process. Namespaces NamespacesSet `json:"-"` // the 7 namespaces joined by this process. Starttime uint64 `json:"starttime"` // time of process start, since the Kernel boot epoch. CpuCgroup string `json:"cpucgroup"` // (relative) path of CPU control group for this process. // (relative) path of freezer control group for this process. Please note // that for a cgroup v2 unified and non-hybrid hierarchy this path will // always be the same as for CpuCgroup. FridgeCgroup string `json:"fridgecgroup"` FridgeFrozen bool `json:"fridgefrozen"` // effective freezer state. }
Process represents our very limited view and even more limited interest in a specific Linux process. Well, the limitation comes from what we need for namespace discovery to be useful.
func NewProcess ¶
NewProcess returns a Process object describing certain properties of the Linux process with the specified PID. In particular, the parent PID and the name of the process, as well as the command line.
func (*Process) Basename ¶
Basename returns the process executable name with the directory stripped off, similar to what basename(1) does when applied to the "$0" argument. In case the basename would be empty, then the process name is returned instead as fallback.
type ProcessListByPID ¶
type ProcessListByPID []*Process
ProcessListByPID is a type alias for sorting slices of *Process by their PIDs in numerically ascending order.
func (ProcessListByPID) Len ¶
func (l ProcessListByPID) Len() int
func (ProcessListByPID) Less ¶
func (l ProcessListByPID) Less(i, j int) bool
func (ProcessListByPID) Swap ¶
func (l ProcessListByPID) Swap(i, j int)
type ProcessTable ¶
ProcessTable maps PIDs to their Process descriptions, allowing for quick lookups.
func NewProcessTable ¶
func NewProcessTable(freezer bool) (pt ProcessTable)
NewProcessTable takes returns the currently available processes (as usual, without tasks/threads). The process table is in fact a map, indexed by PIDs. When the freezer parameter is true then additionally the cgroup freezer states will also be discovered; as this might require switching into the initial mount namespace and this is possible in Go only when re-executing as a child, the caller must explicitly request this additional discovery.