Esempio n. 1
0
  def __createNetns(self, phyIfaceIndex):
    netnsName = self.__getNetnsName()
    (pvdIfaceName, pvdIfaceIndex) = self.__getPvdIfaceParams()
    netns.create(netnsName)
    LOG.debug('network namespace {0} created'.format(netnsName))

    # create a virtual interface where PvD parameters are going to be configured, then move the interface to the new network namespace
    self.ipRoot.link_create(ifname=pvdIfaceName, index=pvdIfaceIndex, kind=self.__PVD_IFACE_TYPE, link=phyIfaceIndex)
    LOG.debug('macvlan {0} created in default network namespace'.format(pvdIfaceName))
    pvdIfaceIndex = self.ipRoot.link_lookup(ifname=pvdIfaceName)
    self.ipRoot.link('set', index=pvdIfaceIndex[0], net_ns_fd=netnsName)
    LOG.debug('macvlan {0} moved to network namespace {1}'.format(pvdIfaceName, netnsName))

    # change the namespace and get new NETLINK handles to operate in new namespace
    netns.setns(netnsName)
    LOG.debug('network namespace switched to {0}'.format(netnsName))
    ip = IPRoute()
    ipdb = IPDB()
    ipdb.register_callback(self.__onIfaceStateChange)
    # disable kernel to auto-configure the interface associated with the PvD, let the pvdman to solely control interface configuration
    acceptRaConfFile = self.__ACCEPT_RA_CONF_FILE.replace(self.__IFACENAME_REPLACE_PATTERN, pvdIfaceName)
    acceptRaConfFile = open(acceptRaConfFile, 'w')
    acceptRaConfFile.write('0')
    LOG.debug('processing of RAs by kernel disabled in {0}'.format(acceptRaConfFile.name))
    # return to a default network namespace to not cause a colision with other modules
    # ip and ipdb handles continue to work in the target network namespace
    netns.setns(self.__NETNS_DEFAULT_NAME)
    LOG.debug('network namespace switched to default')

    # get new index since interface has been moved to a different namespace
    loIfaceIndex = ip.link_lookup(ifname=self.__LOOPBACK_IFACE_NAME)
    if (len(loIfaceIndex) > 0):
      loIfaceIndex = loIfaceIndex[0]
    pvdIfaceIndex = ip.link_lookup(ifname=pvdIfaceName)
    if (len(pvdIfaceIndex) > 0):
      pvdIfaceIndex = pvdIfaceIndex[0]

    # start interfaces
    ip.link_up(loIfaceIndex)
    ip.link_up(pvdIfaceIndex)

    # clear network configuration if exists
    ip.flush_addr(index=pvdIfaceIndex)
    ip.flush_routes(index=pvdIfaceIndex)
    ip.flush_rules(index=pvdIfaceIndex)

    LOG.debug('macvlan {0} in network namespace {1} initialized'.format(pvdIfaceName, netnsName))

    return (netnsName, pvdIfaceName, ip)
Esempio n. 2
0
def main():
    global arpcache, neighborcache, modgatecnt, ipdb, event_callback, bess, ipr
    # for holding unresolved ARP queries
    arpcache = {}
    # for holding list of registered neighbors
    neighborcache = {}
    # for holding gate count per route module
    modgatecnt = {}
    # for interacting with kernel
    ipdb = IPDB()
    ipr = IPRoute()
    # for bess client
    bess = BESS()

    # connect to bessd
    connect_bessd()

    # program current routes
    bootstrap_routes()

    # listen for netlink events
    print('Registering netlink event listener callback...'),
    event_callback = ipdb.register_callback(netlink_event_listener)
    print('Done.')

    signal.signal(signal.SIGHUP, reconfigure)
    signal.signal(signal.SIGINT, cleanup)
    signal.signal(signal.SIGTERM, cleanup)
    signal.pause()
Esempio n. 3
0
    def run(self):
        logging.info('Started LinkNeg...')
        iface = self.get_mopt('iface')
        state = bool_it(self.get_mopt('state'))
        admin_speed = self.get_opt('speed', default=0)
        timeout = self.get_opt('timeout', default=10)

        ip = IPDB()
        self.oper_state = ip.interfaces[iface]['operstate']
        wd = ip.watchdog(ifname=iface)
        cuid = ip.register_callback(self._cb)

        wd.wait(timeout=timeout)
        ip.unregister_callback(cuid)
        ip.release()

        admin_state = 'UP' if state else 'DOWN'
        oper_state = self.oper_state

        if admin_state == oper_state and admin_speed:
            oper_speed = self.get_speed(iface)
        else:
            oper_speed = 0

        res_data = {'admin_state': admin_state, 'oper_state': oper_state}
        if admin_speed:
            res_data['admin_speed'] = "%s Mb/s" % admin_speed
            res_data['oper_speed'] = "%s Mb/s" % oper_speed

        if admin_state == oper_state and admin_speed == oper_speed:
            self.set_pass(res_data)
        else:
            self.set_fail(res_data)
Esempio n. 4
0
    def run(self):
        logging.info('Started LinkNeg...')
        iface = self.get_mopt('iface')
        state = bool_it(self.get_mopt('state'))
        timeout = self.get_opt('timeout', default=10)

        ip = IPDB()
        self.oper_state = ip.interfaces[iface]['operstate']
        wd = ip.watchdog(ifname=iface)
        cuid = ip.register_callback(self._cb)

        wd.wait(timeout=timeout)
        ip.unregister_callback(cuid)
        ip.release()

        admin_state = 'UP' if state else 'DOWN'
        oper_state = self.oper_state
        res_data = {'admin_state': admin_state, 'oper_state': oper_state}

        if admin_state == oper_state:
            self.set_pass(res_data)
        else:
            self.set_fail(res_data)
