aboutsummaryrefslogtreecommitdiffstats
path: root/node-admin/scripts/pyroute2/netns/nslink.py
diff options
context:
space:
mode:
Diffstat (limited to 'node-admin/scripts/pyroute2/netns/nslink.py')
-rw-r--r--node-admin/scripts/pyroute2/netns/nslink.py310
1 files changed, 0 insertions, 310 deletions
diff --git a/node-admin/scripts/pyroute2/netns/nslink.py b/node-admin/scripts/pyroute2/netns/nslink.py
deleted file mode 100644
index 67d5fff0921..00000000000
--- a/node-admin/scripts/pyroute2/netns/nslink.py
+++ /dev/null
@@ -1,310 +0,0 @@
-# By Peter V. Saveliev https://pypi.python.org/pypi/pyroute2. Dual licensed under the Apache 2 and GPLv2+ see https://github.com/svinota/pyroute2 for License details.
-'''
-NetNS
-=====
-
-A NetNS object is IPRoute-like. It runs in the main network
-namespace, but also creates a proxy process running in
-the required netns. All the netlink requests are done via
-that proxy process.
-
-NetNS supports standard IPRoute API, so can be used instead
-of IPRoute, e.g., in IPDB::
-
- # start the main network settings database:
- ipdb_main = IPDB()
- # start the same for a netns:
- ipdb_test = IPDB(nl=NetNS('test'))
-
- # create VETH
- ipdb_main.create(ifname='v0p0', kind='veth', peer='v0p1').commit()
-
- # move peer VETH into the netns
- with ipdb_main.interfaces.v0p1 as veth:
- veth.net_ns_fd = 'test'
-
- # please keep in mind, that netns move clears all the settings
- # on a VETH interface pair, so one should run netns assignment
- # as a separate operation only
-
- # assign addresses
- # please notice, that `v0p1` is already in the `test` netns,
- # so should be accessed via `ipdb_test`
- with ipdb_main.interfaces.v0p0 as veth:
- veth.add_ip('172.16.200.1/24')
- veth.up()
- with ipdb_test.interfaces.v0p1 as veth:
- veth.add_ip('172.16.200.2/24')
- veth.up()
-
-Please review also the test code, under `tests/test_netns.py` for
-more examples.
-
-By default, NetNS creates requested netns, if it doesn't exist,
-or uses existing one. To control this behaviour, one can use flags
-as for `open(2)` system call::
-
- # create a new netns or fail, if it already exists
- netns = NetNS('test', flags=os.O_CREAT | os.O_EXIST)
-
- # create a new netns or use existing one
- netns = NetNS('test', flags=os.O_CREAT)
-
- # the same as above, the default behaviour
- netns = NetNS('test')
-
-To remove a network namespace::
-
- from pyroute2 import NetNS
- netns = NetNS('test')
- netns.close()
- netns.remove()
-
-One should stop it first with `close()`, and only after that
-run `remove()`.
-
-'''
-
-import os
-import errno
-import atexit
-import select
-import struct
-import threading
-import traceback
-from socket import SOL_SOCKET
-from socket import SO_RCVBUF
-from pyroute2.config import MpPipe
-from pyroute2.config import MpProcess
-from pyroute2.iproute import IPRoute
-from pyroute2.netlink.nlsocket import NetlinkMixin
-from pyroute2.netlink.rtnl.iprsocket import MarshalRtnl
-from pyroute2.iproute import IPRouteMixin
-from pyroute2.netns import setns
-from pyroute2.netns import remove
-
-
-def NetNServer(netns, rcvch, cmdch, flags=os.O_CREAT):
- '''
- The netns server supposed to be started automatically by NetNS.
- It has two communication channels: one simplex to forward incoming
- netlink packets, `rcvch`, and other synchronous duplex to get
- commands and send back responses, `cmdch`.
-
- Channels should support standard socket API, should be compatible
- with poll/select and should be able to transparently pickle objects.
- NetNS uses `multiprocessing.Pipe` for this purpose, but it can be
- any other implementation with compatible API.
-
- The first parameter, `netns`, is a netns name. Depending on the
- `flags`, the netns can be created automatically. The `flags` semantics
- is exactly the same as for `open(2)` system call.
-
- ...
-
- The server workflow is simple. The startup sequence::
-
- 1. Create or open a netns.
-
- 2. Start `IPRoute` instance. It will be used only on the low level,
- the `IPRoute` will not parse any packet.
-
- 3. Start poll/select loop on `cmdch` and `IPRoute`.
-
- On the startup, the server sends via `cmdch` the status packet. It can be
- `None` if all is OK, or some exception.
-
- Further data handling, depending on the channel, server side::
-
- 1. `IPRoute`: read an incoming netlink packet and send it unmodified
- to the peer via `rcvch`. The peer, polling `rcvch`, can handle
- the packet on its side.
-
- 2. `cmdch`: read tuple (cmd, argv, kwarg). If the `cmd` starts with
- "send", then take `argv[0]` as a packet buffer, treat it as one
- netlink packet and substitute PID field (offset 12, uint32) with
- its own. Strictly speaking, it is not mandatory for modern netlink
- implementations, but it is required by the protocol standard.
-
- '''
- try:
- nsfd = setns(netns, flags)
- except OSError as e:
- cmdch.send(e)
- return e.errno
- except Exception as e:
- cmdch.send(OSError(errno.ECOMM, str(e), netns))
- return 255
-
- #
- try:
- ipr = IPRoute()
- rcvch_lock = ipr._sproxy.lock
- ipr._s_channel = rcvch
- poll = select.poll()
- poll.register(ipr, select.POLLIN | select.POLLPRI)
- poll.register(cmdch, select.POLLIN | select.POLLPRI)
- except Exception as e:
- cmdch.send(e)
- return 255
-
- # all is OK so far
- cmdch.send(None)
- # 8<-------------------------------------------------------------
- while True:
- events = poll.poll()
- for (fd, event) in events:
- if fd == ipr.fileno():
- bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2
- with rcvch_lock:
- rcvch.send(ipr.recv(bufsize))
- elif fd == cmdch.fileno():
- try:
- cmdline = cmdch.recv()
- if cmdline is None:
- poll.unregister(ipr)
- poll.unregister(cmdch)
- ipr.close()
- os.close(nsfd)
- return
- (cmd, argv, kwarg) = cmdline
- if cmd[:4] == 'send':
- # Achtung
- #
- # It's a hack, but we just have to do it: one
- # must use actual pid in netlink messages
- #
- # FIXME: there can be several messages in one
- # call buffer; but right now we can ignore it
- msg = argv[0][:12]
- msg += struct.pack("I", os.getpid())
- msg += argv[0][16:]
- argv = list(argv)
- argv[0] = msg
- cmdch.send(getattr(ipr, cmd)(*argv, **kwarg))
- except Exception as e:
- e.tb = traceback.format_exc()
- cmdch.send(e)
-
-
-class NetNSProxy(object):
-
- netns = 'default'
- flags = os.O_CREAT
-
- def __init__(self, *argv, **kwarg):
- self.cmdlock = threading.Lock()
- self.rcvch, rcvch = MpPipe()
- self.cmdch, cmdch = MpPipe()
- self.server = MpProcess(target=NetNServer,
- args=(self.netns, rcvch, cmdch, self.flags))
- self.server.start()
- error = self.cmdch.recv()
- if error is not None:
- self.server.join()
- raise error
- else:
- atexit.register(self.close)
-
- def recv(self, bufsize, flags=0):
- return self.rcvch.recv()
-
- def close(self):
- self.cmdch.send(None)
- self.server.join()
-
- def proxy(self, cmd, *argv, **kwarg):
- with self.cmdlock:
- self.cmdch.send((cmd, argv, kwarg))
- response = self.cmdch.recv()
- if isinstance(response, Exception):
- raise response
- return response
-
- def fileno(self):
- return self.rcvch.fileno()
-
- def bind(self, *argv, **kwarg):
- if 'async' in kwarg:
- kwarg['async'] = False
- return self.proxy('bind', *argv, **kwarg)
-
- def send(self, *argv, **kwarg):
- return self.proxy('send', *argv, **kwarg)
-
- def sendto(self, *argv, **kwarg):
- return self.proxy('sendto', *argv, **kwarg)
-
- def getsockopt(self, *argv, **kwarg):
- return self.proxy('getsockopt', *argv, **kwarg)
-
- def setsockopt(self, *argv, **kwarg):
- return self.proxy('setsockopt', *argv, **kwarg)
-
-
-class NetNSocket(NetlinkMixin, NetNSProxy):
-
- def bind(self, *argv, **kwarg):
- return NetNSProxy.bind(self, *argv, **kwarg)
-
- def close(self):
- NetNSProxy.close(self)
-
- def _sendto(self, *argv, **kwarg):
- return NetNSProxy.sendto(self, *argv, **kwarg)
-
- def _recv(self, *argv, **kwarg):
- return NetNSProxy.recv(self, *argv, **kwarg)
-
-
-class NetNS(IPRouteMixin, NetNSocket):
- '''
- NetNS is the IPRoute API with network namespace support.
-
- **Why not IPRoute?**
-
- The task to run netlink commands in some network namespace, being in
- another network namespace, requires the architecture, that differs
- too much from a simple Netlink socket.
-
- NetNS starts a proxy process in a network namespace and uses
- `multiprocessing` communication channels between the main and the proxy
- processes to route all `recv()` and `sendto()` requests/responses.
-
- **Any specific API calls?**
-
- Nope. `NetNS` supports all the same, that `IPRoute` does, in the same
- way. It provides full `socket`-compatible API and can be used in
- poll/select as well.
-
- The only difference is the `close()` call. In the case of `NetNS` it
- is **mandatory** to close the socket before exit.
-
- **NetNS and IPDB**
-
- It is possible to run IPDB with NetNS::
-
- from pyroute2 import NetNS
- from pyroute2 import IPDB
-
- ip = IPDB(nl=NetNS('somenetns'))
- ...
- ip.release()
-
- Do not forget to call `release()` when the work is done. It will shut
- down `NetNS` instance as well.
- '''
- def __init__(self, netns, flags=os.O_CREAT):
- self.netns = netns
- self.flags = flags
- super(NetNS, self).__init__()
- self.marshal = MarshalRtnl()
-
- def post_init(self):
- pass
-
- def remove(self):
- '''
- Try to remove this network namespace from the system.
- '''
- remove(self.netns)