Ejemplo n.º 1
0
class NetNS(IPRouteMixin, RemoteSocket):
    '''
    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
        self.cmdch, cmdch = MpPipe()
        self.brdch, brdch = MpPipe()
        self.server = MpProcess(target=NetNServer,
                                args=(self.netns, cmdch, brdch, self.flags))
        self.server.start()
        super(NetNS, self).__init__()
        self.marshal = MarshalRtnl()

    def close(self):
        super(NetNS, self).close()
        self.server.join()

    def post_init(self):
        pass

    def remove(self):
        '''
        Try to remove this network namespace from the system.
        '''
        remove(self.netns)
Ejemplo n.º 2
0
class NetNS(IPRouteMixin, RemoteSocket):
    """
    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
        self.cmdch, cmdch = MpPipe()
        self.brdch, brdch = MpPipe()
        self.server = MpProcess(target=NetNServer, args=(self.netns, cmdch, brdch, self.flags))
        self.server.start()
        super(NetNS, self).__init__()
        self.marshal = MarshalRtnl()

    def close(self):
        super(NetNS, self).close()
        self.server.join()

    def post_init(self):
        pass

    def remove(self):
        """
        Try to remove this network namespace from the system.
        """
        remove(self.netns)
Ejemplo n.º 3
0
 def __init__(self, netns, flags=os.O_CREAT):
     self.netns = netns
     self.flags = flags
     self.cmdch, cmdch = MpPipe()
     self.brdch, brdch = MpPipe()
     self.server = MpProcess(target=NetNServer,
                             args=(self.netns, cmdch, brdch, self.flags))
     self.server.start()
     super(NetNS, self).__init__()
     self.marshal = MarshalRtnl()
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 def __init__(self, netns, flags=os.O_CREAT):
     self.netns = netns
     self.flags = flags
     self.cmdch, cmdch = MpPipe()
     self.brdch, brdch = MpPipe()
     self.server = MpProcess(target=NetNServer, args=(self.netns, cmdch, brdch, self.flags))
     self.server.start()
     super(NetNS, self).__init__()
     self.marshal = MarshalRtnl()
Ejemplo n.º 6
0
    def __init__(self, nsname, *argv, **kwarg):
        '''
        The only differences from the `subprocess.Popen` init are:
        * `nsname` -- network namespace name
        * `flags` keyword argument

        All other arguments are passed directly to `subprocess.Popen`.

        Flags usage samples. Create a network namespace, if it doesn't
        exist yet::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT)

        Create a network namespace only if it doesn't exist, otherwise
        fail and raise an exception::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT | os.O_EXCL)
        '''
        # create a child
        self.nsname = nsname
        if 'flags' in kwarg:
            self.flags = kwarg.pop('flags')
        else:
            self.flags = 0
        self.channel_out = MpQueue()
        self.channel_in = MpQueue()
        self.lock = threading.Lock()
        self.released = False
        self.server = MpProcess(target=NSPopenServer,
                                args=(self.nsname,
                                      self.flags,
                                      self.channel_out,
                                      self.channel_in,
                                      argv, kwarg))
        # start the child and check the status
        self.server.start()
        response = self.channel_in.get()
        if isinstance(response, Exception):
            self.server.join()
            raise response
        else:
            atexit.register(self.release)
Ejemplo n.º 7
0
 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)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
    def __init__(self, nsname, *argv, **kwarg):
        '''
        The only differences from the `subprocess.Popen` init are:
        * `nsname` -- network namespace name
        * `flags` keyword argument

        All other arguments are passed directly to `subprocess.Popen`.

        Flags usage samples. Create a network namespace, if it doesn't
        exist yet::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT)

        Create a network namespace only if it doesn't exist, otherwise
        fail and raise an exception::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT | os.O_EXCL)
        '''
        # create a child
        self.nsname = nsname
        if 'flags' in kwarg:
            self.flags = kwarg.pop('flags')
        else:
            self.flags = 0
        self.channel_out = MpQueue()
        self.channel_in = MpQueue()
        self.lock = threading.Lock()
        self.released = False
        self.server = MpProcess(target=NSPopenServer,
                                args=(self.nsname,
                                      self.flags,
                                      self.channel_out,
                                      self.channel_in,
                                      argv, kwarg))
        # start the child and check the status
        self.server.start()
        response = self.channel_in.get()
        if isinstance(response, Exception):
            self.server.join()
            raise response
        else:
            atexit.register(self.release)
Ejemplo n.º 11
0
class NSPopen(NSPopenBase, ObjNS):
    '''
    A proxy class to run `Popen()` object in some network namespace.

    Sample to run `ip ad` command in `nsname` network namespace::

        nsp = NSPopen('nsname', ['ip', 'ad'], stdout=subprocess.PIPE)
        print(nsp.communicate())
        nsp.wait()
        nsp.release()

    The `NSPopen` class was intended to be a drop-in replacement
    for the `Popen` class, but there are still some important
    differences.

    The `NSPopen` object implicitly spawns a child python process
    to be run in the background in a network namespace. The target
    process specified as the argument of the `NSPopen` will be
    started in its turn from this child. Thus all the fd numbers
    of the running `NSPopen` object are meaningless in the context
    of the main process. Trying to operate on them, one will get
    'Bad file descriptor' in the best case or a system call working
    on a wrong file descriptor in the worst case. A possible
    solution would be to transfer file descriptors between the
    `NSPopen` object and the main process, but it is not implemented
    yet.

    The process' diagram for `NSPopen('test', ['ip', 'ad'])`::

        +---------------------+     +--------------+     +------------+
        | main python process |<--->| child python |<--->| netns test |
        | NSPopen()           |     | Popen()      |     | $ ip ad    |
        +---------------------+     +--------------+     +------------+

    As a workaround for the issue with file descriptors, some
    additional methods are available on file objects `stdin`,
    `stdout` and `stderr`. E.g., one can run fcntl calls::

        from fcntl import F_GETFL
        from pyroute2 import NSPopen
        from subprocess import PIPE

        proc = NSPopen('test', ['my_program'], stdout=PIPE)
        flags = proc.stdout.fcntl(F_GETFL)

    In that way one can use `fcntl()`, `ioctl()`, `flock()` and
    `lockf()` calls.

    Another additional method is `release()`, which can be used to
    explicitly stop the proxy process and release all the resources.
    '''
    def __init__(self, nsname, *argv, **kwarg):
        '''
        The only differences from the `subprocess.Popen` init are:
        * `nsname` -- network namespace name
        * `flags` keyword argument

        All other arguments are passed directly to `subprocess.Popen`.

        Flags usage samples. Create a network namespace, if it doesn't
        exist yet::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT)

        Create a network namespace only if it doesn't exist, otherwise
        fail and raise an exception::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT | os.O_EXCL)
        '''
        # create a child
        self.nsname = nsname
        if 'flags' in kwarg:
            self.flags = kwarg.pop('flags')
        else:
            self.flags = 0
        self.channel_out = MpQueue()
        self.channel_in = MpQueue()
        self.lock = threading.Lock()
        self.released = False
        self.server = MpProcess(target=NSPopenServer,
                                args=(self.nsname, self.flags,
                                      self.channel_out, self.channel_in, argv,
                                      kwarg))
        # start the child and check the status
        self.server.start()
        response = self.channel_in.get()
        if isinstance(response, Exception):
            self.server.join()
            raise response
        else:
            atexit.register(self.release)

    def release(self):
        '''
        Explicitly stop the proxy process and release all the
        resources. The `NSPopen` object can not be used after
        the `release()` call.
        '''
        with self.lock:
            if self.released:
                return
            self.released = True
            self.channel_out.put({'name': 'release'})
            self.channel_out.close()
            self.channel_in.close()
            self.server.join()

    def __dir__(self):
        return list(self.api.keys()) + ['release']
Ejemplo n.º 12
0
class NSPopen(NSPopenBase, ObjNS):
    '''
    A proxy class to run `Popen()` object in some network namespace.

    Sample to run `ip ad` command in `nsname` network namespace::

        nsp = NSPopen('nsname', ['ip', 'ad'], stdout=subprocess.PIPE)
        print(nsp.communicate())
        nsp.wait()
        nsp.release()

    The only difference in the `release()` call. It explicitly ends
    the proxy process and releases all the resources.
    '''

    def __init__(self, nsname, *argv, **kwarg):
        '''
        The only differences from the `subprocess.Popen` init are:
        * `nsname` -- network namespace name
        * `flags` keyword argument

        All other arguments are passed directly to `subprocess.Popen`.

        Flags usage samples. Create a network namespace, if it doesn't
        exist yet::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT)

        Create a network namespace only if it doesn't exist, otherwise
        fail and raise an exception::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT | os.O_EXCL)
        '''
        # create a child
        self.nsname = nsname
        if 'flags' in kwarg:
            self.flags = kwarg.pop('flags')
        else:
            self.flags = 0
        self.channel_out = MpQueue()
        self.channel_in = MpQueue()
        self.lock = threading.Lock()
        self.released = False
        self.server = MpProcess(target=NSPopenServer,
                                args=(self.nsname,
                                      self.flags,
                                      self.channel_out,
                                      self.channel_in,
                                      argv, kwarg))
        # start the child and check the status
        self.server.start()
        response = self.channel_in.get()
        if isinstance(response, Exception):
            self.server.join()
            raise response
        else:
            atexit.register(self.release)

    def release(self):
        '''
        Explicitly stop the proxy process and release all the
        resources. The `NSPopen` object can not be used after
        the `release()` call.
        '''
        with self.lock:
            if self.released:
                return
            self.released = True
            self.channel_out.put({'name': 'release'})
            self.channel_out.close()
            self.channel_in.close()
            self.server.join()

    def __dir__(self):
        return list(self.api.keys()) + ['release']
Ejemplo n.º 13
0
class NetNS(IPRouteMixin, RemoteSocket):
    '''
    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
        self.cmdch, self._cmdch = MpPipe()
        self.brdch, self._brdch = MpPipe()
        atexit.register(self.close)
        self.server = MpProcess(target=NetNServer,
                                args=(self.netns,
                                      self._cmdch,
                                      self._brdch,
                                      self.flags))
        self.server.start()
        super(NetNS, self).__init__()
        self.marshal = MarshalRtnl()

    def clone(self):
        return type(self)(self.netns, self.flags)

    def close(self):
        try:
            super(NetNS, self).close()
        except:
            # something went wrong, force server shutdown
            self.cmdch.send({'stage': 'shutdown'})
            log.error('forced shutdown procedure, clean up netns manually')
        # force cleanup command channels
        self.cmdch.close()
        self.brdch.close()
        self._cmdch.close()
        self._brdch.close()
        # join the server
        self.server.join()
        # Workaround for http://bugs.python.org/issue27151
        if sys.version_info > (3, 2) and sys.version_info < (3, 6):
            try:
                fcntl.fcntl(self.server.sentinel, fcntl.F_GETFD)
            except:
                pass
            else:
                os.close(self.server.sentinel)

    def post_init(self):
        pass

    def remove(self):
        '''
        Try to remove this network namespace from the system.
        '''
        remove(self.netns)