Esempio n. 5
0
class Pingu(object):
    def __init__(self, configuration=None):
        if configuration is None:
            configuration = {
                "host": "8.8.8.8",
                "gateways_file": None,
                "interfaces": {
                    "enx0c5b8f279a64": {
                        "metric": 100,
                        "count": 10,
                        "max_lost": 5,
                        "max_delay": 100,
                        "reset_script": None,
                        "reset_script_grace_period": 0,
                    },
                    "wlo1": {
                        "metric": 50,
                    }
                },
                "period": 5
            }

        self.log = logging.getLogger("py-pingu")
        self.gateways = {}
        self.ipdb = IPDB()
        self.pyroute = None
        self.event_queue = Queue()
        self.DEFAULT_PROTO = configuration.get("proto", PINGU_PROTO)
        self.gw_lock = Lock()
        self.sockets = {}
        self.route_monitor = Thread(target=self.route_monitor_thread)
        self.next_check_timestamps = {}

        self.loop_event = Event()
        self.exited = Event()
        self.exited.clear()

        self.base_period = configuration.get("period", 5)
        self.configuration = configuration

        self.configure_scapy()
        self.load_gw_from_file()

    def load_gw_from_file(self):
        filename = self.configuration.get("gateways_file", None)
        if filename:
            try:
                if not os.path.isfile(filename):
                    self.log.info("Gateways file not found.")

                with open(filename, "r") as f:
                    self.gateways = json.load(f)
                self.log.info("Loaded %s gateways from the gateways file",
                              len(self.gateways))
            except Exception as ex:
                self.log.error("Error while loading gateways file: %s" %
                               filename,
                               exc_info=True)

    def save_gw_file(self):
        filename = self.configuration.get("gateways_file", None)

        try:
            if not filename:
                return

            with open(filename, "w") as file:
                json.dump(self.gateways, file)

        except Exception as ex:
            self.log.error("Error while writing gateways file: %s" % filename,
                           exc_info=True)

    def configure_scapy(self):
        scapyconf.sniff_promisc = 0

    def get_ip(self, idx, addrs):
        for a in addrs:
            if a["index"] == idx:
                return self.get_attribute(a, "IFA_ADDRESS")

    def set_gw_for_iface(self, iface, gw):
        self.gateways[iface] = gw
        self.save_gw_file()

    def route_monitor_thread(self):

        while not self.exited.is_set():

            with IPRoute() as self.pyroute:
                try:
                    message = self.event_queue.get(timeout=0.5)
                except Empty as ex:
                    continue

                try:
                    links = self.pyroute.get_links()

                    with self.gw_lock:
                        iface = self.get_iface_name(
                            message.get_attr("RTA_OIF"), links)

                        if iface not in self.configuration["interfaces"]:
                            continue

                        if message["dst_len"] == 0 and message["src_len"] == 0 and \
                                message["table"] == 254 and message["proto"] != self.DEFAULT_PROTO:

                            gw = self.get_attribute(message, "RTA_GATEWAY")

                            with IPRoute() as ipr2:
                                kwargs = dict(dst_len=0,
                                              src_len=0,
                                              type=message['type'],
                                              scope=message['scope'],
                                              oif=message.get_attr("RTA_OIF"))

                                #
                                # route scope is == 253 if the destination network is on the local host,
                                # so the fetched gateway will be null
                                #
                                #   eg. ip route add default dev eth0
                                #

                                if gw is not None and message['scope'] != 253:
                                    kwargs["gateway"] = gw

                                ipr2.route("del", **kwargs)
                            self.log.info(
                                "Fetched new default gw for interface %s: %s "
                                % (iface, gw))

                            self.set_gw_for_iface(iface, gw)

                            self.next_check_timestamps[iface] = -1
                            self.loop_event.set()

                except Exception as ex:
                    self.log.exception("Exception in route_monitor_thread")

                finally:
                    self.event_queue.task_done()

    def get_attribute(self, message, name):
        for x in message["attrs"]:
            if x[0] == name:
                return x[1]

    def get_iface_name(self, index, links):
        for l in links:
            if l["index"] == index:
                return self.get_attribute(l, "IFLA_IFNAME")

    def load_route_table(self):
        self.log.info("Loading routing table")
        with IPDB() as ipdb:
            routes = ipdb.routes.filter({"dst": "default", "table": 254})
            with self.gw_lock:
                for r in routes:
                    name = ipdb.interfaces[r["route"].oif].ifname

                    if name not in self.configuration["interfaces"]:
                        continue
                    gw = r["route"].gateway
                    self.log.info("Fetched gateway for %s: %s" % (name, gw))
                    self.set_gw_for_iface(name, gw)

                    with r["route"] as to_del:
                        to_del.remove()
        self.log.info("Loaded %s gateways from routing table" %
                      len(self.gateways))

    def get_gw_mac_address(self, iface):

        for i in range(5):
            arp_req_ip_dst = self.gateways[iface]

            source_hw_addr = get_if_hwaddr(iface)

            arp_req = Ether(dst="ff:ff:ff:ff:ff:ff", src=source_hw_addr) / \
                      ARP(pdst=arp_req_ip_dst, psrc=get_if_addr(iface), hwsrc=source_hw_addr)

            ans, unans = sndrcv(self.sockets[iface],
                                arp_req,
                                timeout=1,
                                verbose=0)

            if len(ans) < 1:
                continue

            return ans[0][1].src

        raise ConnectionError("ARP Resolution Failed for %s (%s)" %
                              (self.gateways[iface], iface))

    def use_l2_packet(self, interface):
        addrfamily, mac = get_if_raw_hwaddr(interface)
        return addrfamily in [ARPHDR_ETHER, ARPHDR_LOOPBACK]

    def check_interface(self, interface):
        try:
            if interface not in self.gateways:
                self.log.debug("No gateway fetched for %s" % interface)
                return False

            if hasattr(self.ipdb.interfaces[interface], "carrier"
                       ) and self.ipdb.interfaces[interface].carrier == 0:
                return False

            count = self.configuration["interfaces"][interface].get(
                "count", DEFAULT_COUNT)
            max_lost = self.configuration["interfaces"][interface].get(
                "max_lost", DEFAULT_MAX_LOST)
            max_delay = self.configuration["interfaces"][interface].get(
                "max_delay", DEFAULT_MAX_DELAY)

            delays = []
            id = random.randint(1, 65535)

            if_addr = get_if_addr(interface)

            if self.use_l2_packet(interface):

                try:
                    mac_address_gw = self.get_gw_mac_address(interface)
                except ConnectionError as ex:
                    self.log.error(ex.args[0])
                    return False

                if_hw_addr = get_if_hwaddr(interface)
                header = Ether(dst=mac_address_gw, src=if_hw_addr)

            else:
                # if using an L3 socket for this interface ->
                # add scapy route to route L3 traffic on the probed interface
                # the route will not be added to the kernel routing table
                scapyconf.route.add(net='%s/32' % self.configuration["host"],
                                    dev=interface)
                header = None

            for i in range(count):

                if self.exited.is_set():
                    return

                if header:
                    packet = header / \
                             IP(src=if_addr, dst=self.configuration["host"]) / \
                             ICMP(id=id, seq=i + 1)
                else:
                    packet = IP(src=if_addr, dst=self.configuration["host"]) / \
                             ICMP(id=id, seq=i + 1)

                ans, unans = sndrcv(self.sockets[interface],
                                    packet,
                                    timeout=1,
                                    verbose=0)

                # self.log.debug("Ping sent")
                if len(ans) > 0:
                    if ans[0][1][ICMP].type == 0 and ans[0][1][ICMP].id == id:
                        rx = ans[0][1]
                        tx = ans[0][0]
                        delta = rx.time - tx.sent_time
                        delays.append(delta)
                    else:
                        self.log.debug(
                            "[%s] Missed ping seq=%s - ICMP Recv Type: %s (must be 0) - Id: %s (must be %s) "
                            % (interface, i + 1, ans[0][1][ICMP].type,
                               ans[0][1][ICMP].id, id))
                else:
                    self.log.debug("[%s] Missed ping id=%s seq=%s  - Timeout" %
                                   (interface, id, i + 1))

                self.exited.wait(timeout=DEFAULT_DELAY / 1000)

            # if using an L3 socket for this interface -> remove scapy route
            if header is None:
                scapyconf.route.delt(net='%s/32' % self.configuration["host"],
                                     dev=interface)

            if len(delays) == 0:
                return False

            ok_count = len(delays)
            delay_avg = sum(delays) / ok_count
            is_ok = (count - ok_count) <= max_lost and (delay_avg *
                                                        1000) < max_delay
            self.log.debug(
                "[%s %s] Ping %s via %s result - lost: %s/%s, delay: %0.0f ms"
                % (interface, "OK" if is_ok else "FAIL",
                   self.configuration["host"], self.gateways[interface],
                   (count - ok_count), count, delay_avg * 1000))
            return is_ok

        except PermissionError as pe:
            raise pe

        except Exception as ex:
            self.log.exception("check_interface error: ")
            return False

    def metric(self, interface):
        return self.configuration["interfaces"][interface]

    def activate_interface(self, name):
        if name not in self.gateways:
            self.log.warning("Missing default gw for ", name)

        with IPDB() as ipdb:
            existing_route = None
            try:
                existing_route = ipdb.routes[{
                    'oif': ipdb.interfaces[name].index,
                    'proto': self.DEFAULT_PROTO,
                    'dst': 'default'
                }]
            except KeyError as ex:
                pass

            if existing_route is not None:
                if existing_route["priority"] == self.configuration["interfaces"][name]["metric"] and \
                        existing_route["gateway"] == self.gateways[name]:
                    return  # esco se gia' esiste

                # altrimenti cancello
                if len(existing_route) > 0:
                    ipdb.routes.remove({
                        'oif': ipdb.interfaces[name].index,
                        'proto': self.DEFAULT_PROTO,
                        'dst': 'default'
                    }).commit()
            metric = self.configuration["interfaces"][name]["metric"]
            ipdb.routes.add({
                'oif': ipdb.interfaces[name].index,
                'dst': 'default',
                'proto': self.DEFAULT_PROTO,
                'gateway': self.gateways[name],
                "priority": metric
            }).commit()
            self.log.info("[INSTALLED] %s via %s (metric %s)" %
                          (name, self.gateways[name], metric))

    def deactivate_interface(self, name):

        with IPDB() as ipdb:
            try:
                ipdb.routes.remove({
                    'oif': ipdb.interfaces[name].index,
                    'proto': self.DEFAULT_PROTO,
                    'dst': 'default'
                })

                ipdb.commit()

                self.log.info("[REMOVED] %s via %s" %
                              (name, self.gateways.get(name, "---")))
            except KeyError as ex:
                pass

    def callback(self, ipdb, message, action):
        if "ROUTE" in message["event"]:
            self.log.debug("Event detected: %s " % message["event"])

            if message["event"] == "RTM_NEWROUTE":
                self.event_queue.put(message)

    def print_fetched_gws(self, a, b):
        with self.gw_lock:
            self.log.info("Fetched gateways:\n %s\n " %
                          json.dumps(self.gateways))

    def get_interface_next_check(self, interface):
        return time.time() + self.configuration["interfaces"][interface].get(
            "period", self.base_period)

    def load_next_checks(self):
        for i in self.configuration["interfaces"].keys():
            self.next_check_timestamps[i] = -1

    def run_on_interface(self, interface):
        try:

            if self.use_l2_packet(interface):
                self.sockets[interface] = L2Socket(
                    iface=interface,
                    filter="arp or (icmp and src host %s)" %
                    self.configuration["host"])
            else:
                self.sockets[interface] = L3PacketSocket(iface=interface)

        except Exception as ex:
            if "permission" in str(ex):
                self.log.exception("Error while opening filter: ")
            # if "tcpdump" in str(ex).lower():
            #     self.log.error("py-pingu requires tcpdump executable, please install tcpdump.")
            #     exit(1)

            return

        with self.gw_lock:
            if self.check_interface(interface):
                self.activate_interface(interface)
            else:
                try:
                    self.run_reset_script(interface)
                except Exception as ex:
                    self.log.exception("Error while executing reset script - ",
                                       exc_info=True)

                self.deactivate_interface(interface)

    def run_reset_script(self, interface):
        script = self.configuration["interfaces"][interface].get(
            "reset_script", None)
        if script is None:
            return
        grace_period = self.configuration["interfaces"][interface].get(
            "reset_script_grace_period", 600)
        last = self.configuration["interfaces"][interface].get(
            "last_reset_script_run", 0)
        now = time.time()

        if now - last < grace_period:
            return

        if not os.path.isfile(script):
            self.log.warning("Unable to find reset script %s for %s" %
                             (script, interface))
            return

        self.log.info("Executing reset script for %s" % interface)
        p = subprocess.Popen(script,
                             shell=True,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             close_fds=True)
        # allow external program to work
        p.wait()

        self.configuration["interfaces"][interface][
            "last_reset_script_run"] = now

    def fetch_next_interface(self):
        v = min(self.next_check_timestamps, key=self.next_check_timestamps.get)
        now = time.time()
        expiration = self.next_check_timestamps[v]
        delta = expiration - now
        return v, delta if delta > 0 else 0

    def on_sigint(self, a, b):
        self.exited.set()
        self.loop_event.set()

    def run(self):
        self.ipdb.register_callback(self.callback, )

        self.log.info("Welcome to py-pingu! ")
        self.log.info(json.dumps(self.configuration, indent=2))
        self.route_monitor.start()

        signal.signal(signal.SIGINT, self.on_sigint)
        signal.signal(signal.SIGUSR1, self.print_fetched_gws)

        self.load_route_table()

        self.load_next_checks()

        while not self.exited.is_set():

            name, period = self.fetch_next_interface()

            if period > 0:
                if self.loop_event.wait(timeout=period):
                    self.loop_event.clear()
                    continue

            try:
                self.log.debug("Probing %s" % name)
                ifaces = get_if_list()

                if name not in ifaces:
                    self.log.debug("Interface %s does not exists." % name)
                    continue

                self.run_on_interface(name)

            except Exception as ex:
                self.log.exception("Error in main loop:", exc_info=True)
            finally:
                self.next_check_timestamps[
                    name] = self.get_interface_next_check(name)

        self.log.info("Exit signal received")
