{"id":251,"date":"2013-12-15T19:45:26","date_gmt":"2013-12-15T18:45:26","guid":{"rendered":"http:\/\/www.opencloudblog.com\/?p=251"},"modified":"2021-01-17T13:18:19","modified_gmt":"2021-01-17T12:18:19","slug":"how-to-find-namespaces-in-a-linux-system","status":"publish","type":"post","link":"https:\/\/www.opencloudblog.com\/?p=251","title":{"rendered":"How to find namespaces in a Linux system"},"content":{"rendered":"<p>Namespaces in Linux are heavily used by many applications, e.g. LXC, Docker and Openstack.<br \/>\n<em>Question: How to find all existing namespaces in a Linux system?<\/em><\/p>\n<p>The answer is quite difficult, because it&#8217;s easy to hide a namespace or more exactly make it difficult to find them.<\/p>\n<h1>Exploring the system<\/h1>\n<p>In the basic\/default setup Ubuntu 12.04 and higher provide namespaces for<\/p>\n<ul>\n<li>ipc for IPC objects and POSIX message queues<\/li>\n<li>mnt for filesystem mountpoints<\/li>\n<li>net for network abstraction (VRF)<\/li>\n<li>pid to provide\u00a0a separated, isolated\u00a0process ID number space<\/li>\n<li>uts to isolate two system identifiers \u2014 nodename and domainname &#8211; to be used by uname<\/li>\n<\/ul>\n<p>These namespaces are shown for every process in the system. if you execute as root<\/p>\n<pre class=\"lang:sh decode:true\" title=\"ls -lai \/proc\/1\/ns\">ls -lai \/proc\/1\/ns\r\n\r\n60073292 dr-x--x--x 2 root root 0 Dec 15 18:23 .\r\n   10395 dr-xr-xr-x 9 root root 0 Dec  4 11:07 ..\r\n60073293 lrwxrwxrwx 1 root root 0 Dec 15 18:23 ipc -&gt; ipc:[4026531839]\r\n60073294 lrwxrwxrwx 1 root root 0 Dec 15 18:23 mnt -&gt; mnt:[4026531840]\r\n60073295 lrwxrwxrwx 1 root root 0 Dec 15 18:23 net -&gt; net:[4026531968]\r\n60073296 lrwxrwxrwx 1 root root 0 Dec 15 18:23 pid -&gt; pid:[4026531836]\r\n60073297 lrwxrwxrwx 1 root root 0 Dec 15 18:23 uts -&gt; uts:[4026531838]<\/pre>\n<p>you get the list of attached namespaces of the init process using <strong>PID=1<\/strong>. Even this process has attached namespaces. These are the default namespaces for ipc, mnt, net, pid and uts. For example, the default net namespace is using the ID net:[4026531968]. The number in the brackets is a inode number.<\/p>\n<p>In order to find other namespaces <strong>with attached processes<\/strong> in the system, we use these entries of the PID=1 as a reference. Any process or thread in the system, which has not the same namespace ID as PID=1 is not belonging to the DEFAULT namespace.<\/p>\n<p>Additionally, you find the namespaces created by &#8222;ip netns add &lt;NAME&gt;&#8220; by default in <strong>\/var\/run\/netns\/<\/strong> .<\/p>\n<h1>The python code<\/h1>\n<p>The python code below is listing all non default namespaces in a system. The program flow is<\/p>\n<ul>\n<li>Get the reference namespaces from the init process (PID=1). Assumption: PID=1 is assigned to the default namespaces supported by the system<\/li>\n<li>Loop through \/var\/run\/netns\/ and add the entries to the list<\/li>\n<li>Loop through \/proc\/ over all PIDs and look for entries in \/proc\/&lt;PID&gt;\/ns\/ which are not the same as for PID=1 and add then to the list<\/li>\n<li>Print the result<\/li>\n<\/ul>\n<pre class=\"lang:python decode:true \" title=\"List all non default namespaces in a system\">#!\/usr\/bin\/python\r\n#\r\n# List all Namespaces (works for Ubuntu 12.04 and higher)\r\n#\r\n# (C) Ralf Trezeciak    2013-2014\r\n#\r\n#\r\n#    This program is free software: you can redistribute it and\/or modify\r\n#    it under the terms of the GNU General Public License as published by\r\n#    the Free Software Foundation, either version 3 of the License, or\r\n#    (at your option) any later version.\r\n#\r\n#    This program is distributed in the hope that it will be useful,\r\n#    but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n#    GNU General Public License for more details.\r\n#\r\n#    You should have received a copy of the GNU General Public License\r\n#    along with this program.  If not, see &lt;http:\/\/www.gnu.org\/licenses\/&gt;.\r\n#\r\nimport os\r\nimport fnmatch\r\n\r\nif os.geteuid() != 0:\r\n    print \"This script must be run as root\\nBye\"\r\n    exit(1)\r\n\r\ndef getinode( pid , type):\r\n    link = '\/proc\/' + pid + '\/ns\/' + type\r\n    ret = ''\r\n    try:\r\n        ret = os.readlink( link )\r\n    except OSError as e:\r\n        ret = ''\r\n        pass\r\n    return ret\r\n\r\n#\r\n# get the running command\r\ndef getcmd( p ):\r\n    try:\r\n        cmd = open(os.path.join('\/proc', p, 'cmdline'), 'rb').read()\r\n        if cmd == '':\r\n            cmd = open(os.path.join('\/proc', p, 'comm'), 'rb').read()\r\n        cmd = cmd.replace('\\x00' , ' ')\r\n        cmd = cmd.replace('\\n' , ' ')\r\n        return cmd\r\n    except:\r\n        return ''\r\n#\r\n# look for docker parents\r\ndef getpcmd( p ):\r\n    try:\r\n        f = '\/proc\/' + p + '\/stat'\r\n        arr = open( f, 'rb').read().split()\r\n        cmd = getcmd( arr[3] )\r\n        if cmd.startswith( '\/usr\/bin\/docker' ):\r\n            return 'docker'\r\n    except:\r\n        pass\r\n    return ''\r\n#\r\n# get the namespaces of PID=1\r\n# assumption: these are the namespaces supported by the system\r\n#\r\nnslist = os.listdir('\/proc\/1\/ns\/')\r\nif len(nslist) == 0:\r\n    print 'No Namespaces found for PID=1'\r\n    exit(1)\r\n#print nslist\r\n#\r\n# get the inodes used for PID=1\r\n#\r\nbaseinode = []\r\nfor x in nslist:\r\n    baseinode.append( getinode( '1' , x ) )\r\n#print \"Default namespaces: \" , baseinode\r\nerr = 0\r\nns = []\r\nipnlist = []\r\n#\r\n# loop over the network namespaces created using \"ip\"\r\n#\r\ntry:\r\n    netns = os.listdir('\/var\/run\/netns\/')\r\n    for p in netns:\r\n        fd = os.open( '\/var\/run\/netns\/' + p, os.O_RDONLY )\r\n        info = os.fstat(fd)\r\n        os.close( fd)\r\n        ns.append( '-- net:[' + str(info.st_ino) + '] created by ip netns add ' + p )\r\n        ipnlist.append( 'net:[' + str(info.st_ino) + ']' )\r\nexcept:\r\n    # might fail if no network namespaces are existing\r\n    pass\r\n#\r\n# walk through all pids and list diffs\r\n#\r\npidlist = fnmatch.filter(os.listdir('\/proc\/'), '[0123456789]*')\r\n#print pidlist\r\nfor p in pidlist:\r\n    try:\r\n        pnslist = os.listdir('\/proc\/' + p + '\/ns\/')\r\n        for x in pnslist:\r\n            i = getinode ( p , x )\r\n            if i != '' and i not in baseinode:\r\n                cmd = getcmd( p )\r\n                pcmd = getpcmd( p )\r\n                if pcmd != '':\r\n                    cmd = '[' + pcmd + '] ' + cmd\r\n                tag = ''\r\n                if i in ipnlist:\r\n                    tag='**' \r\n                ns.append( p + ' ' + i + tag + ' ' + cmd)\r\n    except:\r\n        # might happen if a pid is destroyed during list processing\r\n        pass\r\n#\r\n# print the stuff\r\n#\r\nprint '{0:&gt;10}  {1:20}  {2}'.format('PID','Namespace','Thread\/Command')\r\nfor e in ns:\r\n    x = e.split( ' ' , 2 )\r\n    print '{0:&gt;10}  {1:20}  {2}'.format(x[0],x[1],x[2][:60])\r\n#<\/pre>\n<p>Copy the script to your system as <strong>listns.py<\/strong> , and run it as root using python <strong>listns.py<\/strong><\/p>\n<pre class=\"lang:sh decode:true\">       PID  Namespace             Thread\/Command\r\n        --  net:[4026533172]      created by ip netns add qrouter-c33ffc14-dbc2-4730-b787-4747\r\n        --  net:[4026533112]      created by ip netns add qrouter-5a691ed3-f6d3-4346-891a-3b59\r\n        --  net:[4026533050]      created by ip netns add qdhcp-02e848cb-72d0-49df-8592-2f7a03\r\n        --  net:[4026532992]      created by ip netns add qdhcp-47cfcdef-2b34-43b8-a504-6720e5\r\n       297  mnt:[4026531856]      kdevtmpfs \r\n      3429  net:[4026533050]**    dnsmasq --no-hosts --no-resolv --strict-order --bind-interfa\r\n      3429  mnt:[4026533108]      dnsmasq --no-hosts --no-resolv --strict-order --bind-interfa\r\n      3446  net:[4026532992]**    dnsmasq --no-hosts --no-resolv --strict-order --bind-interfa\r\n      3446  mnt:[4026533109]      dnsmasq --no-hosts --no-resolv --strict-order --bind-interfa\r\n      3486  net:[4026533050]**    \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n      3486  mnt:[4026533107]      \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n      3499  net:[4026532992]**    \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n      3499  mnt:[4026533110]      \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n      4117  net:[4026533112]**    \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n      4117  mnt:[4026533169]      \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n     41998  net:[4026533172]**    \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil\r\n     41998  mnt:[4026533229]      \/usr\/bin\/python \/usr\/bin\/neutron-ns-metadata-proxy --pid_fil<\/pre>\n<p>The example above is from an Openstack network node. The first four entries are entries created using the command ip.\u00a0The entry PID=297 is a kernel thread and no user process. All other processes listed, are started by Openstack agents. These process are using network and mount namespaces. PID entries marked with &#8218;**&#8216; have a corresponding entry created with the ip command.<\/p>\n<p>When a docker command is started, the output is:<\/p>\n<pre class=\"lang:sh decode:true \" title=\" \">       PID  Namespace             Thread\/Command\r\n        --  net:[4026532676]      created by ip netns add test\r\n        35  mnt:[4026531856]      kdevtmpfs \r\n      6189  net:[4026532585]      [docker] \/bin\/bash \r\n      6189  uts:[4026532581]      [docker] \/bin\/bash \r\n      6189  ipc:[4026532582]      [docker] \/bin\/bash \r\n      6189  pid:[4026532583]      [docker] \/bin\/bash \r\n      6189  mnt:[4026532580]      [docker] \/bin\/bash \r\n<\/pre>\n<p>The docker child running in the namespaces is marked using [docker].<\/p>\n<p>On a node running mininet and a simple network setup the output looks like:<\/p>\n<pre class=\"lang:sh decode:true\" title=\"mininet example\">       PID  Namespace             Thread\/Command\r\n        14  mnt:[4026531856]      kdevtmpfs \r\n      1198  net:[4026532150]      bash -ms mininet:h1 \r\n      1199  net:[4026532201]      bash -ms mininet:h2 \r\n      1202  net:[4026532252]      bash -ms mininet:h3 \r\n      1203  net:[4026532303]      bash -ms mininet:h4<\/pre>\n<h1>Googles Chrome Browser<\/h1>\n<p>Googles Chrome Browser makes extensive use of the linux namespaces. Start Chrome and run the python script. The output looks like:<\/p>\n<pre class=\"lang:sh decode:true\" title=\"Chrome's namespaces\">       PID  Namespace             Thread\/Command\r\n        63  mnt:[4026531856]      kdevtmpfs \r\n     30747  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=zygote \r\n     30747  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=zygote \r\n     30753  net:[4026532344]      \/opt\/google\/chrome\/nacl_helper \r\n     30753  pid:[4026532337]      \/opt\/google\/chrome\/nacl_helper \r\n     30754  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=zygote \r\n     30754  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=zygote \r\n     30801  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30801  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30807  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30807  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30813  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30813  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30820  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30820  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30829  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30829  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30835  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30835  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30841  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30841  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30887  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30887  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30893  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30893  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30901  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30901  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30910  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30910  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30915  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30915  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30923  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30923  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30933  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30933  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30938  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30938  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30944  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     30944  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     31271  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     31271  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     31538  net:[4026532344]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for\r\n     31538  pid:[4026532337]      \/opt\/google\/chrome\/chrome --type=renderer --lang=en-US --for<\/pre>\n<p>Chrome makes use of pid and network namespaces to restrict the access of subcomponents. The network namespace does not have a link in \/var\/run\/netns\/.<\/p>\n<h1>Conclusion<\/h1>\n<p>It&#8217;s quite hard to explore the Linux namespace. There is a lot of documentation flowing around. I did not find any simple program to look for namespaces in the system. So I wrote one.<\/p>\n<p>The script cannot find a network namespace, which do not have any process attached to AND which has no reference in \/var\/run\/netns\/. If root creates the reference inode somewhere else in the filesystem, you may only detect network ports (ovs port, veth port on one side), which are not attached to a known network namespace &#8211;&gt; an unknown guest might be on your system using a &#8222;hidden&#8220; (not so easy to find) network namespace.<\/p>\n<p>And &#8212; Linux namespaces can be stacked.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Namespaces in Linux are heavily used by many applications, e.g. LXC, Docker and Openstack. Question: How to find all existing namespaces in a Linux system? The answer is quite difficult, because it&#8217;s easy to hide a namespace or more exactly make it difficult to find them. Exploring the system In the basic\/default setup Ubuntu 12.04 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=\/wp\/v2\/posts\/251"}],"collection":[{"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=251"}],"version-history":[{"count":19,"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=\/wp\/v2\/posts\/251\/revisions"}],"predecessor-version":[{"id":436,"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=\/wp\/v2\/posts\/251\/revisions\/436"}],"wp:attachment":[{"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.opencloudblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}