Ejemplo n.º 14
0
class NSPopen(NSPopenBase, ObjNS):
    '''
    A proxy class to run `Popen()` object in some network namespace.

    Sample to run `ip ad` command in `nsname` network namespace::

        nsp = NSPopen('nsname', ['ip', 'ad'], stdout=subprocess.PIPE)
        print(nsp.communicate())
        nsp.wait()
        nsp.release()

    The `NSPopen` class was intended to be a drop-in replacement
    for the `Popen` class, but there are still some important
    differences.

    The `NSPopen` object implicitly spawns a child python process
    to be run in the background in a network namespace. The target
    process specified as the argument of the `NSPopen` will be
    started in its turn from this child. Thus all the fd numbers
    of the running `NSPopen` object are meaningless in the context
    of the main process. Trying to operate on them, one will get
    'Bad file descriptor' in the best case or a system call working
    on a wrong file descriptor in the worst case. A possible
    solution would be to transfer file descriptors between the
    `NSPopen` object and the main process, but it is not implemented
    yet.

    The process' diagram for `NSPopen('test', ['ip', 'ad'])`::

        +---------------------+     +--------------+     +------------+
        | main python process |<--->| child python |<--->| netns test |
        | NSPopen()           |     | Popen()      |     | $ ip ad    |
        +---------------------+     +--------------+     +------------+

    As a workaround for the issue with file descriptors, some
    additional methods are available on file objects `stdin`,
    `stdout` and `stderr`. E.g., one can run fcntl calls::

        from fcntl import F_GETFL
        from pyroute2 import NSPopen
        from subprocess import PIPE

        proc = NSPopen('test', ['my_program'], stdout=PIPE)
        flags = proc.stdout.fcntl(F_GETFL)

    In that way one can use `fcntl()`, `ioctl()`, `flock()` and
    `lockf()` calls.

    Another additional method is `release()`, which can be used to
    explicitly stop the proxy process and release all the resources.
    '''

    def __init__(self, nsname, *argv, **kwarg):
        '''
        The only differences from the `subprocess.Popen` init are:
        * `nsname` -- network namespace name
        * `flags` keyword argument

        All other arguments are passed directly to `subprocess.Popen`.

        Flags usage samples. Create a network namespace, if it doesn't
        exist yet::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT)

        Create a network namespace only if it doesn't exist, otherwise
        fail and raise an exception::

            import os
            nsp = NSPopen('nsname', ['command'], flags=os.O_CREAT | os.O_EXCL)
        '''
        # create a child
        self.nsname = nsname
        if 'flags' in kwarg:
            self.flags = kwarg.pop('flags')
        else:
            self.flags = 0
        self.channel_out = MpQueue()
        self.channel_in = MpQueue()
        self.lock = threading.Lock()
        self.released = False
        self.server = MpProcess(target=NSPopenServer,
                                args=(self.nsname,
                                      self.flags,
                                      self.channel_out,
                                      self.channel_in,
                                      argv, kwarg))
        # start the child and check the status
        self.server.start()
        response = self.channel_in.get()
        if isinstance(response, Exception):
            self.server.join()
            raise response
        else:
            atexit.register(self.release)

    def release(self):
        '''
        Explicitly stop the proxy process and release all the
        resources. The `NSPopen` object can not be used after
        the `release()` call.
        '''
        with self.lock:
            if self.released:
                return
            self.released = True
            self.channel_out.put({'name': 'release'})
            self.channel_out.close()
            self.channel_in.close()
            self.server.join()

    def __dir__(self):
        return list(self.api.keys()) + ['release']
