Esempio n. 1
0
    def test_imports(self):
        from pyroute2 import IPRSocket
        from pyroute2.netlink import NLM_F_REQUEST
        from pyroute2.netlink import NLM_F_DUMP
        from pyroute2.netlink import NLM_F_ROOT
        from pyroute2.netlink import NLM_F_MATCH
        from pyroute2.netlink import NLMSG_DONE
        from pyroute2.netlink import NLMSG_ERROR
        from pyroute2.netlink import nlmsg
        from pyroute2.iproute import RTM_GETLINK
        from pyroute2.iproute import RTM_NEWLINK
        from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg

        ip = IPRSocket()
        ip.bind()
        ip.close()

        assert issubclass(IPRSocket, socket.socket)
        assert issubclass(ifinfmsg, nlmsg)
        assert NLM_F_REQUEST == 1
        assert NLM_F_ROOT == 0x100
        assert NLM_F_MATCH == 0x200
        assert NLM_F_DUMP == (NLM_F_ROOT | NLM_F_MATCH)
        assert NLMSG_DONE == 0x3
        assert NLMSG_ERROR == 0x2
        assert RTM_GETLINK == 0x12
        assert RTM_NEWLINK == 0x10
Esempio n. 2
0
    def test_basic(self):
        from pyroute2 import IPRSocket
        from pyroute2.netlink import NLM_F_REQUEST
        from pyroute2.netlink import NLM_F_DUMP
        from pyroute2.netlink import NLM_F_ROOT
        from pyroute2.netlink import NLM_F_MATCH
        from pyroute2.netlink import NLMSG_DONE
        from pyroute2.netlink import NLMSG_ERROR
        from pyroute2.netlink import nlmsg
        from pyroute2.iproute import RTM_GETLINK
        from pyroute2.iproute import RTM_NEWLINK
        from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg

        ip = IPRSocket()
        ip.bind()

        # check the `socket` interface compliance
        poll = select.poll()
        poll.register(ip, select.POLLIN | select.POLLPRI)
        poll.unregister(ip)
        ip.close()

        assert issubclass(ifinfmsg, nlmsg)
        assert NLM_F_REQUEST == 1
        assert NLM_F_ROOT == 0x100
        assert NLM_F_MATCH == 0x200
        assert NLM_F_DUMP == (NLM_F_ROOT | NLM_F_MATCH)
        assert NLMSG_DONE == 0x3
        assert NLMSG_ERROR == 0x2
        assert RTM_GETLINK == 0x12
        assert RTM_NEWLINK == 0x10
Esempio n. 3
0
    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self.rescan_devices()
Esempio n. 4
0
 def __init__(self, context):
     threading.Thread.__init__(self)
     self.logger = logging.getLogger(__name__)
     self.context = context
     self.ip = IPRSocket()
     self.ip.bind(rtnl.RTNLGRP_LINK | rtnl.RTNLGRP_NOTIFY)
     self.control = None
     self.state = ''
     self.carrier = -1
Esempio n. 5
0
    def __init__(self, server_handler):
        self._devices = {} #if_index to device
        self._id_mapping = {} #id from the ctl to if_index
        self._tmp_mapping = {} #id from the ctl to newly created device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind()

        self.rescan_devices()

        self._server_handler = server_handler
Esempio n. 6
0
    def __init__(self, server_handler):
        self._device_classes = {}

        self._devices = {} #if_index to device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._dl_manager = DevlinkManager()

        self._server_handler = server_handler
Esempio n. 7
0
class NICMonitor(threading.Thread):
    def __init__(self, context):
        threading.Thread.__init__(self)
        self.logger = logging.getLogger(__name__)
        self.context = context
        self.ip = IPRSocket()
        self.ip.bind(rtnl.RTNLGRP_LINK | rtnl.RTNLGRP_NOTIFY)
        self.control = None
        self.state = ''
        self.carrier = -1

    def setup(self):
        self.logger.info('NICMon:setup()')
        self.control = self.context.socket(zmq.PAIR)
        self.control.bind(const.fmNICMonitorEndpoint)
        return self.control

    def run(self):
        self.command = self.context.socket(zmq.PAIR)
        self.command.connect(const.fmNICMonitorEndpoint)
        self.poller = zmq.Poller()
        self.poller.register(self.ip._sock, zmq.POLLIN)
        self.poller.register(self.command, zmq.POLLIN)
        while True:
            sockets = dict(self.poller.poll())
            if self.ip._sock.fileno() in sockets:
                infos = self.ip.get()
                for info in infos:
                    attrs = dict(info['attrs'])
                    ifname = attrs['IFLA_IFNAME']
                    state = attrs['IFLA_OPERSTATE']
                    carrier = attrs['IFLA_CARRIER']
                    if ifname == Config.NIC_NAME and state != self.state and carrier != self.carrier:
                        self.logger.info(
                            "NICMonitor: state has changed (%s,%d)" %
                            (state, carrier))
                        if state != 'UP' or carrier != 1:  # NIC down and/or carrier lost
                            info = ('nic-', )
                            self.command.send_pyobj(info)
                        elif state == 'UP' and carrier == 1:  # NIC UP and carrier is on
                            info = ('nic+', )
                            self.command.send_pyobj(info)
                        self.state, self.carrier = state, carrier
                del sockets[self.ip._sock.fileno()]
            elif self.command in sockets:
                msg = self.command.recv_pyobj()
                if msg == 'stop':
                    break
                del sockets[self.command]
        self.command.close()
        self.ip.close()

    def terminate(self):
        self.control.send_pyobj('stop')
Esempio n. 8
0
    def __init__(self, server_handler):
        self._devices = {} #if_index to device
        self._id_mapping = {} #id from the ctl to if_index
        self._tmp_mapping = {} #id from the ctl to newly created device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._dl_manager = DevlinkManager()

        self.rescan_devices()

        self._server_handler = server_handler
Esempio n. 9
0
    def __init__(self, server_handler):
        self._device_classes = {}

        self._devices = {}  #ifindex to device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._msg_queue = deque()

        #TODO split DevlinkManager away from the InterfaceManager
        #self._dl_manager = DevlinkManager()

        self._server_handler = server_handler
Esempio n. 10
0
    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self.rescan_devices()
Esempio n. 11
0
    def __init__(self, server_handler):
        self._devices = {}
        self._id_mapping = {}  # id from the ctl to device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind()

        self.rescan_devices()

        self._server_handler = server_handler
Esempio n. 12
0
    def test_basic(self):
        from pyroute2 import IPRSocket
        from pyroute2.netlink import NLM_F_REQUEST
        from pyroute2.netlink import NLM_F_DUMP
        from pyroute2.netlink import NLM_F_ROOT
        from pyroute2.netlink import NLM_F_MATCH
        from pyroute2.netlink import NLMSG_DONE
        from pyroute2.netlink import NLMSG_ERROR
        from pyroute2.netlink import nlmsg
        from pyroute2.iproute import RTM_GETLINK
        from pyroute2.iproute import RTM_NEWLINK
        from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg

        ip = IPRSocket()
        ip.bind()

        # check the `socket` interface compliance
        poll = select.poll()
        poll.register(ip, select.POLLIN | select.POLLPRI)
        poll.unregister(ip)
        ip.close()

        assert issubclass(ifinfmsg, nlmsg)
        assert NLM_F_REQUEST == 1
        assert NLM_F_ROOT == 0x100
        assert NLM_F_MATCH == 0x200
        assert NLM_F_DUMP == (NLM_F_ROOT | NLM_F_MATCH)
        assert NLMSG_DONE == 0x3
        assert NLMSG_ERROR == 0x2
        assert RTM_GETLINK == 0x12
        assert RTM_NEWLINK == 0x10
