There's no actual name existing in the low-level handling of namespaces. It's all handled by common actions or expectations done with every command in the iproute2 suite.
Assigning a name to an existing anonymous network namespace really means: make the iproute2 tools believe they did their usual settings when creating this network namespace.
So what is
ip netns add foo really doing? It unshares to a new network namespace, and to keep this namespace existing even without process using it, mounts it. In the usual *nix philosophy, a namespace has an inode number representing a pseudo-file in the pseudo-filesystem nsfs. Almost no operation can be done on the file (not even read it), but it can be opened to use it as a token for namespace operations (eg
setns(2)) and can also be mounted as a bind mount.
Alas, the link nsid is not directly usable: that's not a global value representing an other namespace, but a local (locally unique but recyclable and not globally unique) ID representing a link to an other namespace. Multiple values means: links to multiple other namespaces, twice the same value means: two links to the same other namespace.
If you have to find the other namespaces starting only from this, I invite you to check my answer in this other Q/A where I made an answer about it. There's also a handy mapping tool available:
plotnetcfg which can map all the network namespaces. While it does know about iproute2 methods, it doesn't appear to give a process id separately, instead it names a namespace with a PID from it when it's not "named" by iproute2. Redacted example (requiring
jq), run as root:
# unshare -n -- sleep 999 &
# plotnetcfg -f json | jq '.namespaces.name'
"PID 268150 (systemd)"
"PID 345878 (systemd)"
"PID 677451 (sleep)"
"" represents the initial namespace, the two
systemd are from two LXC instances, and the
sleep command running is also found.
To help for two common cases:
Once you have found by whatever method available a process in the intended network namespace, you can mimic what would do the iproute2 tools. What they exactly do might depend on their exact version. From
strace mine appear to do:
mkdir -p /run/netns
and then mount it over itself so it can be set as shared propagation:
mount --bind --make-shared /run/netns /run/netns
Above should only be done if not already done and only once. To have the tools do it for you (and only when needed), simply create and delete a dummy namespace:
ip netns add dummy && ip netns delete dummy
Now pick a name, for example
foo, create an empty file and change its mode to 000 (which is not needed, but mimics iproute2):
chmod 0 /run/netns/foo
And finally mount the process' namespace given its PID (eg
sleep from before: 677451):
mount --bind /proc/677451/ns/net /run/netns/foo
That's it. Even if the
sleep command ends, the namespace will now survive. All iproute2 tools will now name it foo. For example if there was a veth interface connected to it,
ip link would replace the link nsid's number with
If you want to remove this network namespace,
ip netns del foo will now do it (caveat: as usual the actual network namespace really disappears once there's no resource using it anymore, like this sleep command).
Further documentation on iproute2's specific additional features along network namespaces in an other answer of mine.