Esempio n. 6
0
#      pp.pprint(netlink_message)


def new_dev_callback(ipdb, netlink_message, action):
    if action == 'RTM_NEWLINK':
        #pp.pprint(netlink_message)
        nldict = dict(netlink_message)
        print "handling call back"
        ifindex = nldict['index']
        ifnametup = nldict['attrs'][0]
        ifname = ifnametup[1]
        nsPath = check_output([
            "sudo", "docker", "inspect", "--format",
            " '{{.NetworkSettings.SandboxKey}}'", ifname[:-1]
        ])
        nsPath = nsPath.rstrip('\r\n')[1:]
        nsPath = json.dumps(str(nsPath)).replace("'", "")
        nsPath = nsPath.replace('"', "")
        out = check_output(["sudo", "ls", "-Li", nsPath])
        inum = out.split(" ")[0]
        print inum
        ifInum[ct.c_uint(ifindex)] = ct.c_uint64(int(inum))
        print "ifindex", ifindex, ifInum[ct.c_uint(ifindex)]


#addr_callback = ipdb.register_callback(new_address_callback)
dev_callback = ipdb.register_callback(new_dev_callback)
input()
#ipdb.unregister_callback(addr_callback)
ipdb.unregister_callback(dev_callback)
Esempio n. 7
0
            ipdb.interfaces.br0.commit()
        except Exception:
            pass