Esempio n. 13
0
    def test_imports(self):
        from pyroute2 import IPRSocket
        from pyroute2.netlink import NLM_F_REQUEST
        from pyroute2.netlink import NLM_F_DUMP
        from pyroute2.netlink import NLM_F_ROOT
        from pyroute2.netlink import NLM_F_MATCH
        from pyroute2.netlink import NLMSG_DONE
        from pyroute2.netlink import NLMSG_ERROR
        from pyroute2.netlink.iproute import RTM_GETLINK
        from pyroute2.netlink.iproute import RTM_NEWLINK
        from pyroute2.netlink.generic import nlmsg
        from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg

        ip = IPRSocket()
        ip.bind()
        ip.close()

        assert issubclass(IPRSocket, socket.socket)
        assert issubclass(ifinfmsg, nlmsg)
        assert NLM_F_REQUEST == 1
        assert NLM_F_ROOT == 0x100
        assert NLM_F_MATCH == 0x200
        assert NLM_F_DUMP == (NLM_F_ROOT | NLM_F_MATCH)
        assert NLMSG_DONE == 0x3
        assert NLMSG_ERROR == 0x2
        assert RTM_GETLINK == 0x12
        assert RTM_NEWLINK == 0x10
Esempio n. 14
0
    def test_isinstance(self):
        from pyroute2 import IPRSocket
        from pyroute2 import IPRoute
        from pyroute2.iproute import IPRoute as IPRoute_real
        from pyroute2.netlink.rtnl.iprsocket import IPRSocket as IPRSocket_real

        ipr1 = IPRoute()
        ipr2 = IPRoute_real()

        ips1 = IPRSocket()
        ips2 = IPRSocket_real()

        # positive
        assert isinstance(ips1, IPRSocket)
        assert isinstance(ips2, IPRSocket)
        assert isinstance(ips1, IPRSocket_real)
        assert isinstance(ips2, IPRSocket_real)

        assert isinstance(ipr1, IPRoute)
        assert isinstance(ipr2, IPRoute)
        assert isinstance(ipr1, IPRoute_real)
        assert isinstance(ipr2, IPRoute_real)

        # negative
        assert not isinstance(ips1, IPRoute)
        assert not isinstance(ips2, IPRoute)
        assert not isinstance(ips1, IPRoute_real)
        assert not isinstance(ips2, IPRoute_real)

        # this must succeed -- IPRoute is a subclass of IPRSocket
        assert isinstance(ipr1, IPRSocket)
        assert isinstance(ipr2, IPRSocket)
        assert isinstance(ipr1, IPRSocket_real)
        assert isinstance(ipr2, IPRSocket_real)

        ips1.close()
        ips2.close()
        ipr1.close()
        ipr2.close()
Esempio n. 15
0
    def test_isinstance(self):
        from pyroute2 import IPRSocket
        from pyroute2 import IPRoute
        from pyroute2.iproute import IPRoute as IPRoute_real
        from pyroute2.netlink.rtnl.iprsocket import IPRSocket as IPRSocket_real

        ipr1 = IPRoute()
        ipr2 = IPRoute_real()

        ips1 = IPRSocket()
        ips2 = IPRSocket_real()

        # positive
        assert isinstance(ips1, IPRSocket)
        assert isinstance(ips2, IPRSocket)
        assert isinstance(ips1, IPRSocket_real)
        assert isinstance(ips2, IPRSocket_real)

        assert isinstance(ipr1, IPRoute)
        assert isinstance(ipr2, IPRoute)
        assert isinstance(ipr1, IPRoute_real)
        assert isinstance(ipr2, IPRoute_real)

        # negative
        assert not isinstance(ips1, IPRoute)
        assert not isinstance(ips2, IPRoute)
        assert not isinstance(ips1, IPRoute_real)
        assert not isinstance(ips2, IPRoute_real)

        # this must succeed -- IPRoute is a subclass of IPRSocket
        assert isinstance(ipr1, IPRSocket)
        assert isinstance(ipr2, IPRSocket)
        assert isinstance(ipr1, IPRSocket_real)
        assert isinstance(ipr2, IPRSocket_real)

        ips1.close()
        ips2.close()
        ipr1.close()
        ipr2.close()
Esempio n. 16
0
    def __init__(self, server_handler):
        self._devices = {} #if_index to device
        self._id_mapping = {} #id from the ctl to if_index
        self._tmp_mapping = {} #id from the ctl to newly created device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._dl_manager = DevlinkManager()

        self.rescan_devices()

        self._server_handler = server_handler
    def start_listening(self):

        if self.socket is None:
            self.socket = IPRSocket()

        self.socket.bind()

        self.logger.info("Starting listener...")
        self.listen = True
        while self.listen:
            r, _, _ = select((self.socket, ), (), (), 0.5)
            if r:
                msg_array = self.socket.get()
                for event_msg in msg_array:
                    try:
                        self.queue.put(event_msg)
                    except Queue.Full:
                        self.logger.warn(
                            "Message queue is full! it has %s elements",
                            self.queue.qsize())

        # stop after listening
        self.socket.close()
        self.logger.debug("Socket closed")
Esempio n. 18
0
def scan_netdevs():
    scan = []
    nl_socket = IPRSocket()
    msg = ifinfmsg()
    msg["family"] = socket.AF_UNSPEC
    msg["header"]["type"] = RTM_GETLINK
    msg["header"]["flags"] = NLM_F_REQUEST | NLM_F_DUMP
    msg["header"]["pid"] = os.getpid()
    msg["header"]["sequence_number"] = 1
    msg.encode()

    nl_socket.sendto(msg.buf.getvalue(), (0,0))

    finished = False
    while not finished:
        parts = nl_socket.get()
        for part in parts:
            if part["header"]["type"] in [NLMSG_DONE, NLMSG_ERROR]:
                finished = True
                continue
            if part["header"]["sequence_number"] != 1:
                continue

            if part["header"]["type"] == RTM_NEWLINK:
                new_link = {}
                new_link["netlink_msg"] = part
                new_link["index"] = part["index"]
                new_link["name"] = part.get_attr("IFLA_IFNAME")

                hwaddr = part.get_attr("IFLA_ADDRESS")
                new_link["hwaddr"] = normalize_hwaddr(hwaddr)

                scan.append(new_link)

    nl_socket.close()
    return scan
Esempio n. 19
0
    "ctn2": "10.200.0.3",
}

ctn_arp = {
    "10.200.0.2": "02:42:0a:00:00:02",
    "10.200.0.3": "02:42:0a:00:00:03"
}

ctn_fib = {
    "02:42:0a:00:00:02": "10.200.129.100",
    "02:42:0a:00:00:03": "10.200.128.218"
}

logging.basicConfig(format='%(levelname)s %(message)s', level=logging.INFO)
ipr = IPRoute()
s = IPRSocket()
s.bind()

while True:
    msg = s.get()
    for m in msg:
        logging.debug('Received an event: {}'.format(m['event']))
        if m['event'] != 'RTM_GETNEIGH':
            continue

        logging.debug("Received a Neighbor miss")

        ifindex = m['ifindex']
        ifname = ipr.get_links(ifindex)[0].get_attr("IFLA_IFNAME")
        logging.debug("Family: {}".format(
            if_family.get(m['family'], m['family'])))
Esempio n. 20
0
'''
Simplest example to monitor Netlink events with a Python script.
'''

from pyroute2 import IPRSocket
from pprint import pprint

