My current understanding of Linux (kernel) namespaces is that their lifetime after creation is as long as at least one of the following conditions holds true:
- at least one process/thread is joined (attached, ...) to namespace X.
- at least one bind-mount exists to namespace X.
- at least one open fd exists referencing namespace X.
- for user/PID namespaces: at least one child namespace Y of X exists.
Naively, I would have thought that the Linux kernel destroys a namespace "as soon" as none of the above conditions holds true anymore. However, I notice that there is some delay between a namespace becoming obsolete and it becoming destroyed ... if I'm not mistaken, that is.
The following small Python3 script creates a series of new network namespaces and enters each one immediately, leaving the previous one. As there is no other process and thread holding any references to the previously created network namespace, it becomes obsolete and eventually should go away. An indirect sign is that namespace inode numbers then get reused.
Now notice how this script creates "temporary" network namespaces in two sequences: once in a slow fashion with much idle time in between, and once in a rapid fashion...
import unshare
import os
import time
def trash(delay):
for i in range(4):
unshare.unshare(unshare.CLONE_NEWNET)
print('trash net:[%d]' % os.stat('/proc/self/ns/net').st_ino)
time.sleep(delay) # wait for penguins to collect garbage namespaces
# user namespaces can be created by unprivileged processes
# (unless on mispatched Debian kernels): this gives us all
# capabilities inside this new user namespace owned by our
# user, so we can create other namespaces.
unshare.unshare(unshare.CLONE_NEWUSER)
print('original net:[%d]' % os.stat('/proc/self/ns/net').st_ino)
print('slow trashing...')
trash(0.5)
time.sleep(0.5)
print('fast trashing...')
trash(0.01)
When run, your output should look similar to this one:
$ python3 nsgarbage.py
original net:[4026531905]
slow trashing...
trash net:[4026532268]
trash net:[4026532344]
trash net:[4026532268]
trash net:[4026532344]
fast trashing...
trash net:[4026532268]
trash net:[4026532419]
trash net:[4026532494]
trash net:[4026532569]
Notice how in the slow sequence with 0.5s delays, obsolete network namespaces get destroyed and their inode numbers reused: the inode number of freshly create network namespaces oscillate.
In contrast, for the fast sequence, obsolete namespaces do no seem to get destroyed (garbage-collected), as indicated by their inode numbers not getting reused, but instead "piling up".
Please note that I can only indirectly deduce when namespaces get destroyed, based on the inode number reuse. This might be the wrong assumption.
Can someone with Linux kernel knowledge shed more light on the behavior of Linux: when does the kernel really destroy namespaces? And if destruction is delayed, is there some intrinsic granularity for this "garbage collection"?