Ejemplo n.º 15
0
class NetNS(IPRouteMixin, RemoteSocket):
    '''
    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
        self.cmdch, self._cmdch = MpPipe()
        self.brdch, self._brdch = MpPipe()
        atexit.register(self.close)
        self.server = MpProcess(target=NetNServer,
                                args=(self.netns, self._cmdch, self._brdch,
                                      self.flags))
        self.server.start()
        super(NetNS, self).__init__()
        self.marshal = MarshalRtnl()

    def clone(self):
        return type(self)(self.netns, self.flags)

    def close(self):
        try:
            super(NetNS, self).close()
        except:
            # something went wrong, force server shutdown
            self.cmdch.send({'stage': 'shutdown'})
            log.error('forced shutdown procedure, clean up netns manually')
        # force cleanup command channels
        self.cmdch.close()
        self.brdch.close()
        self._cmdch.close()
        self._brdch.close()
        # join the server
        self.server.join()
        # Workaround for http://bugs.python.org/issue27151
        if sys.version_info > (3, 2) and sys.version_info < (3, 6):
            try:
                fcntl.fcntl(self.server.sentinel, fcntl.F_GETFD)
            except:
                pass
            else:
                os.close(self.server.sentinel)

    def post_init(self):
        pass

    def remove(self):
        '''
        Try to remove this network namespace from the system.
        '''
        remove(self.netns)