ip = IPRSocket()
ip.bind()
pprint(ip.get())
ip.close()
Esempio n. 21
0
class InterfaceManager(object):
    def __init__(self, server_handler):
        self._devices = {}
        self._id_mapping = {}  # id from the ctl to device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind()

        self.rescan_devices()

        self._server_handler = server_handler

    def map_if(self, if_id, if_index):
        if if_id in self._id_mapping:
            raise IfMgrError("Interface already mapped.")
        elif if_index not in self._devices:
            raise IfMgrError("No interface with index %s found." % if_index)

        self._id_mapping[if_id] = self._devices[if_index]
        return

    def clear_if_mapping(self):
        self._id_mapping = {}

    def get_nl_socket(self):
        return self._nl_socket

    def rescan_devices(self):
        self._devices = {}
        devs = scan_netdevs()
        for dev in devs:
            if dev["index"] not in self._devices:
                device = Device(self)
                device.init_netlink(dev["netlink_msg"])

                self._devices[dev["index"]] = device

    def handle_netlink_msgs(self, msgs):
        for msg in msgs:
            self._handle_netlink_msg(msg)

    def _handle_netlink_msg(self, msg):
        if msg["header"]["type"] == RTM_NEWLINK:
            if msg["index"] in self._devices:
                update_msg = self._devices[msg["index"]].update_netlink(msg)
                if update_msg != None:
                    for if_id, dev in self._id_mapping.iteritems():
                        if dev.get_if_index() == msg["index"]:
                            update_msg["if_id"] = if_id
                            break
                    if "if_id" in update_msg:
                        self._server_handler.send_data_to_ctl(update_msg)
            else:
                dev = None
                for d in self._id_mapping.values():
                    d_cfg = d.get_conf_dict()
                    if d.get_if_index() == None and d_cfg["name"] == msg.get_attr("IFLA_IFNAME"):
                        dev = d
                        break
                if dev == None:
                    dev = Device(self)
                dev.init_netlink(msg)
                self._devices[msg["index"]] = dev
        elif msg["header"]["type"] == RTM_DELLINK:
            if msg["index"] in self._devices:
                self._devices[msg["index"]].del_link()
                del self._devices[msg["index"]]
        else:
            return

    def get_mapped_device(self, if_id):
        if if_id in self._id_mapping:
            return self._id_mapping[if_id]
        else:
            raise IfMgrError("No device with id %s mapped." % if_id)

    def get_mapped_devices(self):
        return self._id_mapping

    def get_device(self, if_index):
        if if_index in self._devices:
            return self._devices[if_index]
        else:
            return None

    def get_devices(self):
        return self._devices.values()

    def get_device_by_hwaddr(self, hwaddr):
        for dev in self._devices.values():
            if dev.get_hwaddr() == hwaddr:
                return dev
        return None

    def deconfigure_all(self):
        for dev in self._devices.itervalues():
            dev.clear_configuration()

    def create_device_from_config(self, if_id, config):
        if config["type"] == "eth":
            raise IfMgrError("Ethernet devices can't be created.")

        config["name"] = self.assign_name(config)

        device = Device(self)
        device.set_configuration(config)
        device.configure()

        self._id_mapping[if_id] = device
        return config["name"]

    def _is_name_used(self, name):
        for device in self._devices.itervalues():
            if name == device.get_name():
                return True
        return False

    def _assign_name_generic(self, prefix):
        index = 0
        while self._is_name_used(prefix + str(index)):
            index += 1
        return prefix + str(index)

    def assign_name(self, config):
        if "name" in config:
            return config["name"]
        dev_type = config["type"]
        if dev_type == "eth":
            if not "hwaddr" in config or "name" in config:
                return
            hwaddr = normalize_hwaddr(netdev["hwaddr"])
            for dev in self._devices:
                if dev.get_hwaddr() == hwaddr:
                    return dev.get_name()
        elif dev_type == "bond":
            return self._assign_name_generic("t_bond")
        elif dev_type == "bridge" or dev_type == "ovs_bridge":
            return self._assign_name_generic("t_br")
        elif dev_type == "macvlan":
            return self._assign_name_generic("t_macvlan")
        elif dev_type == "team":
            return self._assign_name_generic("t_team")
        elif dev_type == "vlan":
            netdev_name = self.get_mapped_device(config["slaves"][0]).get_name()
            vlan_tci = get_option(config, "vlan_tci")
            prefix = "%s.%s_" % (netdev_name, vlan_tci)
            return self._assign_name_generic(prefix)
Esempio n. 22
0
class InterfaceManager(object):
    def __init__(self, server_handler):
        self._devices = {} #if_index to device
        self._id_mapping = {} #id from the ctl to if_index
        self._tmp_mapping = {} #id from the ctl to newly created device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind()

        self.rescan_devices()

        self._server_handler = server_handler

    def map_if(self, if_id, if_index):
        if if_id in self._id_mapping:
            raise IfMgrError("Interface already mapped.")
        elif if_index not in self._devices:
            raise IfMgrError("No interface with index %s found." % if_index)

        self._id_mapping[if_id] = if_index
        return

    def unmap_if(self, if_id):
        if if_id in self._id_mapping:
            del self._id_mapping[if_id]
        elif if_id in self._tmp_mapping:
            del self._tmp_mapping[if_id]
        else:
            pass

    def clear_if_mapping(self):
        self._id_mapping = {}

    def get_id_by_if_index(self, if_index):
        for if_id, index in self._id_mapping.iteritems():
            if if_index == index:
                return if_id
        return None

    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind()

    def get_nl_socket(self):
        return self._nl_socket

    def rescan_devices(self):
        self._devices = {}
        devs = scan_netdevs()
        for dev in devs:
            if dev['index'] not in self._devices:
                device = Device(self)
                device.init_netlink(dev['netlink_msg'])

                self._devices[dev['index']] = device

    def handle_netlink_msgs(self, msgs):
        for msg in msgs:
            self._handle_netlink_msg(msg)

    def _handle_netlink_msg(self, msg):
        if msg['header']['type'] == RTM_NEWLINK:
            if msg['index'] in self._devices:
                update_msg = self._devices[msg['index']].update_netlink(msg)
                if update_msg != None:
                    for if_id, if_index in self._id_mapping.iteritems():
                        if if_index == msg['index']:
                            update_msg["if_id"] = if_id
                            break
                    if "if_id" in update_msg:
                        self._server_handler.send_data_to_ctl(update_msg)
            else:
                dev = None
                for if_id, d in self._tmp_mapping.items():
                    d_cfg = d.get_conf_dict()
                    if d_cfg["name"] == msg.get_attr("IFLA_IFNAME"):
                        dev = d
                        self._id_mapping[if_id] = msg['index']
                        del self._tmp_mapping[if_id]
                        break
                if dev == None:
                    dev = Device(self)
                dev.init_netlink(msg)
                self._devices[msg['index']] = dev
        elif msg['header']['type'] == RTM_DELLINK:
            if msg['index'] in self._devices:
                dev = self._devices[msg['index']]
                if dev.get_netns() == None and dev.get_conf_dict() == None:
                    dev.del_link()
                    del self._devices[msg['index']]
        else:
            return

    def get_mapped_device(self, if_id):
        if if_id in self._id_mapping:
            if_index = self._id_mapping[if_id]
            return self._devices[if_index]
        elif if_id in self._tmp_mapping:
            return self._tmp_mapping[if_id]
        else:
            return None

    def get_mapped_devices(self):
        ret = {}
        for if_id, if_index in self._id_mapping.iteritems():
            ret[if_id] = self._devices[if_index]
        for if_id in self._tmp_mapping:
            ret[if_id] = self._tmp_mapping[if_id]
        return ret

    def get_device(self, if_index):
        if if_index in self._devices:
            return self._devices[if_index]
        else:
            return None

    def get_devices(self):
        return self._devices.values()

    def get_device_by_hwaddr(self, hwaddr):
        for dev in self._devices.values():
            if dev.get_hwaddr() == hwaddr:
                return dev
        return None

    def get_device_by_params(self, params):
        matched = None
        for dev in self._devices.values():
            matched = dev
            dev_data = dev.get_if_data()
            for key, value in params.iteritems():
                if key not in dev_data or dev_data[key] != value:
                    matched = None
                    break

            if matched:
                break

        return matched

    def deconfigure_all(self):
        for dev in self._devices.itervalues():
            dev.clear_configuration()

    def create_device_from_config(self, if_id, config):
        if config["type"] == "eth":
            raise IfMgrError("Ethernet devices can't be created.")

        config["name"] = self.assign_name(config)

        device = Device(self)
        device.set_configuration(config)
        device.create()

        self._tmp_mapping[if_id] = device
        return config["name"]

    def create_device_pair(self, if_id1, config1, if_id2, config2):
        name1, name2 = self.assign_name(config1)
        config1["name"] = name1
        config2["name"] = name2
        config1["peer_name"] = name2
        config2["peer_name"] = name1

        device1 = Device(self)
        device2 = Device(self)

        device1.set_configuration(config1)
        device2.set_configuration(config2)
        device1.create()

        device1.set_peer(device2)
        device2.set_peer(device1)

        self._tmp_mapping[if_id1] = device1
        self._tmp_mapping[if_id2] = device2
        return name1, name2

    def _is_name_used(self, name):
        for device in self._devices.itervalues():
            if name == device.get_name():
                return True
        for device in self._tmp_mapping.itervalues():
            if name == device.get_name():
                return True
        return False

    def _assign_name_generic(self, prefix):
        index = 0
        while (self._is_name_used(prefix + str(index))):
            index += 1
        return prefix + str(index)

    def _assign_name_pair(self, prefix):
        index1 = 0
        index2 = 0
        while (self._is_name_used(prefix + str(index1))):
            index1 += 1
        index2 = index1 + 1
        while (self._is_name_used(prefix + str(index2))):
            index2 += 1
        return prefix + str(index1), prefix + str(index2)

    def assign_name(self, config):
        if "name" in config:
            return config["name"]
        dev_type = config["type"]
        if dev_type == "eth":
            if (not "hwaddr" in config or
                "name" in config):
                return
            hwaddr = normalize_hwaddr(config["hwaddr"])
            for dev in self._devices:
                if dev.get_hwaddr() == hwaddr:
                    return dev.get_name()
        elif dev_type == "bond":
            return self._assign_name_generic("t_bond")
        elif dev_type == "bridge" or dev_type == "ovs_bridge":
            return self._assign_name_generic("t_br")
        elif dev_type == "macvlan":
            return self._assign_name_generic("t_macvlan")
        elif dev_type == "team":
            return self._assign_name_generic("t_team")
        elif dev_type == "vlan":
            netdev_name = self.get_mapped_device(config["slaves"][0]).get_name()
            vlan_tci = get_option(config, "vlan_tci")
            prefix = "%s.%s_" % (netdev_name, vlan_tci)
            return self._assign_name_generic(prefix)
        elif dev_type == "veth":
            return self._assign_name_pair("veth")
        elif dev_type == "vti":
            return self._assign_name_generic("vti")
        elif dev_type == "vti6":
            return self._assign_name_generic("t_ip6vti")
        else:
            return self._assign_name_generic("dev")