# create IPDB instance
ip = IPDB()
# create watchdogs
wd0 = ip.watchdog(ifname='br0')
wd1 = ip.watchdog(ifname='bala_port0')
wd2 = ip.watchdog(ifname='bala_port1')
# create bridge
ip.create(kind='bridge', ifname='br0').commit()
# wait the bridge to be created
wd0.wait()
# register callback
ip.register_callback(cb)
# create ports
ip.create(kind='dummy', ifname='bala_port0').commit()
ip.create(kind='dummy', ifname='bala_port1').commit()
# sleep for interfaces
wd1.wait()
wd2.wait()

ip.unregister_callback(cb)

# cleanup
for i in ('bala_port0', 'bala_port1', 'br0'):
    try:
        ip.interfaces[i].remove().commit()
    except:
        pass
Esempio n. 8
0
        except Exception:
            pass


# create IPDB instance
ip = IPDB()
# create watchdogs
wd0 = ip.watchdog(ifname='br0')
wd1 = ip.watchdog(ifname='bala_port0')
wd2 = ip.watchdog(ifname='bala_port1')
# create bridge
ip.create(kind='bridge', ifname='br0').commit()
# wait the bridge to be created
wd0.wait()
# register callback
ip.register_callback(cb)
# create ports
ip.create(kind='dummy', ifname='bala_port0').commit()
ip.create(kind='dummy', ifname='bala_port1').commit()
# sleep for interfaces
wd1.wait()
wd2.wait()

ip.unregister_callback(cb)

# cleanup
for i in ('bala_port0', 'bala_port1', 'br0'):
    try:
        ip.interfaces[i].remove().commit()
    except:
        pass
Esempio n. 9
0
from pyroute2.common import uifname

p0 = uifname()


###
#
# "Pre" callbacks are executed before the message
# gets processed by IPDB, and in synchronous manner.
# Normally, you will not need these callbacks, but
# they can be useful to perform some hacks
#
def cb(ipdb, msg, action):
    if action == 'RTM_NEWLINK':
        msg['flags'] = 1234


# create IPDB instance
ip = IPDB()
# register "pre" callback
ip.register_callback(cb, mode='pre')
# create an interface
ip.create(kind='dummy', ifname=p0).commit()
# assert flags
assert ip.interfaces[p0].flags == 1234
# cleanup
ip.interfaces[p0].remove()
ip.interfaces[p0].commit()
# release Netlink socket
ip.release()
Esempio n. 10
0
class DevTracker(object):
    def __init__(self, devlist, logger=None):
        self.devlist = devlist
        self.queue = queue.Queue()
        self.ipdb = IPDB()
        self.logger = logger or default_logger

    def _get_current(self):

        for dev in self.devlist:

            if not dev in self.ipdb.interfaces:
                continue

            devinfo = self.ipdb.by_name[dev]

            for addr, preflen in devinfo["ipaddr"]:
                if whichipversion(addr) == 4:
                    addr = "{}/{}".format(addr, preflen)
                    prefix = ipaddress.ip_interface(addr).network
                    msg = {
                        "action": "RTM_NEWADDR",
                        "device": dev,
                        "address": prefix,
                    }
                    self.queue.put(msg)

    def start(self):

        self.logger.debug("start to track devices: %s", " ".join(self.devlist))

        self._get_current()

        def ipdb_callback(ipdb, msg, action):

            if not action in ("RTM_NEWADDR", "RTM_DELADDR"):
                return

            if msg["family"] != 2:
                # XXX: IPv4 only :(
                return

            tracked_dev = None
            tracked_dev_addr = None
            for attr in msg["attrs"]:
                if attr[0] == "IFA_LABEL" and attr[1] in self.devlist:
                    tracked_dev = attr[1]
                elif attr[0] == "IFA_ADDRESS":
                    tracked_dev_addr = attr[1]

            if not tracked_dev or not tracked_dev_addr:
                return

            addr = "{}/{}".format(tracked_dev_addr, msg["prefixlen"])
            prefix = ipaddress.ip_interface(addr).network

            msg = {
                "action": action,
                "device": tracked_dev,
                "address": prefix,
            }

            try:
                self.logger.debug("device addr change: %s", str(msg))
                self.queue.put(msg)
            except queue.Full:
                self.logger.error("devtracker queue full for msg %s", str(msg))

        self.cbid = self.ipdb.register_callback(ipdb_callback)

    def stop(self):
        self.ipdb.unregister_callback(self.cbid)

    def queued(self):
        return (not self.queue.empty())

    def pop(self):
        try:
            return self.queue.get(block=False)
        except queue.Empty:
            return None