Esempio n. 23
0
class InterfaceManager(object):
    def __init__(self, server_handler):
        self._devices = {} #if_index to device
        self._id_mapping = {} #id from the ctl to if_index
        self._tmp_mapping = {} #id from the ctl to newly created device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._dl_manager = DevlinkManager()

        self.rescan_devices()

        self._server_handler = server_handler

    def map_if(self, if_id, if_index):
        if if_id in self._id_mapping:
            raise IfMgrError("Interface already mapped.")
        elif if_index not in self._devices:
            raise IfMgrError("No interface with index %s found." % if_index)

        self._id_mapping[if_id] = if_index
        return

    def unmap_if(self, if_id):
        if if_id in self._id_mapping:
            del self._id_mapping[if_id]
        elif if_id in self._tmp_mapping:
            del self._tmp_mapping[if_id]
        else:
            pass

    def clear_if_mapping(self):
        self._id_mapping = {}

    def get_id_by_if_index(self, if_index):
        for if_id, index in self._id_mapping.iteritems():
            if if_index == index:
                return if_id
        return None

    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self.rescan_devices()

    def get_nl_socket(self):
        return self._nl_socket

    def rescan_devices(self):
        devices_to_remove = self._devices.keys()
        devs = scan_netdevs()
        for dev in devs:
            if dev['index'] not in self._devices:
                device = None
                for if_id, d in self._tmp_mapping.items():
                    d_cfg = d.get_conf_dict()
                    if d_cfg["name"] == dev["name"]:
                        device = d
                        self._id_mapping[if_id] = dev['index']
                        del self._tmp_mapping[if_id]
                        break
                if device == None:
                    device = Device(self)
                device.init_netlink(dev['netlink_msg'])
                self._devices[dev['index']] = device
            else:
                self._devices[dev['index']].update_netlink(dev['netlink_msg'])
                devices_to_remove.remove(dev['index'])

            self._devices[dev['index']].clear_ips()
            for addr_msg in dev['ip_addrs']:
                self._devices[dev['index']].update_netlink(addr_msg)
        for i in devices_to_remove:
            if self._devices[i].get_netns() != None:
                continue

            dev_name = self._devices[i].get_name()
            logging.debug("Deleting Device with if_index %d, name %s because "\
                          "it doesn't exist anymore." % (i, dev_name))

            del_msg = {"type": "if_deleted",
                       "if_index": i}
            self._server_handler.send_data_to_ctl(del_msg)
            del self._devices[i]

        self._dl_manager.rescan_ports()
        for device in self._devices.values():
            dl_port = self._dl_manager.get_port(device.get_name())
            device.set_devlink(dl_port)

    def handle_netlink_msgs(self, msgs):
        for msg in msgs:
            self._handle_netlink_msg(msg)

        self._dl_manager.rescan_ports()
        for device in self._devices.values():
            dl_port = self._dl_manager.get_port(device.get_name())
            device.set_devlink(dl_port)

    def _handle_netlink_msg(self, msg):
        if msg['header']['type'] in [RTM_NEWLINK, RTM_NEWADDR, RTM_DELADDR]:
            if msg['index'] in self._devices:
                update_msg = self._devices[msg['index']].update_netlink(msg)
                if update_msg != None:
                    for if_id, if_index in self._id_mapping.iteritems():
                        if if_index == msg['index']:
                            update_msg["if_id"] = if_id
                            break
                    self._server_handler.send_data_to_ctl(update_msg)
            elif msg['header']['type'] == RTM_NEWLINK:
                dev = None
                for if_id, d in self._tmp_mapping.items():
                    d_cfg = d.get_conf_dict()
                    if d_cfg["name"] == msg.get_attr("IFLA_IFNAME"):
                        dev = d
                        self._id_mapping[if_id] = msg['index']
                        del self._tmp_mapping[if_id]
                        break
                if dev == None:
                    dev = Device(self)
                update_msg = dev.init_netlink(msg)
                self._devices[msg['index']] = dev

                if update_msg != None:
                    for if_id, if_index in self._id_mapping.iteritems():
                        if if_index == msg['index']:
                            update_msg["if_id"] = if_id
                            break
                    self._server_handler.send_data_to_ctl(update_msg)

        elif msg['header']['type'] == RTM_DELLINK:
            if msg['index'] in self._devices:
                dev = self._devices[msg['index']]
                if dev.get_netns() == None and dev.get_conf_dict() == None:
                    dev.del_link()
                    del self._devices[msg['index']]

                    del_msg = {"type": "if_deleted",
                               "if_index": msg['index']}
                    self._server_handler.send_data_to_ctl(del_msg)
        else:
            return

    def get_mapped_device(self, if_id):
        if if_id in self._id_mapping:
            if_index = self._id_mapping[if_id]
            return self._devices[if_index]
        elif if_id in self._tmp_mapping:
            return self._tmp_mapping[if_id]
        else:
            return None

    def get_mapped_devices(self):
        ret = {}
        for if_id, if_index in self._id_mapping.iteritems():
            ret[if_id] = self._devices[if_index]
        for if_id in self._tmp_mapping:
            ret[if_id] = self._tmp_mapping[if_id]
        return ret

    def get_device(self, if_index):
        if if_index in self._devices:
            return self._devices[if_index]
        else:
            return None

    def get_devices(self):
        return self._devices.values()

    def get_device_by_hwaddr(self, hwaddr):
        for dev in self._devices.values():
            if dev.get_hwaddr() == hwaddr:
                return dev
        return None

    def get_device_by_params(self, params):
        matched = None
        for dev in self._devices.values():
            matched = dev
            dev_data = dev.get_if_data()
            for key, value in params.iteritems():
                if key not in dev_data or dev_data[key] != value:
                    matched = None
                    break

            if matched:
                break

        return matched

    def deconfigure_all(self):
        for dev in self._devices.itervalues():
            dev.clear_configuration()

    def create_device_from_config(self, if_id, config):
        if config["type"] == "eth":
            raise IfMgrError("Ethernet devices can't be created.")

        config["name"] = self.assign_name(config)

        device = Device(self)
        self._tmp_mapping[if_id] = device

        device.set_configuration(config)
        device.create()

        return config["name"]

    def create_device_pair(self, if_id1, config1, if_id2, config2):
        name1, name2 = self.assign_name(config1)
        config1["name"] = name1
        config2["name"] = name2
        config1["peer_name"] = name2
        config2["peer_name"] = name1

        device1 = Device(self)
        device2 = Device(self)
        self._tmp_mapping[if_id1] = device1
        self._tmp_mapping[if_id2] = device2

        device1.set_configuration(config1)
        device2.set_configuration(config2)
        device1.create()

        device1.set_peer(device2)
        device2.set_peer(device1)
        return name1, name2

    def wait_interface_init(self):
        while len(self._tmp_mapping) > 0:
            rl, wl, xl = select.select([self._nl_socket], [], [], 1)

            if len(rl) == 0:
                continue

            msgs = recv_data(self._nl_socket)["data"]
            self.handle_netlink_msgs(msgs)

    def _is_name_used(self, name):
        self.rescan_devices()
        for device in self._devices.itervalues():
            if name == device.get_name():
                return True
        for device in self._tmp_mapping.itervalues():
            if name == device.get_name():
                return True
        return False

    def assign_name_generic(self, prefix):
        index = 0
        while (self._is_name_used(prefix + str(index))):
            index += 1
        return prefix + str(index)

    def _assign_name_pair(self, prefix):
        index1 = 0
        index2 = 0
        while (self._is_name_used(prefix + str(index1))):
            index1 += 1
        index2 = index1 + 1
        while (self._is_name_used(prefix + str(index2))):
            index2 += 1
        return prefix + str(index1), prefix + str(index2)

    def assign_name(self, config):
        if "name" in config:
            return config["name"]
        dev_type = config["type"]
        if dev_type == "eth":
            if (not "hwaddr" in config or
                "name" in config):
                return
            hwaddr = normalize_hwaddr(config["hwaddr"])
            for dev in self._devices:
                if dev.get_hwaddr() == hwaddr:
                    return dev.get_name()
        elif dev_type == "bond":
            return self.assign_name_generic("t_bond")
        elif dev_type == "bridge" or dev_type == "ovs_bridge":
            return self.assign_name_generic("t_br")
        elif dev_type == "macvlan":
            return self.assign_name_generic("t_macvlan")
        elif dev_type == "team":
            return self.assign_name_generic("t_team")
        elif dev_type == "vlan":
            netdev_name = self.get_mapped_device(config["slaves"][0]).get_name()
            vlan_tci = get_option(config, "vlan_tci")
            prefix = "%s.%s_" % (netdev_name, vlan_tci)
            return self.assign_name_generic(prefix)
        elif dev_type == "veth":
            return self._assign_name_pair("veth")
        elif dev_type == "vti":
            return self.assign_name_generic("vti")
        elif dev_type == "vti6":
            return self.assign_name_generic("t_ip6vti")
        elif dev_type == "vxlan":
            return self.assign_name_generic("vxlan")
        elif dev_type == "gre":
            return self.assign_name_generic("gre_")
        elif dev_type == "ipip":
            return self.assign_name_generic("ipip_")
        elif dev_type == "dummy":
            return self.assign_name_generic("dummy_")
        else:
            return self.assign_name_generic("dev")