Esempio n. 11
0
class PvdManager:
  __NETNS_PREFIX = 'mifpvd-'
  __netnsIdGenerator = 0;
  __PVD_IFACE_BASENAME = 'mifpvd'
  __PVD_IFACE_TYPE = 'macvlan'

  __NETNSDIRNAME_REPLACE_PATTERN = '%NETNS_NAME%'
  __DNS_CONF_FILE = '/etc/netns/' + __NETNSDIRNAME_REPLACE_PATTERN + '/resolv.conf'

  __IFACENAME_REPLACE_PATTERN = '%IFACE_NAME%'
  __ACCEPT_RA_CONF_FILE = '/proc/sys/net/ipv6/conf/' + __IFACENAME_REPLACE_PATTERN + '/accept_ra'

  __LOOPBACK_IFACE_NAME = 'lo'

  __NETNS_DEFAULT_PROC = '/proc/1/ns/net'
  __NETNS_DEFAULT_NAME = 'mifpvd-default'

  __DEFAULT_ROUTE_ADDRESS = '::'
  __LINK_LOCAL_PREFIX = 'fe80::'
  __LINK_LOCAL_PREFIX_LENGTH = 64


  '''
  PRIVATE METHODS
  '''

  def __init__(self):
    LOG.debug('PvdManager initialization started')
    self.pvds = {}
    self.ipRoot = IPRoute()
    self.ipdbRoot = IPDB()
    self.ipdbRoot.register_callback(self.__onIfaceStateChange)
    # create a symbolic link to be able to return to a default network namespace
    self.__createDefaultNetnsSymlink()
    # register a cleanup handler to remove configured PvDs and associated components at exit
    atexit.register(self.cleanup)

    self.operation_in_progress = False # debugging...
    self.pvdserver = None

    LOG.debug('cleanup handler initialized')
    LOG.debug('PvdManager initialization finished')


  def __onIfaceStateChange(self, ipdb, msg, action):
    pass
    '''
    if (ipdb == self.ipdbRoot):
      netnsName = 'root'
    else:
      netnsName = 'netns'

    if (action == 'RTM_NEWLINK' or action == 'RTM_DELLINK'):
      for attr in msg['attrs']:
        if attr[0] == 'IFLA_IFNAME':
          ifaceName = attr[1]
        elif attr[0] == 'IFLA_OPERSTATE':
          ifaceState = attr[1]
      if (action == 'RTM_NEWLINK'):
        LOG.debug(netnsName + ': ' + ifaceName + ' ADDED, state: ' + ifaceState)
      elif (action == 'RTM_DELLINK'):
        LOG.debug(netnsName + ': ' + ifaceName + ' DELETED, state: ' + ifaceState)
    '''


  def __getNetnsName(self):
    netnsName = None
    while (not netnsName or netnsName in netns.listnetns()):
      self.__netnsIdGenerator += 1;
      netnsName = self.__NETNS_PREFIX + str(self.__netnsIdGenerator)
    return netnsName


  def __getPvdIfaceParams(self):
    # use interface base name if available, add suffix otherwise
    pvdIfaceName = self.__PVD_IFACE_BASENAME
    pvdIfaceSuffix = 0
    while (len(self.ipRoot.link_lookup(ifname=pvdIfaceName)) > 0):
      pvdIfaceSuffix += 1;
      pvdIfaceName = self.__PVD_IFACE_BASENAME + '-' + str(pvdIfaceSuffix)
    # find the largest index among the existing interfaces, use the next one
    pvdIfaceIndex = 1
    existingIfaceIndices = [iface['index'] for iface in self.ipRoot.get_links()]
    if (len(existingIfaceIndices) > 0):
      existingIfaceIndices.sort()
      pvdIfaceIndex = existingIfaceIndices[-1] + 1
    return (pvdIfaceName, pvdIfaceIndex)


  def __getDnsConfPath(self, netnsName):
    dnsConfFile = self.__DNS_CONF_FILE.replace(self.__NETNSDIRNAME_REPLACE_PATTERN, netnsName)
    dnsConfDir = dnsConfFile[0:dnsConfFile.rfind('/')]
    return (dnsConfDir, dnsConfFile)


  def __getDefaultNetnsSymlinkPath(self):
    netnsDir = netns.NETNS_RUN_DIR
    if (not netnsDir.endswith('/')):
      netnsDir += '/'
    return netnsDir + self.__NETNS_DEFAULT_NAME


  def __createDefaultNetnsSymlink(self):
    symlinkPath = self.__getDefaultNetnsSymlinkPath()
    if (not os.path.exists(os.path.dirname(symlinkPath))):
      os.makedirs(os.path.dirname(symlinkPath))
    if (os.path.exists(symlinkPath) and os.path.islink(symlinkPath)):
      os.unlink(symlinkPath)
    os.symlink(self.__NETNS_DEFAULT_PROC, symlinkPath)
    LOG.debug('symlink {0}->{1} created'.format(symlinkPath, os.readlink(symlinkPath)))


  def __removeDefaultNetnsSymlink(self):
    symlinkPath = self.__getDefaultNetnsSymlinkPath()
    if (os.path.exists(symlinkPath) and os.path.islink(symlinkPath)):
      # need to read the link target for logging prior to delete a link
      symlinkTarget = os.readlink(symlinkPath)
      os.unlink(symlinkPath)
    LOG.debug('symlink {0}->{1} removed'.format(symlinkPath, symlinkTarget))


  def __createNetns(self, phyIfaceIndex):
    netnsName = self.__getNetnsName()
    (pvdIfaceName, pvdIfaceIndex) = self.__getPvdIfaceParams()
    netns.create(netnsName)
    LOG.debug('network namespace {0} created'.format(netnsName))

    # create a virtual interface where PvD parameters are going to be configured, then move the interface to the new network namespace
    self.ipRoot.link_create(ifname=pvdIfaceName, index=pvdIfaceIndex, kind=self.__PVD_IFACE_TYPE, link=phyIfaceIndex)
    LOG.debug('macvlan {0} created in default network namespace'.format(pvdIfaceName))
    pvdIfaceIndex = self.ipRoot.link_lookup(ifname=pvdIfaceName)
    self.ipRoot.link('set', index=pvdIfaceIndex[0], net_ns_fd=netnsName)
    LOG.debug('macvlan {0} moved to network namespace {1}'.format(pvdIfaceName, netnsName))

    # change the namespace and get new NETLINK handles to operate in new namespace
    netns.setns(netnsName)
    LOG.debug('network namespace switched to {0}'.format(netnsName))
    ip = IPRoute()
    ipdb = IPDB()
    ipdb.register_callback(self.__onIfaceStateChange)
    # disable kernel to auto-configure the interface associated with the PvD, let the pvdman to solely control interface configuration
    acceptRaConfFile = self.__ACCEPT_RA_CONF_FILE.replace(self.__IFACENAME_REPLACE_PATTERN, pvdIfaceName)
    acceptRaConfFile = open(acceptRaConfFile, 'w')
    acceptRaConfFile.write('0')
    LOG.debug('processing of RAs by kernel disabled in {0}'.format(acceptRaConfFile.name))
    # return to a default network namespace to not cause a colision with other modules
    # ip and ipdb handles continue to work in the target network namespace
    netns.setns(self.__NETNS_DEFAULT_NAME)
    LOG.debug('network namespace switched to default')

    # get new index since interface has been moved to a different namespace
    loIfaceIndex = ip.link_lookup(ifname=self.__LOOPBACK_IFACE_NAME)
    if (len(loIfaceIndex) > 0):
      loIfaceIndex = loIfaceIndex[0]
    pvdIfaceIndex = ip.link_lookup(ifname=pvdIfaceName)
    if (len(pvdIfaceIndex) > 0):
      pvdIfaceIndex = pvdIfaceIndex[0]

    # start interfaces
    ip.link_up(loIfaceIndex)
    ip.link_up(pvdIfaceIndex)

    # clear network configuration if exists
    ip.flush_addr(index=pvdIfaceIndex)
    ip.flush_routes(index=pvdIfaceIndex)
    ip.flush_rules(index=pvdIfaceIndex)

    LOG.debug('macvlan {0} in network namespace {1} initialized'.format(pvdIfaceName, netnsName))

    return (netnsName, pvdIfaceName, ip)


  def __configureNetwork(self, ifaceName, pvdInfo, ip):
    if (pvdInfo):
      ifaceIndex = ip.link_lookup(ifname=ifaceName)
      if (len(ifaceIndex) > 0):
        ifaceIndex = ifaceIndex[0]

      # clear network configuration if exists
      ip.flush_addr(index=ifaceIndex)
      ip.flush_routes(index=ifaceIndex)
      ip.flush_rules(index=ifaceIndex)

      # set new network configuration
      if (pvdInfo.mtu):
        ip.link('set', index=ifaceIndex, mtu=pvdInfo.mtu.mtu)
        LOG.debug('MTU {0} on {1} configured'.format(pvdInfo.mtu.mtu, ifaceName))

      # get interface MAC address to derive the IPv6 address from
      iface = ip.get_links(ifaceIndex)[0]
      mac = iface.get_attr('IFLA_ADDRESS')

      # add link-local IPv6 address
      ipAddress = str(netaddr.EUI(mac).ipv6(netaddr.IPAddress(self.__LINK_LOCAL_PREFIX)))
      ip.addr('add', index=ifaceIndex, address=ipAddress, prefixlen=self.__LINK_LOCAL_PREFIX_LENGTH, rtproto='RTPROT_RA', family=socket.AF_INET6)
      LOG.debug('link-local IP address {0}/{1} on {2} configured'.format(ipAddress, self.__LINK_LOCAL_PREFIX_LENGTH, ifaceName))

      # add PvD-related IPv6 addresses
      if (pvdInfo.prefixes):
        for prefix in pvdInfo.prefixes:
          # TODO: PrefixInfo should contain IPAddress instead of str for prefix
          ipAddress = str(netaddr.EUI(mac).ipv6(netaddr.IPAddress(prefix.prefix)))
          ip.addr('add', index=ifaceIndex, address=ipAddress, prefixlen=prefix.prefixLength, rtproto='RTPROT_RA', family=socket.AF_INET6)
          LOG.debug('IP address {0}/{1} on {2} configured'.format(ipAddress, prefix.prefixLength, ifaceName))

      # add PvD-related routes
      if (pvdInfo.routes):
        for route in pvdInfo.routes:
          # some routes may be added during interface prefix configuration, skip them if already there
          try:
            # TODO: RouteInfo should contain IPAddress instead of str for prefix
            # TODO: PvdInfo should contain IPAddress instead of str for routerAddress
            ip.route('add', dst=route.prefix, mask=route.prefixLength, gateway=pvdInfo.routerAddress, oif=ifaceIndex, rtproto='RTPROT_RA', family=socket.AF_INET6)
            LOG.debug('route to {0}/{1} via {2} on {3} configured'.format(route.prefix, route.prefixLength, pvdInfo.routerAddress, ifaceName))
          except:
            LOG.warning('cannot configure route to {0}/{1} via {2} on {3}'.format(route.prefix, route.prefixLength, pvdInfo.routerAddress, ifaceName))

      # add link-local route
      try:
        ip.route('add', dst=self.__LINK_LOCAL_PREFIX, mask=self.__LINK_LOCAL_PREFIX_LENGTH, oif=ifaceIndex, rtproto='RTPROT_RA', family=socket.AF_INET6)
        LOG.debug('link-local route to {0}/{1} on {2} configured'.format(self.__LINK_LOCAL_PREFIX, self.__LINK_LOCAL_PREFIX_LENGTH, ifaceName))
      except:
        LOG.warning('cannot configure link-local route to {0}/{1} on {2}'.format(self.__LINK_LOCAL_PREFIX, self.__LINK_LOCAL_PREFIX_LENGTH, ifaceName))

      # add default route
      try:
        ip.route('add', dst=self.__DEFAULT_ROUTE_ADDRESS, gateway=pvdInfo.routerAddress, oif=ifaceIndex, rtproto='RTPROT_RA', family=socket.AF_INET6)
        LOG.debug('default route via {0} on {1} configured'.format(pvdInfo.routerAddress, ifaceName))
      except:
        LOG.warning('cannot configure default route via {0} on {1}'.format(pvdInfo.routerAddress, ifaceName))


  def __configureDns(self, pvdInfo, netnsName):
    # configure DNS data in resolv.conf
    if (pvdInfo):
      # delete existing resolv.conf file for a given namespace
      (dnsConfDir, dnsConfFile) = self.__getDnsConfPath(netnsName)
      shutil.rmtree(dnsConfDir, True)

      if (pvdInfo.rdnsses or pvdInfo.dnssls):
        # create new resolv.conf file for a given namespace
        os.makedirs(dnsConfDir)
        dnsConfFile = open(dnsConfFile, 'w')
        dnsConfFile.write('# Autogenerated by pvdman\n')
        dnsConfFile.write('# PvD ID: ' + pvdInfo.pvdId + '\n\n')

        if (pvdInfo.rdnsses):
          for rdnss in pvdInfo.rdnsses:
            if (rdnss.addresses):
              dnsConfFile.write('\n'.join('{} {}'.format('nameserver', address) for address in rdnss.addresses) + '\n\n')
          LOG.debug('RDNSS in {0} configured'.format(dnsConfFile.name))

        if (pvdInfo.dnssls):
          for dnssl in pvdInfo.dnssls:
            if (dnssl.domainNames):
              dnsConfFile.write('search ' + ' '.join('{}'.format(domainName) for domainName in dnssl.domainNames))
          LOG.debug('DNSSL in {0} configured'.format(dnsConfFile.name))


  def __createPvd(self, phyIfaceName, pvdInfo):
    phyIfaceIndex = self.ipRoot.link_lookup(ifname=phyIfaceName)
    if (len(phyIfaceIndex) > 0):
      phyIfaceIndex = phyIfaceIndex[0]
      if (self.pvds.get((phyIfaceName, pvdInfo.pvdId)) is None):
        # create a new network namespace to isolate the PvD configuration
        (netnsName, pvdIfaceName, ip) = self.__createNetns(phyIfaceIndex)
        # create a record to track the configured PvDs
        pvd = Pvd(pvdInfo.pvdId, pvdInfo, phyIfaceName, pvdIfaceName, netnsName)
        # configure the network namespace with the data received in RA message
        self.__configureNetwork(pvdIfaceName, pvdInfo, ip)
        self.__configureDns(pvdInfo, netnsName)
        # if PvD configuration completed successfully, add PvD record to the PvD manager's log
        self.pvds[(phyIfaceName, pvd.pvdId)] = pvd
        LOG.info('PvD {0} received through {1} CONFIGURED in network namespace {2} on macvlan {3}, type {4}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.netnsName, pvd.pvdIfaceName, pvd.pvdInfo.pvdType))
        self.pvdserver.stateChanged ("new_pvd", pvdInfo.pvdId)
      else:
        raise Exception('PvD duplicate error: PvD {0} is already configured on {1}'.format(pvdInfo.pvdId, phyIfaceName))
    else:
      raise Exception('Interface {0} does not exist'.format(phyIfaceName))

  def __updatePvd(self, phyIfaceName, pvdInfo):
    pvd = self.pvds.get((phyIfaceName, pvdInfo.pvdId))
    if (pvd):
      if (pvd.pvdInfo == pvdInfo):
        # if PvD parameters did not change, just update the timestamp in the PvD manager's log
        pvd.updateTimestamp()
        LOG.info('PvD {0} received through {1} UNCHANGED, timestamp UPDATED, type {2}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.pvdInfo.pvdType))
      else:
        # if any of the PvD parameters has changed, reconfigure the PvD
        netns.setns(pvd.netnsName)
        ip = IPRoute()
        # return to a default network namespace to not cause a colision with other modules
        # ip handle continues to work in the target network namespace
        netns.setns(self.__NETNS_DEFAULT_NAME)
        self.__configureNetwork(pvd.pvdIfaceName, pvdInfo, ip)
        self.__configureDns(pvdInfo, pvd.netnsName)
        # update the PvD record in the PvD manager's log
        pvd.pvdInfo = pvdInfo
        pvd.updateTimestamp()
        LOG.info('PvD {0} received through {1} RECONFIGURED in network namespace {2} on macvlan {3}, type {4}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.netnsName, pvd.pvdIfaceName, pvd.pvdInfo.pvdType))
        self.pvdserver.stateChanged ("updated", pvdInfo.pvdId)
    else:
      raise Exception('There is no PvD {0} configured on {1}'.format(pvdInfo.pvdId, phyIfaceName))


  def __removePvd(self, phyIfaceName, pvdId):
    pvd = self.pvds.get((phyIfaceName, pvdId))
    if (pvd):
      # remove the network namespace associated with the PvD (this in turn removes the PvD network configuration as well)
      if (pvd.netnsName in netns.listnetns()):
        netns.remove(pvd.netnsName)
      # remove the directory containing PvD-related DNS information
      (dnsConfDir, dnsConfFile) = self.__getDnsConfPath(pvd.netnsName)
      if (os.path.exists(dnsConfDir)):
        shutil.rmtree(dnsConfDir, True)
      # remove the PvD record from the PvD manager's log
      del self.pvds[(phyIfaceName, pvdId)]
      LOG.info('PvD {0} received through {1} REMOVED, network namespace {2} deleted, DNS directory {3} deleted, type {4}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.netnsName, dnsConfDir, pvd.pvdInfo.pvdType))
      self.pvdserver.stateChanged ("deleted", pvdId)

    else:
      raise Exception('There is no PvD {0} configured on {1}'.format(pvdInfo.pvdId, phyIfaceName))


  '''
  PUBLIC METHODS
  '''

  def setPvd(self, phyIfaceName, pvdInfo):
    '''
    Configures the PvD parameters associated with a given physical network interface.
    This function is idempotent and can be safely invoked multiple times with the same or different parameters.
    If no PvD with a given ID is configured on a given interface, new PvD will be created.
    If PvD with a given ID is already configured on the interface, PvD parameters will be reconfigured if necessary.
    '''
    self.operation_in_progress = True  # debugging...

    if (self.pvds.get((phyIfaceName, pvdInfo.pvdId)) is None):
      self.__createPvd(phyIfaceName, pvdInfo)
    else:
      self.__updatePvd(phyIfaceName, pvdInfo)

    self.operation_in_progress = False # debugging...

  def removePvd(self, phyIfaceName, pvdId):
    self.operation_in_progress = True  # debugging...
    self.__removePvd(phyIfaceName, pvdId)
    self.operation_in_progress = False # debugging...


  def listPvds(self):
    pvdData = []
    for pvdKey, pvd in self.pvds.items():
      pvdData.append((pvd.phyIfaceName, pvd.pvdId))
    return pvdData


  def getPvds(self):
    pvdData = []
    for pvdKey, pvd in self.pvds.items():
      pvdData.append((pvd.pvdId, pvd.netnsName, pvd.phyIfaceName, pvd.pvdInfo.pvd_properties))
    return pvdData


  def getPvdInfo(self, phyIfaceName, pvdId):
    return self.pvds.get((phyIfaceName, pvdId))

  def TEST_createPvd ( self, phyIfaceName="tunnelX", pvdId="317a088c-ab67-43a3-bcf0-23c26f623a2d" ):
    netnsName = "VPNTEST"
    pvdIfaceName = netnsName
    pvdInfo = PvdInfo ( pvdId, PvdType.EXPLICIT, None, None, None, None, None, None, None, None,
		{"type":["voice", "cellular"], "bandwidth":"1 Mbps", "pricing":"0,01 $/MB", "id":pvdId } )
    pvd = Pvd ( pvdInfo.pvdId, pvdInfo, phyIfaceName, pvdIfaceName, netnsName )
    self.pvds[(phyIfaceName, pvd.pvdId)] = pvd
    LOG.info('PvD {0} received through {1} CONFIGURED in network namespace {2} on macvlan {3}, type {4}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.netnsName, pvd.pvdIfaceName, pvd.pvdInfo.pvdType))


  def cleanup(self):
    LOG.debug('PvdManager cleanup started')
    # create a deep copy of dictionary keys before deletion because Python cannot delete dictionary items while iterating over them
    pvdKeys = [key for key in self.pvds.keys()]
    for (phyIfaceName, pvdId) in pvdKeys:
      self.__removePvd(phyIfaceName, pvdId)
    # remove a symbolic link to a default network namespace
    self.__removeDefaultNetnsSymlink()
    LOG.debug('PvdManager cleanup finished')
Esempio n. 12
0
class NetlinkClient(object):
    def __init__(self):
        self.neighbours = []
        self.unresolvedneighbours = []
        self.ip = IPDB(ignore_rtables=[254])
        self.ip_uuid = self.ip.register_callback(self.callback)
        self.server = eventlet.listen(('127.0.0.1', 55652))
        self.socket = None
        self.serve = True
        self.pool = eventlet.GreenPool()
        self.not_connect = True

    def callback(self, ipdb, msg, action):
        if action is 'RTM_NEWNEIGH':
            self.add_neighbour(msg)
        if action is 'RTM_DELNEIGH':
            self.remove_neighbour(msg)
        if action is 'RTM_NEWLINK':
            self.notify(['ifaceTable', self.ifaceTable(ipdb)])
        if action is 'RTM_DELLINK':
            self.notify(['ifaceTable', self.ifaceTable(ipdb)])
        if action is 'RTM_NEWADDR':
            log.info("RTM_NEWADDR happened at %s", str(datetime.now()))
            self.notify(['ifaceTable', self.ifaceTable(ipdb)])
        if action is 'RTM_DELADDR':
            log.info("RTM_DELADDR happened at %s", str(datetime.now()))
            self.notify(['ifaceTable', self.ifaceTable(ipdb)])

    def add_neighbour(self, msg):
        attributes = msg['attrs']
        ip_addr = attributes[0][1]
        if attributes[1][0] is 'NDA_LLADDR':
            mac_addr = attributes[1][1]
            iface_index = msg['ifindex']
            host = {'ipaddr': ip_addr, 'mac_addr': mac_addr,
                    'ifindex': iface_index}
            if host not in self.neighbours:
                self.notify(['add_neigh', host])
                self.neighbours.append(host)
                if ip_addr in self.unresolvedneighbours:
                    self.unresolvedneighbours = list(filter(lambda x: x !=
                                                     ip_addr,
                                                     self.unresolvedneighbours)
                                                     )
        else:
            if ip_addr not in self.unresolvedneighbours:
                self.unresolvedneighbours.append(ip_addr)
                self.notify(['unresolved', self.unresolvedneighbours])

    def remove_neighbour(self, msg):
        attributes = msg['attrs']
        ip_addr = attributes[0][1]
        if attributes[1][0] is 'NDA_LLADDR':
            mac_addr = attributes[1][1]
            iface_index = msg['ifindex']
            host = {'ipaddr': ip_addr, 'mac_addr': mac_addr,
                    'ifindex': iface_index}
            self.notify(['remove_neigh', host])
            self.neighbours = list(filter(
                                   lambda x: x != host, self.neighbours))

    def notify(self, rheamsg):
        notification = pickle.dumps(rheamsg)
        if self.socket is not None:
            self.socket.send(notification)
            recv = self.socket.recv(8192)

    def ifaceTable(self, ipdb):
        ifaces = ipdb.by_name.keys()
        table = []
        for iface in ifaces:
            mac_addr = ipdb.interfaces[iface]['address']
            ip_addresses = ipdb.interfaces[iface]['ipaddr']
            ifindex = ipdb.interfaces[iface]['index']
            state = ipdb.interfaces[iface]['operstate']
            table.append({'ifname': iface, 'mac-address': mac_addr,
                          'IP-Addresses': [x for x in ip_addresses],
                          'ifindex': ifindex,
                          'state': state})
        return table

    def neighbourtable(self):
        return self.neighbours

    def returnunresolvedhost(self):
        return self.unresolvedneighbours

    def process_requests(self, ipdb, request):
        if request[0] == 'ifaceTable':
            res = self.ifaceTable(ipdb)
            result = ['ifaceTable', res]
            return pickle.dumps(result)

        if request[0] == 'neighbourtable':
            res = self.neighbourtable()
            result = ['neighbourtable', res]
            return pickle.dumps(result)

        if request[0] == 'get_unresolved':
            res = self.returnunresolvedhost()
            result = ['unresolved', res]
            return pickle.dumps(result)

    def handle_request(self, sock):
        is_active = True
        while is_active:
            received = sock.recv(8192)
            if len(received) != 0:
                request = pickle.loads(received)
                response = self.process_requests(self.ip, request)
                sock.send(response)

            if len(received) == 0:
                is_active = False
                sock.close()
        sock.close()

    def try_connect(self):
        while self.not_connect:
            try:
                self.socket = eventlet.connect(('127.0.0.1', 55651))
            except socket.error as e:
                pass
            else:
                self.not_connect = False

    def serve_forever(self):
        while self.serve:
            nl_sock, address = self.server.accept()
            self.pool.spawn_n(self.handle_request, nl_sock)
            log.info("Rhea has contacted us")
            self.try_connect()