Esempio n. 24
0
class InterfaceManager(object):
    def __init__(self, server_handler):
        self._device_classes = {}

        self._devices = {}  #ifindex to device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._msg_queue = deque()

        #TODO split DevlinkManager away from the InterfaceManager
        #self._dl_manager = DevlinkManager()

        self._server_handler = server_handler

    def clear_dev_classes(self):
        self._device_classes = {}

    def add_device_class(self, name, cls):
        if name in self._device_classes:
            raise InterfaceManagerError("Device class name conflict %s" % name)

        self._device_classes[name] = cls
        return cls

    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self.rescan_devices()

    def get_nl_socket(self):
        return self._nl_socket

    def pull_netlink_messages_into_queue(self):
        try:
            while True:
                rl, wl, xl = select.select([self._nl_socket], [], [], 0)
                if not len(rl):
                    break
                self._msg_queue.extend(self._nl_socket.get())
        except socket.error:
            self.reconnect_netlink()
            return []

    def rescan_devices(self):
        self.request_netlink_dump()
        self.handle_netlink_msgs()

    def request_netlink_dump(self):
        self._nl_socket.put(None,
                            RTM_GETLINK,
                            msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
        self._nl_socket.put(None,
                            RTM_GETADDR,
                            msg_flags=NLM_F_REQUEST | NLM_F_DUMP)

    def handle_netlink_msgs(self):
        self.pull_netlink_messages_into_queue()

        while len(self._msg_queue):
            msg = self._msg_queue.popleft()
            self._handle_netlink_msg(msg)

        # self._dl_manager.rescan_ports()
        # for device in self._devices.values():
        # dl_port = self._dl_manager.get_port(device.name)
        # device._set_devlink(dl_port)

    def _handle_netlink_msg(self, msg):
        if msg['header']['type'] in [RTM_NEWLINK, RTM_NEWADDR, RTM_DELADDR]:
            if msg['index'] in self._devices:
                self._devices[msg['index']]._update_netlink(msg)
            elif msg['header']['type'] == RTM_NEWLINK:
                dev = self._device_classes["Device"](self)
                dev._init_netlink(msg)
                self._devices[msg['index']] = dev

                update_msg = {
                    "type": "dev_created",
                    "dev_data": dev._get_if_data()
                }
                self._server_handler.send_data_to_ctl(update_msg)

                dev._disable()
        elif msg['header']['type'] == RTM_DELLINK:
            if msg['family'] == PF_BRIDGE:
                return

            if msg['index'] in self._devices:
                dev = self._devices[msg['index']]
                dev._deleted = True

                del self._devices[msg['index']]

                del_msg = {"type": "dev_deleted", "ifindex": msg['index']}
                self._server_handler.send_data_to_ctl(del_msg)
        else:
            return

    def untrack_device(self, dev):
        if dev.ifindex in self._devices:
            del self._devices[dev.ifindex]

    def get_device(self, ifindex):
        self.rescan_devices()
        if ifindex in self._devices:
            return self._devices[ifindex]
        else:
            raise DeviceNotFound()

    def get_devices(self):
        self.rescan_devices()
        return list(self._devices.values())

    def get_device_by_hwaddr(self, hwaddr):
        self.rescan_devices()
        for dev in list(self._devices.values()):
            if dev.hwaddr == hwaddr:
                return dev
        raise DeviceNotFound()

    def get_device_by_name(self, name):
        self.rescan_devices()
        for dev in list(self._devices.values()):
            if dev.name == name:
                return dev
        raise DeviceNotFound()

    def get_device_by_params(self, params):
        self.rescan_devices()
        matched = None
        for dev in list(self._devices.values()):
            matched = dev
            dev_data = dev.get_if_data()
            for key, value in params.items():
                if key not in dev_data or dev_data[key] != value:
                    matched = None
                    break

            if matched:
                break

        return matched

    def deconfigure_all(self):
        for dev in self._devices.values():
            pass
            # dev.clear_configuration()

    def create_device(self, clsname, args=[], kwargs={}):
        devcls = self._device_classes[clsname]

        try:
            device = devcls(self, *args, **kwargs)
        except KeyError as e:
            raise DeviceConfigError("%s is a mandatory argument" % e)
        device._create()
        device._bulk_enabled = False

        self.request_netlink_dump()
        self.pull_netlink_messages_into_queue()

        device_found = False
        while len(self._msg_queue):
            msg = self._msg_queue.popleft()
            if msg.get_attr("IFLA_IFNAME") == device.name:
                device_found = True
                device._init_netlink(msg)
                self._devices[msg['index']] = device
            else:
                self._handle_netlink_msg(msg)

        if device_found:
            return device
        else:
            raise DeviceError("Device creation failed")

    def replace_dev(self, if_id, dev):
        del self._devices[if_id]
        self._devices[if_id] = dev

    def _is_name_used(self, name):
        self.rescan_devices()
        for device in self._devices.values():
            if name == device.name:
                return True

        out, _ = exec_cmd("ovs-vsctl --columns=name list Interface",
                          log_outputs=False,
                          die_on_err=False)
        for line in out.split("\n"):
            m = re.match(r'.*: \"(.*)\"', line)
            if m is not None:
                if name == m.group(1):
                    return True
        return False

    def assign_name(self, prefix):
        index = 0
        while (self._is_name_used(prefix + str(index))):
            index += 1
        return prefix + str(index)

    def _assign_name_pair(self, prefix):
        index1 = 0
        index2 = 0
        while (self._is_name_used(prefix + str(index1))):
            index1 += 1
        index2 = index1 + 1
        while (self._is_name_used(prefix + str(index2))):
            index2 += 1
        return prefix + str(index1), prefix + str(index2)
    def __init__(self, api, config, *args, **kw):

        super(NetLinkListener, self).__init__(api, config, *args, **kw)
        self.listen = True
        self.socket = IPRSocket()
Esempio n. 26
0
class InterfaceManager(object):
    def __init__(self, server_handler):
        self._devices = {} #if_index to device
        self._id_mapping = {} #id from the ctl to if_index
        self._tmp_mapping = {} #id from the ctl to newly created device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._dl_manager = DevlinkManager()

        self.rescan_devices()

        self._server_handler = server_handler

    def map_if(self, if_id, if_index):
        if if_id in self._id_mapping:
            raise IfMgrError("Interface already mapped.")
        elif if_index not in self._devices:
            raise IfMgrError("No interface with index %s found." % if_index)

        self._id_mapping[if_id] = if_index
        return

    def unmap_if(self, if_id):
        if if_id in self._id_mapping:
            del self._id_mapping[if_id]
        elif if_id in self._tmp_mapping:
            del self._tmp_mapping[if_id]
        else:
            pass

    def clear_if_mapping(self):
        self._id_mapping = {}

    def get_id_by_if_index(self, if_index):
        for if_id, index in self._id_mapping.iteritems():
            if if_index == index:
                return if_id
        return None

    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self.rescan_devices()

    def get_nl_socket(self):
        return self._nl_socket

    def rescan_devices(self):
        devices_to_remove = self._devices.keys()
        devs = scan_netdevs()
        for dev in devs:
            if dev['index'] not in self._devices:
                device = None
                for if_id, d in self._tmp_mapping.items():
                    d_cfg = d.get_conf_dict()
                    if d_cfg["name"] == dev["name"]:
                        device = d
                        self._id_mapping[if_id] = dev['index']
                        del self._tmp_mapping[if_id]
                        break
                if device == None:
                    device = Device(self)
                device.init_netlink(dev['netlink_msg'])
                self._devices[dev['index']] = device
            else:
                self._devices[dev['index']].update_netlink(dev['netlink_msg'])
                devices_to_remove.remove(dev['index'])

            self._devices[dev['index']].clear_ips()
            for addr_msg in dev['ip_addrs']:
                self._devices[dev['index']].update_netlink(addr_msg)
        for i in devices_to_remove:
            if self._devices[i].get_netns() != None:
                continue

            dev_name = self._devices[i].get_name()
            logging.debug("Deleting Device with if_index %d, name %s because "\
                          "it doesn't exist anymore." % (i, dev_name))

            del_msg = {"type": "if_deleted",
                       "if_index": i}
            self._server_handler.send_data_to_ctl(del_msg)
            del self._devices[i]

        self._dl_manager.rescan_ports()
        for device in self._devices.values():
            dl_port = self._dl_manager.get_port(device.get_name())
            device.set_devlink(dl_port)

    def handle_netlink_msgs(self, msgs):
        for msg in msgs:
            self._handle_netlink_msg(msg)

        self._dl_manager.rescan_ports()
        for device in self._devices.values():
            dl_port = self._dl_manager.get_port(device.get_name())
            device.set_devlink(dl_port)

    def _handle_netlink_msg(self, msg):
        if msg['header']['type'] in [RTM_NEWLINK, RTM_NEWADDR, RTM_DELADDR]:
            if msg['index'] in self._devices:
                update_msg = self._devices[msg['index']].update_netlink(msg)
                if update_msg != None:
                    for if_id, if_index in self._id_mapping.iteritems():
                        if if_index == msg['index']:
                            update_msg["if_id"] = if_id
                            break
                    self._server_handler.send_data_to_ctl(update_msg)
            elif msg['header']['type'] == RTM_NEWLINK:
                dev = None
                for if_id, d in self._tmp_mapping.items():
                    d_cfg = d.get_conf_dict()
                    if d_cfg["name"] == msg.get_attr("IFLA_IFNAME"):
                        dev = d
                        self._id_mapping[if_id] = msg['index']
                        del self._tmp_mapping[if_id]
                        break
                if dev == None:
                    dev = Device(self)
                update_msg = dev.init_netlink(msg)
                self._devices[msg['index']] = dev

                if update_msg != None:
                    for if_id, if_index in self._id_mapping.iteritems():
                        if if_index == msg['index']:
                            update_msg["if_id"] = if_id
                            break
                    self._server_handler.send_data_to_ctl(update_msg)

        elif msg['header']['type'] == RTM_DELLINK:
            if msg['index'] in self._devices:
                dev = self._devices[msg['index']]
                if dev.get_netns() == None and dev.get_conf_dict() == None:
                    dev.del_link()
                    del self._devices[msg['index']]

                    del_msg = {"type": "if_deleted",
                               "if_index": msg['index']}
                    self._server_handler.send_data_to_ctl(del_msg)
        else:
            return

    def get_mapped_device(self, if_id):
        if if_id in self._id_mapping:
            if_index = self._id_mapping[if_id]
            return self._devices[if_index]
        elif if_id in self._tmp_mapping:
            return self._tmp_mapping[if_id]
        else:
            return None

    def get_mapped_devices(self):
        ret = {}
        for if_id, if_index in self._id_mapping.iteritems():
            ret[if_id] = self._devices[if_index]
        for if_id in self._tmp_mapping:
            ret[if_id] = self._tmp_mapping[if_id]
        return ret

    def get_device(self, if_index):
        if if_index in self._devices:
            return self._devices[if_index]
        else:
            return None

    def get_devices(self):
        return self._devices.values()

    def get_device_by_hwaddr(self, hwaddr):
        for dev in self._devices.values():
            if dev.get_hwaddr() == hwaddr:
                return dev
        return None

    def get_device_by_params(self, params):
        matched = None
        for dev in self._devices.values():
            matched = dev
            dev_data = dev.get_if_data()
            for key, value in params.iteritems():
                if key not in dev_data or dev_data[key] != value:
                    matched = None
                    break

            if matched:
                break

        return matched

    def deconfigure_all(self):
        for dev in self._devices.itervalues():
            dev.clear_configuration()

    def create_device_from_config(self, if_id, config):
        if config["type"] == "eth":
            raise IfMgrError("Ethernet devices can't be created.")

        config["name"] = self.assign_name(config)

        device = Device(self)
        self._tmp_mapping[if_id] = device

        device.set_configuration(config)
        device.create()

        return config["name"]

    def create_device_pair(self, if_id1, config1, if_id2, config2):
        name1, name2 = self.assign_name(config1)
        config1["name"] = name1
        config2["name"] = name2
        config1["peer_name"] = name2
        config2["peer_name"] = name1

        device1 = Device(self)
        device2 = Device(self)
        self._tmp_mapping[if_id1] = device1
        self._tmp_mapping[if_id2] = device2

        device1.set_configuration(config1)
        device2.set_configuration(config2)
        device1.create()

        device1.set_peer(device2)
        device2.set_peer(device1)
        return name1, name2

    def wait_interface_init(self):
        while len(self._tmp_mapping) > 0:
            rl, wl, xl = select.select([self._nl_socket], [], [], 1)

            if len(rl) == 0:
                continue

            msgs = recv_data(self._nl_socket)["data"]
            self.handle_netlink_msgs(msgs)

    def _is_name_used(self, name):
        self.rescan_devices()
        for device in self._devices.itervalues():
            if name == device.get_name():
                return True
        for device in self._tmp_mapping.itervalues():
            if name == device.get_name():
                return True
        return False

    def assign_name_generic(self, prefix):
        index = 0
        while (self._is_name_used(prefix + str(index))):
            index += 1
        return prefix + str(index)

    def _assign_name_pair(self, prefix):
        index1 = 0
        index2 = 0
        while (self._is_name_used(prefix + str(index1))):
            index1 += 1
        index2 = index1 + 1
        while (self._is_name_used(prefix + str(index2))):
            index2 += 1
        return prefix + str(index1), prefix + str(index2)

    def assign_name(self, config):
        if "name" in config:
            return config["name"]
        dev_type = config["type"]
        if dev_type == "eth":
            if (not "hwaddr" in config or
                "name" in config):
                return
            hwaddr = normalize_hwaddr(config["hwaddr"])
            for dev in self._devices:
                if dev.get_hwaddr() == hwaddr:
                    return dev.get_name()
        elif dev_type == "bond":
            return self.assign_name_generic("t_bond")
        elif dev_type == "bridge" or dev_type == "ovs_bridge":
            return self.assign_name_generic("t_br")
        elif dev_type == "macvlan":
            return self.assign_name_generic("t_macvlan")
        elif dev_type == "team":
            return self.assign_name_generic("t_team")
        elif dev_type == "vlan":
            netdev_name = self.get_mapped_device(config["slaves"][0]).get_name()
            vlan_tci = get_option(config, "vlan_tci")
            prefix = "%s.%s_" % (netdev_name, vlan_tci)
            return self.assign_name_generic(prefix)
        elif dev_type == "veth":
            return self._assign_name_pair("veth")
        elif dev_type == "vti":
            return self.assign_name_generic("vti")
        elif dev_type == "vti6":
            return self.assign_name_generic("t_ip6vti")
        elif dev_type == "vxlan":
            return self.assign_name_generic("vxlan")
        else:
            return self.assign_name_generic("dev")
Esempio n. 27
0
 def reconnect_netlink(self):
     if self._nl_socket != None:
         self._nl_socket.close()
         self._nl_socket = None
     self._nl_socket = IPRSocket()
     self._nl_socket.bind()
class NetLinkListener(Plugin):
    """This plugin reads kernel messages and is able to react to certain network events"""
    states = {"UP": True, "DOWN": False}

    def __init__(self, api, config, *args, **kw):

        super(NetLinkListener, self).__init__(api, config, *args, **kw)
        self.listen = True
        self.socket = IPRSocket()

    def _init(self, *args, **kw):
        # super(NetLinkListener, self).__init__(*args, **kw)
        self.queue = Queue.Queue()
        self.listen = False

        # add handlers here
        self.event_handlers = {
            "RTM_NEWLINK": self.rtm_newlink_handler,
            "RTM_NEWADDR": self.rtm_newaddr_handler,
            "RTM_DELADDR": self.rtm_deladdr_handler
        }

        self.api.register_connectivity_handler(self.connectivity_request)
        self.logger.debug("Connectivity request handler registered")

        self._initialized()

    def _start(self):
        self.api.run_task(self.start_listening)
        self.api.run_task(self.start_queue_handler)

        self._started()

    def _stop(self):
        self.stop_listening()
        self._stopped()

    def start_listening(self):

        if self.socket is None:
            self.socket = IPRSocket()

        self.socket.bind()

        self.logger.info("Starting listener...")
        self.listen = True
        while self.listen:
            r, _, _ = select((self.socket, ), (), (), 0.5)
            if r:
                msg_array = self.socket.get()
                for event_msg in msg_array:
                    try:
                        self.queue.put(event_msg)
                    except Queue.Full:
                        self.logger.warn(
                            "Message queue is full! it has %s elements",
                            self.queue.qsize())

        # stop after listening
        self.socket.close()
        self.logger.debug("Socket closed")

    def start_queue_handler(self):
        """Start reading the queue in a while loop until plugin stops listening to kernel messages"""

        self.logger.debug("Starting queue handler...")
        while self.listen or not self.queue.empty():
            try:
                self.handle_event(self.queue.get(timeout=0.5))
            except Queue.Empty:
                pass
        self.logger.debug("Queue handler finished")

    def stop_listening(self):
        """Stop listening to kernel messages -> shuts down queue handler"""
        self.logger.info("Stopping listener...")
        self.listen = False

    def handle_event(self, event_msg):
        """Find the handler matching the message event and run the handler with the message

        :param event_msg: event message from kernel message (kernel message is usually an array with 1 event message
        """
        event = event_msg["event"]
        # self.logger.debug("new event:\r\n%s", json.dumps(event_msg, indent=2, sort_keys=True))
        # self.logger.debug("new event: %s", event)

        handler = self.event_handlers.get(event)
        if handler is not None:
            self.logger.info("Handling event: %s", event)
            handler(event_msg)
        else:
            # self.logger.debug("No handler for event: %s", event)
            pass

    def rtm_newlink_handler(self, msg):
        """Handler parsing RTM_NEWLINK event messages

        :param msg: RTM_NEWLINK event message
        """
        name = str()
        state = str()
        for attr in msg["attrs"]:
            if attr[0] == "IFLA_IFNAME":
                name = attr[1]
            elif attr[0] == "IFLA_OPERSTATE":
                state = attr[1]

        if name == str():
            self.logger.debug(
                "No IFLA_IFNAME attribute found. Using index to assume interface"
            )
            name = self.get_interface_name_from_index(msg)

        if name != str() and state != str():
            try:
                interface = self.get_interface(name)
                if self.states[state]:
                    self.api.events.interface_created.fire(interface)
                else:
                    self.api.events.interface_removed.fire(interface)
            except InterfaceNotFoundException:
                self.logger.error(
                    "RTM_NEWLINK: Unable to fire event for interface state change: %s is an unknown interface",
                    name)
                self.logger.debug("Debug print of skipped message:\r\n%s",
                                  json.dumps(msg, indent=2, sort_keys=True))
        else:
            self.logger.warn(
                "RTM_NEWLINK: interface not found or unknown state in msg!")
            self.logger.debug("Debug print of skipped message:\r\n%s",
                              json.dumps(msg, indent=2, sort_keys=True))

    def rtm_newaddr_handler(self, msg):
        """Handler parsing RTM_NEWADDR event messages

        :param msg: RTM_NEWADDR event message
        """
        interface = str()
        address = str()
        for attr in msg["attrs"]:
            if attr[0] == "IFA_LABEL":
                interface = attr[1]
            elif attr[0] == "IFA_ADDRESS":
                address = attr[1]

        if interface == str():
            self.logger.debug(
                "No IFA_LABEL attribute found. Using index to assume interface"
            )
            interface = self.get_interface_name_from_index(msg)

        if interface != str() and address != str():
            try:
                self.api.events.address_created.fire(
                    self.get_interface(interface),
                    Address(address=address, family=msg["family"]))
            except InterfaceNotFoundException:
                self.logger.error(
                    "RTM_NEWADDR: Unable to fire address_created event: %s is an unknown interface",
                    interface)
                self.logger.debug("Debug print of skipped message:\r\n%s",
                                  json.dumps(msg, indent=2, sort_keys=True))
        else:
            self.logger.warn(
                "RTM_NEWADDR: interface and/or address not found in msg!")
            self.logger.debug("Debug print of skipped message:\r\n%s",
                              json.dumps(msg, indent=2, sort_keys=True))

    def rtm_deladdr_handler(self, msg):
        """Handler parsing RTM_DELADDR event messages

        :param msg: RTM_DELADDR event message
        """
        interface = str()
        address = str()
        for attr in msg["attrs"]:
            if attr[0] == "IFA_LABEL":
                interface = attr[1]
            elif attr[0] == "IFA_ADDRESS":
                address = attr[1]

        if interface == str():
            self.logger.debug(
                "No IFA_LABEL attribute found. Using index to assume interface"
            )
            interface = self.get_interface_name_from_index(msg)

        if interface != str() and address != str():
            try:
                self.api.events.address_removed.fire(
                    self.get_interface(interface),
                    Address(address=address, family=msg["family"]))
            except InterfaceNotFoundException:
                self.logger.error(
                    "RTM_DELADDR: Unable to fire address_removed event: %s is an unknown interface",
                    interface)
                self.logger.debug("Debug print of skipped message:\r\n%s",
                                  json.dumps(msg, indent=2, sort_keys=True))
        else:
            self.logger.warn(
                "RTM_DELADDR: interface and/or address not found in msg!")
            self.logger.debug("Debug print of skipped message:\r\n%s",
                              json.dumps(msg, indent=2, sort_keys=True))

    def get_addresses(self, interface):
        """Get addresses of a given interface

        :param interface: name of interface
        :return: list of addresses
        """
        n_addresses = netifaces.ifaddresses(interface)
        addresses = []
        for family in n_addresses:
            for addr in n_addresses[family]:
                addresses.append(Address(address=addr["addr"], family=family))

        return addresses

    def get_interface(self, name):
        """Returns an Interface object identified by name

        :param name: name of interface
        :return Interface: interface
        :raise UnknownInterface: if interface was not found
        """
        if name not in netifaces.interfaces():
            raise InterfaceNotFoundException("%s was not found" % name)
        else:
            addresses = self.get_addresses(name)
            hwaddress = [
                addr for addr in addresses if addr[1] == netifaces.AF_LINK
            ][0]
            return Interface(name=name,
                             addresses=addresses,
                             hwaddress=hwaddress)

    def get_interface_name_from_index(self, msg):
        """Parse event message and try to assume interface from index attribute

        :param msg: event message
        :return: interface name corresponding to index value, or empty string if unsuccessful
        """
        interface = str()
        try:
            interface = netifaces.interfaces()[msg["index"] - 1]
            self.logger.debug("Index: %s -> %s", msg["index"], interface)
        except IndexError:
            self.logger.debug("Unable to get interface from index")
        finally:
            return interface

    def connectivity_request(self, rcat=0):
        """Handles connectivity requests"""
        with Promise() as p:
            blacklist = ['lo']
            interfaces = netifaces.interfaces()

            interface = next((x for x in interfaces if (x not in blacklist)),
                             None)

            if interface is None:
                p.reject(
                    InterfaceNotFoundException(
                        "No interfaces found matching request"))
            else:
                p.fulfill((self.get_interface(interface), 0))

        return p
Esempio n. 29
0
class InterfaceManager(object):
    def __init__(self, server_handler):
        self._device_classes = {}

        self._devices = {} #if_index to device

        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self._dl_manager = DevlinkManager()

        self._server_handler = server_handler

    def clear_dev_classes(self):
        self._device_classes = {}

    def add_device_class(self, name, cls):
        if name in self._device_classes:
            raise InterfaceManagerError("Device class name conflict %s" % name)

        self._device_classes[name] = cls
        return cls

    def reconnect_netlink(self):
        if self._nl_socket != None:
            self._nl_socket.close()
            self._nl_socket = None
        self._nl_socket = IPRSocket()
        self._nl_socket.bind(groups=NL_GROUPS)

        self.rescan_devices()

    def get_nl_socket(self):
        return self._nl_socket

    def rescan_devices(self):
        devices_to_remove = self._devices.keys()
        devs = scan_netdevs()
        for dev in devs:
            if dev['index'] not in self._devices:
                device = self._device_classes["Device"](self)
                device._init_netlink(dev['netlink_msg'])
                self._devices[dev['index']] = device

                update_msg = {"type": "dev_created",
                              "dev_data": device._get_if_data()}
                self._server_handler.send_data_to_ctl(update_msg)
            else:
                self._devices[dev['index']]._update_netlink(dev['netlink_msg'])
                try:
                    devices_to_remove.remove(dev['index'])
                except ValueError:
                    # we may have multiple updates for the same device, it's
                    # okay not to find the device in devices_to_remove
                    pass

            self._devices[dev['index']]._clear_ips()
            for addr_msg in dev['ip_addrs']:
                self._devices[dev['index']]._update_netlink(addr_msg)
        for i in devices_to_remove:
            dev_name = self._devices[i].name
            logging.debug("Deleting Device with if_index %d, name %s because "\
                          "it doesn't exist anymore." % (i, dev_name))

            self._devices[i]._deleted = True
            del self._devices[i]

            del_msg = {"type": "dev_deleted",
                       "if_index": i}
            self._server_handler.send_data_to_ctl(del_msg)

        self._dl_manager.rescan_ports()
        for device in self._devices.values():
            dl_port = self._dl_manager.get_port(device.name)
            device._set_devlink(dl_port)

    def handle_netlink_msgs(self, msgs):
        for msg in msgs:
            self._handle_netlink_msg(msg)

        self._dl_manager.rescan_ports()
        for device in self._devices.values():
            dl_port = self._dl_manager.get_port(device.name)
            device._set_devlink(dl_port)

    def _handle_netlink_msg(self, msg):
        if msg['header']['type'] in [RTM_NEWLINK, RTM_NEWADDR, RTM_DELADDR]:
            if msg['index'] in self._devices:
                self._devices[msg['index']]._update_netlink(msg)
            elif msg['header']['type'] == RTM_NEWLINK:
                dev = self._device_classes["Device"](self)
                dev._init_netlink(msg)
                self._devices[msg['index']] = dev

                update_msg = {"type": "dev_created",
                              "dev_data": dev._get_if_data()}
                self._server_handler.send_data_to_ctl(update_msg)
        elif msg['header']['type'] == RTM_DELLINK:
            if msg['index'] in self._devices:
                dev = self._devices[msg['index']]
                dev._deleted = True

                del self._devices[msg['index']]

                del_msg = {"type": "dev_deleted",
                           "if_index": msg['index']}
                self._server_handler.send_data_to_ctl(del_msg)
        else:
            return

    def get_device(self, if_index):
        self.rescan_devices()
        if if_index in self._devices:
            return self._devices[if_index]
        else:
            raise DeviceNotFound()

    def get_devices(self):
        self.rescan_devices()
        return self._devices.values()

    def get_device_by_hwaddr(self, hwaddr):
        self.rescan_devices()
        for dev in self._devices.values():
            if dev.hwaddr == hwaddr:
                return dev
        raise DeviceNotFound()

    def get_device_by_name(self, name):
        self.rescan_devices()
        for dev in self._devices.values():
            if dev.name == name:
                return dev
        raise DeviceNotFound()

    def get_device_by_params(self, params):
        self.rescan_devices()
        matched = None
        for dev in self._devices.values():
            matched = dev
            dev_data = dev.get_if_data()
            for key, value in params.iteritems():
                if key not in dev_data or dev_data[key] != value:
                    matched = None
                    break

            if matched:
                break

        return matched

    def deconfigure_all(self):
        for dev in self._devices.itervalues():
            pass
            # dev.clear_configuration()

    def create_device(self, clsname, args=[], kwargs={}):
        devcls = self._device_classes[clsname]

        device = devcls(self, *args, **kwargs)
        device._create()

        devs = scan_netdevs()
        for dev in devs:
            if dev["name"] == device.name:
                device._init_netlink(dev['netlink_msg'])
                self._devices[dev['index']] = device
                return device

        return None

    def replace_dev(self, if_id, dev):
        del self._devices[if_id]
        self._devices[if_id] = dev

    def _is_name_used(self, name):
        self.rescan_devices()
        for device in self._devices.itervalues():
            if name == device.name:
                return True

        out, _ = exec_cmd("ovs-vsctl --columns=name list Interface",
                          log_outputs=False, die_on_err=False)
        for line in out.split("\n"):
            m = re.match(r'.*: \"(.*)\"', line)
            if m is not None:
                if name == m.group(1):
                    return True
        return False

    def assign_name(self, prefix):
        index = 0
        while (self._is_name_used(prefix + str(index))):
            index += 1
        return prefix + str(index)

    def _assign_name_pair(self, prefix):
        index1 = 0
        index2 = 0
        while (self._is_name_used(prefix + str(index1))):
            index1 += 1
        index2 = index1 + 1
        while (self._is_name_used(prefix + str(index2))):
            index2 += 1
        return prefix + str(index1), prefix + str(index2)