# Commits

committed 0867f7a

Reversed to revision 1613

• Participants
• Parent commits 6f8151c
• Branches default

# File proto/doc/qspn/tex/qspn.tex

• Ignore whitespace
 	\item For all $r' \in R'$,
 		let $m'\in M$ be a route such that
 		$\T{dst}(r')=\T{dst}(m')$. If
-		$r'$ is a better alternative\footnote{in the current
-		implementation, $r'$ is always a better alternative. In fact,
-		in the previous step we've seen that we don't know any routes
-		to $\T{dst}(r')$ through $N$. $r'$ is a route to $\T{dst}(r')$
-		through $N$, so we memorise it. 	For more info, see Chapter 5 of
-		topology.pdf\cite{ntktopology} }
-		to $m'$ and if
+		$r'$ is a better alternative to $m'$ and if
 		every hop of $r'$ is reachable by $C$,
 		then $r'$  is saved in the map of $C$ as the
 		tern $(dst(r'), N, rem(r')+rem(C\rightarrow  The case where a new link$A \stackrel{l}{\leftrightarrow} B$  is established is handled in the same way of the  \textbf{Changed link} case, because we can consider$l$as a link with - a new rem. However, there's just one difference with the changed link - case: the algorithm does not stop if$R=\0$. This is because,$R=\0$ - if and only if$A$ - is a node with only one link. Even if$A\$ has just one link, it
-	has to send an ETP to advertise its existence to the other nodes of the network.
+	a new rem.

 	\item[Broken link] \qq\\
 		\begin{enumerate}

# File pyntk/TODO

• Ignore whitespace
 - debug, debug, debug

-- p2p.py:
-	- add support for "strict services", that this services that all
-	  Netsukuku nodes have to participate (Coord, maybe even ANDNA).
-	  For the strict services p2p.py can assume that all the active nodes
-	  in the map are participant. Thus, for example, it isn't necessary to
-	  inform the other nodes that X is a participant to Coord.
-	- add support to stop to be a participant (participant_del)
-	-  suppose X becomes a participant and then stops to be one.
-	  suppose that Y receives first the message telling that X is no more
-	  a participant, and then the one telling X is a participant. This is
-	  a problem. To avoid this, X shall add incremental IDs to each p2p
-	  message it sends. Y shall store the last received IDs from X.
-	  If Y receives a message whose ID is less or equal then the current
-	  one, then Y drops it.
-
-	- extend the theory:  declare the participation of nodes using a
-	  coordinator-node. In this way:
-		- don't use numerical ID for services. Let's use descriptive strings.
-		  For example, 'ntk.andna', 'ntk.coord'.
-		- a node will announce its partecipation to the 'myp2psrv'
-		  service  contacting its Local Hash Gnodes associated to the string
-		  'myp2psrv'. (see the Ntk_local_ANDNA  RFC)
-		  The Local Hash Gnodes will keep the list of participant that
-		  contacted them. For example, if a LHG has IP 11.22.33.44,
-		  its stored list can be as follow:
-		  	[11.22.33.13, 11.22.33.15, 11.22.55, 11.22.91, ...
-			 ..., 11.55, 23, 29]
-		  (stored in the TPL format)
-	  With this method, it isn't necessary to flood the network to
-	  announce the partecipation of a gnode.
-	  Clearly, each time the list of participant of a given level is
-	  needed, the Local Hash Gnodes must be contacted. This isn't optimal
-	  for the LHG which maintain the list of the last level (it would be
-	  contacted to many times)
-
-		  ...To do...   ...To refine...
-
 - misc
 	- When using wifi devices, don't create a TCP connection for each
 	  link. Use UDP and exploit the broadcast. In other words, if it is

# File pyntk/ntk/config.py

• Ignore whitespace

 DEFAULT_SETTINGS = dict(
     CONFIGURATION_FILE = 'settings.conf',
-    VERBOSE_LEVEL = 0,
-    DEBUG_ON_SCREEN = False,
+    DEBUG = False,
     # Inet
     IP_VERSION = 4,
     LOG_FILE = 'netsukuku.log',
     # Radar
     MAX_BOUQUET = 16,
     MAX_NEIGH = 16,
-    RADAR_WAIT_TIME = 8, # seconds
+    MAX_WAIT_TIME = 8, # seconds
     MULTIPATH = False,
     SIMULATED = False,


# File pyntk/ntk/core/coord.py

• Ignore whitespace
 #       good thing, you have to consider the rtt from the requester node to
 #       the coordinator node.

+from random import choice

-from ntk.lib.log import logger as logging
-from ntk.lib.log import get_stackframes
+from ntk.core.map import Map
+from ntk.core.p2p import P2P
+from ntk.lib.event import Event
 from ntk.lib.micro import microfunc
 from ntk.wrap.xtime import time
-from ntk.core.p2p import P2P
-from ntk.lib.rencode import serializable
-from ntk.core.map import Map
-from random import choice
-from ntk.network.inet import valid_ids
-

 class Node(object):
+    def __init__(self,
+                 lvl=None, id=None  # these are mandatory for Map.__init__(),
+                ):

-    def __init__(self, lvl, id, alive=False, its_me=False):
-        self.lvl = lvl
-        self.id = id
-        self.its_me = its_me
-        self.alive = alive
-        if self.its_me:
-            self.alive = True
+        self.alive = False

     def is_free(self):
-        return not self.alive
+        return self.alive

     def _pack(self):
-        # lvl and id are not used (as for now) at the time of de-serialization. So
-        # use the value that will produce the smaller output with rencode.dumps.
-        # TODO test what this value is... perhaps None is better than 0 ?
-        return (0, 0, self.alive)
-
-serializable.register(Node)
+        return (self.alive,)

 class MapCache(Map):
     def __init__(self, maproute):
-        logging.log(logging.ULTRADEBUG, 'Coord: copying a mapcache from our maproute.')
         Map.__init__(self, maproute.levels, maproute.gsize, Node, maproute.me)

         self.copy_from_maproute(maproute)

         self.tmp_deleted = {}

-    def alive_node_add(self, lvl, id):
-        if self.node_get(lvl, id).is_free():
-            self.node_get(lvl, id).alive = True
-            self.node_add(lvl, id)
-        logging.log(logging.ULTRADEBUG, 'Coord: MapCache updated: ' + str(self.repr_me()))
-
-    def me_changed(self, old_me, new_me):
-        '''Changes self.me
-
-        :param old_me: my old nip (not used in MapCache)
-        :param new_me: new nip
-        '''
-        Map.me_change(self, new_me)
-        logging.log(logging.ULTRADEBUG, 'Coord: MapCache updated after me_changed: ' + str(self.repr_me()))
-
     def copy_from_maproute(self, maproute):
         for lvl in xrange(self.levels):
             for id in xrange(self.gsize):
-                if not maproute.node_get(lvl, id).is_free():
-                    self.alive_node_add(lvl, id)
+                if not maproute.node_get(lvl, id).is_empty():
+                    self.node_add(lvl, id)

-    def map_data_pack(self):
-        """Prepares a packed_mapcache to be passed to mapcache.map_data_merge
-        in another host."""
-        def fmake_alive(node):
-            node.alive = True
-        return Map.map_data_pack(self, fmake_alive)
+    def node_add(self, lvl, id, silent=0):
+        if not self.node_get(lvl, id).alive:
+            Map.node_add(self, lvl, id, silent)
+            self.node_get(lvl, id).alive = True

-    def map_data_merge(self, (nip, plist, nblist)):
-        """Copies a mapcache from another nip's point of view."""
-        logging.log(logging.ULTRADEBUG, 'Merging a mapcache.map_data_merge: before: ' + self.repr_me())
-        # Was I alive?
-        # TODO always alive?
-        me_was = [False] * self.levels
-        for lvl in xrange(self.levels):
-            me_was[lvl] = self.node_get(lvl, self.me[lvl]).alive
-        logging.debug('MapCache replication: me_was : ' + str(me_was))
-        # Merge as usual...
-        lvl=self.nip_cmp(nip, self.me)
-        logging.log(logging.ULTRADEBUG, 'Merging a mapcache at level ' + str(lvl))
-        logging.log(logging.ULTRADEBUG, get_stackframes(back=1))
-        Map.map_data_merge(self, (nip, plist, nblist))
-        # ... ripristine myself.
-        for lvl in xrange(self.levels):
-            if me_was[lvl]:
-                self.alive_node_add(lvl, self.me[lvl])
-        logging.log(logging.ULTRADEBUG, 'Merging a mapcache.map_data_merge: after: ' + self.repr_me())
-
-    def repr_me(self, func_repr_node=None):
-        def repr_node_mapcache(node):
-            if node.alive: return 'X'
-            return ' '
-        if func_repr_node is None: func_repr_node = repr_node_mapcache
-        return Map.repr_me(self, func_repr_node)
+    def node_del(self, lvl, id, silent=False):
+        if self.node_get(lvl, id).alive:
+            Map.node_del(self, lvl, id, silent)
+            self.node_get(lvl, id).alive = False

     def tmp_deleted_add(self, lvl, id):
         self.tmp_deleted[lvl, id] = time()

     pid = 1

-    def __init__(self, ntkd, radar, maproute, p2pall):
+    def __init__(self, radar, maproute, p2pall):

         P2P.__init__(self, radar, maproute, Coord.pid)
-        self.ntkd = ntkd

         # let's register ourself in p2pall
         p2pall.p2p_register(self)
         # The cache of the coordinator node
         self.mapcache = MapCache(self.maproute)

-        self.maproute.events.listen('NODE_NEW', self.mapcache.alive_node_add)
+        self.maproute.events.listen('NODE_NEW', self.mapcache.node_add)
         self.maproute.events.listen('NODE_DELETED', self.mapcache.node_del)
-        self.maproute.events.listen('ME_CHANGED', self.mapcache.me_changed)
-
         self.mapp2p.events.listen('NODE_NEW', self.new_participant_joined)

-        self.coordnode = [None] * (self.maproute.levels + 1)
+        self.coordnode = [None] * self.maproute.levels
+        self.coornodes_set()

-        self.remotable_funcs += [self.going_out, self.going_out_ok, self.going_in]
+        self.remotable_funcs = [self.going_out,
+                                self.going_out_ok,
+                                self.going_in]

     def h(self, key):
-        """h:KEY-->hIP
+        """h:KEY-->IP
         :type key: a tuple (lvl, ip)
         """
         lvl, ip = key
-        hIP = list(ip)
+        IP = list(ip)
         for l in reversed(xrange(lvl)):
-            hIP[l] = 0
-        return hIP
+            IP[l] = 0
+        return IP

-    def coord_nodes_set(self):
+    def coornodes_set(self):
         """Sets the coordinator nodes of each level, using the current map"""
-        logging.log(logging.ULTRADEBUG, 'Coord: calculating coord_nodes for our gnodes of each level...')
         for lvl in xrange(self.maproute.levels):
-                self.coordnode[lvl+1] = self.H(self.h((lvl+1, self.maproute.me)))
-        logging.log(logging.ULTRADEBUG, 'Coord: coord_nodes (Note: check from the second one) is now ' + str(self.coordnode))
-
-    def participate(self):
-        """Let's become a participant node"""
-        P2P.participate(self)  # base method
-        self.coord_nodes_set()
-
+            self.coordnode[lvl] = self.H(self.h((lvl, self.maproute.me)))

     @microfunc()
     def new_participant_joined(self, lvl, id):
         """Shall the new participant succeed us as a coordinator node?"""

-        logging.log(logging.ULTRADEBUG, 'Coord: new_participant_joined started, a new participant in level ' + str(lvl) + ' id ' + str(id))
         # the node joined in level lvl', thus it may be a coordinator of the
         # level lvl+1'
         level = lvl + 1

-        # The new participant has this part of NIP
-        pIP = self.maproute.me[:]
-
+        pIP = list(self.maproute.me)
         pIP[lvl] = id

-        for l in reversed(xrange(lvl)): pIP[l] = None
-        # Note: I don't know its exact IP, it may have some None in lower-than-lvl levels.
+        for l in reversed(xrange(lvl)):
+            pIP[l] = None

-        # Was I the previous coordinator? Remember it.
-        it_was_me = self.coordnode[level] == self.maproute.me
+        newcor = self.H(self.h((level, self.maproute.me)))
+        if newcor != pIP:
+            # the new partecipant isn't a coordinator node
+            return None

-        # perfect IP for this service is...
-        hIP = self.h((level, self.maproute.me))
-        # as to our knowledge, the nearest participant to 'hIP' is now...
-        HhIP = self.H(hIP)
-        # Is it the new participant?
-        for j in xrange(lvl, self.maproute.levels):
-            if HhIP[j] != pIP[j]:
-                # the new participant isn't a coordinator node
-                return
+        oldcor = self.coordnode[level]
+        self.coordnode[level] = newcor

-        # Yes it is. Keep track.
-        self.coordnode[level] = HhIP
-        logging.info('Coord: new coordinator for our level ' + str(level) + ' is ' + str(HhIP))
+        if oldcor == self.maproute.me and pIP != self.maproute.me:
+            #if we were a coordinator node, and it is different from us:
+            # let's pass it our cache
+            peer = self.peer(hIP=newcor)
+            peer.mapp2p.map_data_merge(self.mapp2p.map_data_pack())

-        # Then, if I was the previous one... (Tricky enough, new participant could just be me!)
-        if it_was_me and HhIP != self.maproute.me:
-            # ... let's pass it our cache
-            logging.debug('Coord: I was coordinator for our level ' + str(level) + ', new coordinator is ' + str(HhIP))
-            logging.debug('Coord: So I will pass him my mapcache.')
-            peer = self.peer(hIP=hIP)
-            peer.mapcache.map_data_merge(self.mapcache.map_data_pack())
-            logging.debug('Coord: Done passing my mapcache.')
-
-
-    def going_out(self, lvl, id, gfree_new=None):
+    def going_out(self, lvl, id, gnumb=None):
         """The node of level lvl' and ID id', wants to go out from its gnode
         G of level lvl+1. We are the coordinator of this gnode G.
+        We'll give an affermative answer if gnumb' < |G| or if gnumb'=None
+        """

-        If gfree_new is None, then we don't have to check any condition.
-        So we remove the node and return the new free_nodes of this gnode.

-        Otherwise, the caller has passed the number of free nodes in the
-        gnode where it's going to rehook. So we must check that our
-        free_nodes is lesser than (gfree_new - 1).
-        If so, we remove the node and return the new free_nodes of this gnode,
-        else, we return None."""
-
-        if gfree_new is None \
-                or self.mapcache.free_nodes_nb(lvl) < gfree_new - 1:
-            if self.mapcache.node_get(lvl, id).alive:
-                self.mapcache.node_del(lvl, id)
-                return self.mapcache.free_nodes_nb(lvl)
-            else:
-                return None
+        if (gnumb < self.mapp2p.nodes_nb[lvl]-1 or gnumb is None) \
+            and self.mapp2p.node_get(lvl, id).alive:
+                self.mapp2p.node_del(lvl, id)
+                return self.mapp2p.nodes_nb[lvl]
         else:
             return None

     def going_out_ok(self, lvl, id):
         """The node, which was going out, is now acknowledging the correct
         migration"""
+        self.mapp2p.tmp_deleted_del(lvl, id)

-        self.mapcache.tmp_deleted_del(lvl, id)
-
-    def going_in(self, lvl, gfree_old_coord=None):
+    def going_in(self, lvl, gnumb=None):
         """A node wants to become a member of our gnode G of level lvl+1'.
         We are the coordinator of this gnode G (so we are also a member of G).
+        We'll give an affermative answer if gnumb' > |G| or if gnumb'=None
+        """
 
-        If gfree_old_coord is None, then we don't have to check any condition.
-        So we add the node and return the assigned newnip.
-
-        Otherwise, the caller has passed the current number of free nodes
-        in the gnode which it's leaving. So we must check that our
-        current free_nodes is bigger than gfree_old_coord.
-        If so, we add the node and return the assigned newnip,
-        else, we return None."""
-
-        logging.log(logging.ULTRADEBUG, 'Coord.going_in: The requested level is ' + str(lvl))
-        logging.log(logging.ULTRADEBUG, 'Coord.going_in: This is mapcache.')
-        logging.log(logging.ULTRADEBUG, self.mapcache.repr_me())
-
-        if gfree_old_coord is not None \
-                and not self.mapcache.free_nodes_nb(lvl) > gfree_old_coord:
-            return None
-
-        fnl = self.mapcache.free_nodes_list(lvl)
-        if fnl == []:
+        if gnumb > self.mapp2p.node_nb[lvl]+1:
+            fnl = self.mapp2p.free_nodes_list(lvl)
+            if fnl == []:
                 return None
 
-        newnip = self.mapcache.me[:]
-        newnip[lvl] = choice(fnl)
-        for l in reversed(xrange(lvl)): newnip[l] = choice(valid_ids(lvl, newnip))
+            newip = self.mapp2p.me
+            newip[lvl] = choice(fnl)
+            for l in reversed(xrange(lvl)):
+                newnip[l]=randint(0, self.mapp2p.gsize)
+            self.node_add(lvl, newip[lvl])
+            return newip
 
-        self.mapcache.alive_node_add(lvl, newnip[lvl])
-
-        logging.log(logging.ULTRADEBUG, 'Coord.going_in: returns ' + str(newnip))
-        return newnip
-
+        return None

# File pyntk/ntk/core/krnl_route.py

• Ignore whitespace
 # Listens to MapRoute generated events, and updates the kernel table
 #
 
-from ntk.lib.log import logger as logging
 from ntk.config import settings
 from ntk.lib.event import Event, apply_wakeup_on_event
-from ntk.lib.micro import microfunc, micro_block
+from ntk.lib.micro import microfunc
 from ntk.network import Route as KRoute
 from ntk.network.inet import ip_to_str, lvl_to_bits
 
 class KrnlRoute(object):
-    def __init__(self, ntkd, neigh, maproute):
-        self.ntkd = ntkd
-
+    def __init__(self, neigh, maproute):
         self.maproute = maproute
         self.neigh = neigh
         self.multipath = settings.MULTIPATH
 
+        self.events =  Event(['KRNL_NEIGH_NEW'])
+
+        self.route_new = apply_wakeup_on_event(self.route_new,
+                                               events=[(self.neigh.events, 'NEIGH_NEW'),
+                                                       (self.events, 'KRNL_NEIGH_NEW')])
+
         self.maproute.events.listen('ROUTE_NEW', self.route_new)
-        self.route_new_calls = []
         self.maproute.events.listen('ROUTE_DELETED', self.route_deleted)
-        self.route_deleted_calls = []
         self.maproute.events.listen('ROUTE_REM_CHGED', self.route_rem_changed)
-        self.route_rem_changed_calls = []
 
-        self.neigh.events.listen('NEIGH_NEW', self.neigh_new, priority=5)
-        self.neigh_new_calls = []
-        self.neigh.events.listen('NEIGH_DELETED', self.neigh_deleted, priority=15)
-        self.neigh_deleted_calls = []
-        self.neigh.events.listen('NEIGH_REM_CHGED', self.neigh_rem_changed, priority=5)
-        self.neigh_rem_changed_calls = []
+        self.neigh.events.listen('NEIGH_NEW', self.neigh_new)
+        self.neigh.events.listen('NEIGH_DELETED', self.neigh_deleted)
+        self.neigh.events.listen('NEIGH_REM_CHGED', self.neigh_rem_changed)
 
 
-    def route_new(self, lvl, dst, gw, rem):
-        # We'll do the real thing in a microfunc, but make sure
-        # to have a chance to get scheduled as soon as possible
-        # and obtain immediately any data that is susceptible to change.
-        self.route_new_calls.append((lvl, dst, gw, rem, self.maproute.node_get(lvl, dst).nroutes()))
-        self._route_new()
-        micro_block()
+    @microfunc(True)
+    def route_new(self, lvl, dst, gw, rem, event_wait=None):
 
-    @microfunc()
-    def _route_new(self):
-        lvl, dst, gw, rem, nroutes = self.route_new_calls.pop(0)
-        # Obtain IP for node and gateway
-        nip = self.maproute.lvlid_to_nip(lvl, dst)
-        ip  = self.maproute.nip_to_ip(nip)
-        neighgw = self.neigh.id_to_neigh(gw)
-        gwip = neighgw.ip
-        # Did we already have one route to this node?
-        existing = nroutes >= 2
-        # Obtain a IP string for the node
-        ipstr = ip_to_str(ip)
-        # Obtain a IP string for this gateway
-        dev = neighgw.bestdev[0]
-        gwipstr = ip_to_str(gwip)
-        # Do we have multipath
-        if self.multipath:
-            # Add new route
-            self.neigh.waitfor_gw_added(gw)
-            KRoute.add(ipstr, lvl_to_bits(lvl), dev, gwipstr)
-        else:
-            # Add or eventually change best route
-            if existing:
-                # Eventually change
-                # Obtain a IP string for the best gateway
-                node = self.maproute.node_get(lvl, dst)
-                best = node.best_route()
-                newgw = best.gw.id
-                newgw_neigh = best.gw
-                newgw_dev = newgw_neigh.bestdev[0]
-                newgw_gwipstr = ip_to_str(newgw_neigh.ip)
-                # Change route in the kernel
-                self.neigh.waitfor_gw_added(newgw)
-                KRoute.change(ipstr, lvl_to_bits(lvl), newgw_dev, gateway=newgw_gwipstr)
-            else:
-                # Add
-                self.neigh.waitfor_gw_added(gw)
-                KRoute.add(ipstr, lvl_to_bits(lvl), dev, gwipstr)
+        if not self.multipath and self.maproute.node_get(lvl, dst).nroutes_synced() >= 1:
+                # We don't have multipath and we've already set one route.
+                return
 
-    def route_deleted(self, lvl, dst, gwip):
-        # We'll do the real thing in a microfunc, but make sure
-        # to have a chance to get scheduled as soon as possible
-        # and obtain immediately any data that is susceptible to change.
-        self.route_deleted_calls.append((lvl, dst, gwip, self.maproute.node_get(lvl, dst).is_free()))
-        self._route_deleted()
-        micro_block()
-
-    @microfunc()
-    def _route_deleted(self):
-        lvl, dst, gwip, isfree = self.route_deleted_calls.pop(0)
-        # Obtain a IP string for the node
         nip = self.maproute.lvlid_to_nip(lvl, dst)
         ip  = self.maproute.nip_to_ip(nip)
         ipstr = ip_to_str(ip)
-        # Obtain a IP string for the old gateway
-        gwipstr = ip_to_str(gwip)
-        # Do we have multipath?
-        if self.multipath:
-            # Just remove old route from kernel
-            KRoute.delete(ipstr, lvl_to_bits(lvl), gateway=gwipstr)
-        else:
-            # Is there a new best route for this node?
-            if isfree:
-                # No more routes, just remove old route from kernel
-                KRoute.delete(ipstr, lvl_to_bits(lvl), gateway=gwipstr)
-            else:
-                # Obtain a IP string for the new gateway
-                node = self.maproute.node_get(lvl, dst)
-                best = node.best_route()
-                newgw = best.gw.id
-                newgw_neigh = best.gw
-                newgw_dev = newgw_neigh.bestdev[0]
-                newgw_gwipstr = ip_to_str(newgw_neigh.ip)
-                # Change route in the kernel
-                KRoute.change(ipstr, lvl_to_bits(lvl), newgw_dev, gateway=newgw_gwipstr)
+        neigh = self.neigh.id_to_neigh(gw)
+        dev = neigh.bestdev[0]
+        gwipstr = ip_to_str(neigh.ip)
+        neigh_node = self.maproute.node_get(*self.maproute.routeneigh_get(neigh))
+
+        if neigh_node.nroutes() > 1:
+                # Let's wait to add the neighbour first
+                while 1:
+                        ev_neigh = event_wait[(self.neigh.events, 'NEIGH_NEW')]()
+                        if neigh == ev_neigh[0]:
+                                # found
+                                break
+
+        if neigh_node.routes_tobe_synced > 0:
+                # The routes to neigh are still to be synced, let's wait
+                while 1:
+                        ev_neigh = event_wait[(self.events, 'KRNL_NEIGH_NEW')]()
+                        if neigh == ev_neigh[0]:
+                                # found
+                                break
+
+        # We can add the route in the kernel
+        KRoute.add(ipstr, lvl_to_bits(lvl), dev, gwipstr)
+
+        self.maproute.node_get(lvl, dst).routes_tobe_synced-=1
+
+
+    @microfunc(True)
+    def route_deleted(self, lvl, dst, gw):
+        nip = self.maproute.lvlid_to_nip(lvl, dst)
+        ip  = self.maproute.nip_to_ip(nip)
+        ipstr = ip_to_str(ip)
+        neigh = self.neigh.id_to_neigh(gw)
+        dev = neigh.bestdev[0]
+        gwipstr = ip_to_str(neigh.ip)
+
+        KRoute.delete(ipstr, lvl_to_bits(lvl), gateway=gwipstr)
 
     def route_rem_changed(self, lvl, dst, gw, rem, oldrem):
-        # We'll do the real thing in a microfunc, but make sure
-        # to have a chance to get scheduled as soon as possible
-        # and obtain immediately any data that is susceptible to change.
-        self.route_rem_changed_calls.append((lvl, dst, gw, rem, oldrem))
-        self._route_rem_changed()
-        micro_block()
+        pass
 
-    @microfunc()
-    def _route_rem_changed(self):
-        lvl, dst, gw, rem, oldrem = self.route_rem_changed_calls.pop(0)
-        # Do we have multipath?
-        if not self.multipath:
-            # We might have a different best route now
-            # Obtain a IP string for the node
-            nip = self.maproute.lvlid_to_nip(lvl, dst)
-            ip  = self.maproute.nip_to_ip(nip)
-            ipstr = ip_to_str(ip)
-            # Obtain a IP string for the actual best gateway
-            node = self.maproute.node_get(lvl, dst)
-            best = node.best_route()
-            newgw = best.gw.id
-            newgw_neigh = best.gw
-            newgw_dev = newgw_neigh.bestdev[0]
-            newgw_gwipstr = ip_to_str(newgw_neigh.ip)
-            # Change route in the kernel
-            self.neigh.waitfor_gw_added(newgw)
-            KRoute.change(ipstr, lvl_to_bits(lvl), newgw_dev, gateway=newgw_gwipstr)
-
+    @microfunc(True)
     def neigh_new(self, neigh):
-        # We'll do the real thing in a microfunc, but make sure
-        # to have a chance to get scheduled as soon as possible
-        # and obtain immediately any data that is susceptible to change.
-        self.neigh_new_calls.append(neigh)
-        self._neigh_new()
-        micro_block()
-
-    @microfunc()
-    def _neigh_new(self):
-        neigh = self.neigh_new_calls.pop(0)
         ipstr = ip_to_str(neigh.ip)
         dev = neigh.bestdev[0]
-        KRoute.add_neigh(ipstr, dev)
-        logging.debug('ANNOUNCE: gw ' + str(neigh.id) + ' added.')
-        self.neigh.announce_gw_added(neigh.id)
+        gwipstr = ipstr
+
+        KRoute.add(ipstr, lvl_to_bits(0), dev, gwipstr)
+
+        self.events.send('KRNL_NEIGH_NEW', (neigh,))
 
     def neigh_rem_changed(self, neigh, oldrem=None):
-        # We'll do the real thing in a microfunc, but make sure
-        # to have a chance to get scheduled as soon as possible
-        # and obtain immediately any data that is susceptible to change.
-        self.neigh_rem_changed_calls.append((neigh, oldrem))
-        self._neigh_rem_changed()
-        micro_block()
+        pass
 
-    @microfunc()
-    def _neigh_rem_changed(self):
-        neigh, oldrem = self.neigh_rem_changed_calls.pop(0)
+    @microfunc(True)
+    def neigh_deleted(self, neigh):
         ipstr = ip_to_str(neigh.ip)
-        dev = neigh.bestdev[0]
-        KRoute.change_neigh(ipstr, dev)
 
-    def neigh_deleted(self, neigh):
-        # We'll do the real thing in a microfunc, but make sure
-        # to have a chance to get scheduled as soon as possible
-        # and obtain immediately any data that is susceptible to change.
-        self.neigh_deleted_calls.append(neigh)
-        self._neigh_deleted()
-        micro_block()
-
-    @microfunc()
-    def _neigh_deleted(self):
-        neigh = self.neigh_deleted_calls.pop(0)
-        ipstr = ip_to_str(neigh.ip)
-        self.neigh.waitfor_gw_removable(neigh.id)
-        KRoute.delete_neigh(ipstr)
-
+        KRoute.delete(ipstr, lvl_to_bits(0))

# File pyntk/ntk/core/map.py

• Ignore whitespace
 # Implementation of the map. See {-topodoc-}
 #
 
-from random import randint, choice
-from ntk.lib.log import get_stackframes
+from random import randint
 
 from ntk.lib.event import Event
-from ntk.network.inet import valid_ids
-import ntk.wrap.xtime as xtime
 
 
 class DataClass(object):
     As another example, look MapRoute and RouteNode in route.py
     """
 
-    def __init__(self, level, id, its_me=False):
+    def __init__(self, level, id):
         # do something
         pass
 
         self.levels = levels   # Number of levels
         self.gsize = gsize     # How many nodes are contained in a gnode
         self.dataclass = dataclass
-        if me is None: self.me = None
-        else: self.me = me[:]     # Ourself. self.me[lvl] is the ID of our
-                                  # (g)node of level lvl
+        self.me = me        # Ourself. self.me[lvl] is the ID of our
+                            # (g)node of level lvl
         # Choose a random nip
         if me is None:
             self.me = self.nip_rand()
         #   self.node_nb[i] = number of (g)nodes inside the gnode self.me[i+1]
         self.node_nb = [0] * self.levels
 
-        for lvl in xrange(self.levels):
-            node_me = self.node_get(lvl, self.me[lvl])
-            if not node_me.is_free(): self.node_add(lvl, self.me[lvl], silent=1)
-
         self.events = Event(['NODE_NEW', 'NODE_DELETED', 'ME_CHANGED'])
 
     def node_get(self, lvl, id):
         it doesn't exist, it is created"""
 
         if self.node[lvl][id] is None:
-            if self.me is not None and self.me[lvl] == id:
-                self.node[lvl][id] = self.dataclass(lvl, id, its_me=True)
-            else:
-                self.node[lvl][id] = self.dataclass(lvl, id)
+            self.node[lvl][id] = self.dataclass(lvl, id)
         return self.node[lvl][id]
 
     def node_add(self, lvl, id, silent=0):
-        """Add node 'id at level 'lvl'.
-
-        The caller of this method has the responsibility to check that the node was
-        previously free, and that now it is busy. This method just sends the event
-        and updates the counters"""
-        node = self.node[lvl][id]
-        if node is not None and not node.is_free():
-            self.node_nb[lvl] += 1
-            if not silent:
-                self.events.send('NODE_NEW', (lvl, id))
+        self.node_get(lvl, id)
+        self.node_nb[lvl] += 1
+        if not silent:
+            self.events.send('NODE_NEW', (lvl, id))

     def node_del(self, lvl, id, silent=0):
-        """Delete node 'id at level 'lvl'.
-        
-        This method checks that the node was previously busy. Then it deletes the
-        node, sends the event and updates the counters"""
-        node = self.node[lvl][id]
-        if node is not None and not node.is_free():
-            self.node[lvl][id]=None
-            if self.node_nb[lvl] > 0:
-                self.node_nb[lvl] -= 1
-            if not silent:
-                self.events.send('NODE_DELETED', (lvl, id))
+        ''' Delete node 'id at level 'lvl '''
+        if self.node_nb[lvl] > 0:
+            self.node_nb[lvl] -= 1
+
+        if not silent:
+            self.events.send('NODE_DELETED', (lvl, id))
+        self.node[lvl][id]=None
 
     def free_nodes_nb(self, lvl):
         """Returns the number of free nodes of level lvl'"""
-        #it depends on the lvl and on the previous ids
-        return len(valid_ids(lvl, self.me))-self.node_nb[lvl]
+        return self.gsize-self.node_nb[lvl]

     def free_nodes_list(self, lvl):
         """Returns the list of free nodes of level lvl'"""
-        #it depends on the lvl and on the previous ids
-        return [nid for nid in valid_ids(lvl, self.me) if (not self.node[lvl][nid]) or self.node[lvl][nid].is_free()]
-
-    def free_nodes_list_in_empty_network(self):
-        """Returns the list of free nodes of level self.levels-1' in an empty network"""
-        return [nid for nid in valid_ids(self.levels - 1, self.me)]
+        return [nid for nid in xrange(self.gsize)
+                        if self.node_get(lvl, nid).is_free()]

     def is_in_level(self, nip, lvl):
         """Does the node nip belongs to our gnode of level lvl'?"""
 
     def nip_rand(self):
         """Returns a random netsukuku ip"""
-        nip = [0 for i in xrange(self.levels)]
-        for lvl in reversed(xrange(self.levels)):
-            nip[lvl] = self._nip_rand(lvl, nip)
-        return nip
-
-    def _nip_rand(self, lvl, nip):
-        """Returns a random id for level lvl that is valid, given that the previous ids are in nip"""
-        return choice(valid_ids(lvl, nip))
+        return [randint(0, self.gsize-1) for i in xrange(self.levels)]
 
     def level_reset(self, level):
         """Resets the specified level, without raising any event"""
-
         self.node[level] = [None] * self.gsize
-
         self.node_nb[level] = 0
-        node_me = self.node_get(level, self.me[level])
-        if not node_me.is_free(): self.node_add(level, self.me[level], silent=1)
 
     def map_reset(self):
         """Silently resets the whole map"""
         for l in xrange(self.levels):
             self.level_reset(l)
 
-    def me_change(self, new_me, silent=False):
+    def me_change(self, new_me):
         """Changes self.me"""
+        old_me = self.me[:]
+        self.me = new_me
+        self.events.send('ME_CHANGED', (old_me, new_me))
 
-        # changing my nip will make many nodes no more significant in my map
-        lev = self.nip_cmp(self.me, new_me)
-        if lev == -1: return  # the same old nip
-        for l in xrange(lev):
-            self.level_reset(l)
-        # silently remove the dataclass objects representing old me (current)
-        for l in xrange(self.levels):
-                self.node[l][self.me[l]] = None
-        # now, change
 
-        old_me = self.me[:]
-        self.me = new_me[:]
-        # silently add the dataclass objects representing new me
-        for l in xrange(self.levels):
-                self.node[l][self.me[l]] = self.dataclass(l, self.me[l], its_me=True)
-        if not silent:
-                self.events.send('ME_CHANGED', (old_me, self.me))
-
-    def map_data_pack(self, func=None):
-        """Prepares a packed_map to be passed to map_data_merge in another host.
-        
-        func' is a function that receives a node and makes it not free.
-        """
-        ret = (self.me,
+    def map_data_pack(self):
+        '''Pack the data map'''
+        return (self.me,
                 [[self.node[lvl][id] for id in xrange(self.gsize)]
                                      for lvl in xrange(self.levels)],
                 [self.node_nb[lvl] for lvl in xrange(self.levels)])
-        for lvl in xrange(self.levels):
-            # self.me MUST be replaced
-            # with a normal node
-            node = self.dataclass(lvl, self.me[lvl])
-            if func: func(node)
-            ret[1][lvl][self.me[lvl]] = node
-
-        # It's been a tough work! And now we'll probably serialize the result!
-        xtime.sleep_during_hard_work(10)
-
-        return ret

     def map_data_merge(self, (nip, plist, nblist)):
-        """Copies a map from another nip's point of view."""
-        lvl=self.nip_cmp(nip, self.me)
+        lvl = self.nip_cmp(nip, self.me)
+        for l in xrange(lvl, self.levels):
+            self.node_nb[l] = nblist[l]
+            for id in xrange(self.gsize):
+                self.node[l][id] = plist[l][id]
+        for l in xrange(0, lvl):
+            self.level_reset(l)

-        for l in xrange(lvl, self.levels):
-                xtime.sleep_during_hard_work(10)
-
-                self.node_nb[l]=nblist[l]
-                for id in xrange(self.gsize):
-                    if id != self.me[l]:  # self.me MUST NOT be replaced
-                                          # with a normal node
-                        self.node[l][id]=plist[l][id]
-
-        for l in xrange(0, lvl):
-                self.level_reset(l)
-
-    def repr_me(self, func_repr_node=None):
-        '''debugging function'''
-        ret = 'me ' + str(self.me) + ', node_nb ' + str(self.node_nb) + ', {'
-        for lvl in xrange(self.levels):
-            ret += self.repr_level(lvl, func_repr_node)
-        ret += '}'
-        return ret
-
-    def repr_level(self, lvl, func_repr_node=None):
-        '''debugging function'''
-        def repr_node_map(node):
-            if node.is_free(): return ' '
-            return 'X'
-        if func_repr_node is None: func_repr_node = repr_node_map
-        ret = ' ['
-        for i in xrange(self.gsize):
-            ret += '\'' + func_repr_node(self.node_get(lvl, i))
-        ret += '\'] '
-        return ret

# File pyntk/ntk/core/p2p.py

• Ignore whitespace
 # Implementation of the P2P Over Ntk RFC. See {-P2PNtk-}
 #

-import ntk.lib.rpc as rpc
-import ntk.wrap.xtime as xtime
-from ntk.lib.log import logger as logging
-from ntk.lib.log import get_stackframes
+from ntk.core.map import Map
 from ntk.lib.event import Event
-from ntk.lib.rpc   import FakeRmt, RPCDispatcher, CallerInfo
-from ntk.lib.micro import microfunc, Channel
+from ntk.lib.micro import microfunc
 from ntk.lib.rencode import serializable
-from ntk.core.map import Map
-
+from ntk.lib.rpc import FakeRmt, RPCDispatcher, CallerInfo

 class P2PError(Exception):
     '''Generic P2P Error'''

 class ParticipantNode(object):
-    def __init__(self, lvl, id, participant=False, its_me=False):
-        self.lvl = lvl
-        self.id = id
-        self.its_me = its_me
+    def __init__(self,
+                 lvl=None, id=None,  # these are mandatory for Map.__init__()
+                 participant=False):
+
         self.participant = participant

-    def is_free(self):
-        '''Override the is_free() method of DataClass (see map.py)'''
-        # DON'T DO THIS:   if self.its_me: return False
-        # Myself, I might be not participant!
-        return not self.participant
-
     def _pack(self):
-        # lvl and id are not used (as for now) at the time of de-serialization. So
-        # use the value that will produce the smaller output with rencode.dumps.
-        # TODO test what this value is... perhaps None is better than 0 ?
         return (0, 0, self.participant)

-    def __repr__(self):
-        return '<%s: %s>' % (self.__class__.__name__, self.participant)
-
 serializable.register(ParticipantNode)

 class MapP2P(Map):

         self.pid = pid

-    def participant_node_add(self, lvl, id):
-        if self.node_get(lvl, id).is_free():
-                self.node_get(lvl, id).participant = True
-                self.node_add(lvl, id)
-        logging.log(logging.ULTRADEBUG, 'P2P: MapP2P updated: ' + str(self.repr_me()))
+    def participate(self):
+        """Set self.me to be a participant node."""

+        for l in xrange(self.levels):
+            self.node_get(l, self.me[l]).participant = True
+
+    @microfunc()
     def me_changed(self, old_me, new_me):
         '''Changes self.me

         :param new_me: new nip
         '''
         Map.me_change(self, new_me)
-        logging.log(logging.ULTRADEBUG, 'P2P: MapP2P updated after me_changed: ' + str(self.repr_me()))

     @microfunc(True)
     def node_del(self, lvl, id):
         Map.node_del(self, lvl, id)

-    def participate(self):
-        """Set self.me to be a participant node."""
-
-        for l in xrange(self.levels):
-            self.participant_node_add(l, self.me[l])
-
-    def map_data_pack(self):
-        """Prepares a packed_mapp2p to be passed to mapp2p.map_data_merge
-        in another host."""
-        def fmake_participant(node):
-            node.participant = True
-        return Map.map_data_pack(self, fmake_participant)
-
-    def map_data_merge(self, (nip, plist, nblist)):
-        """Copies a mapp2p from another nip's point of view."""
-        logging.log(logging.ULTRADEBUG, 'Merging a mapp2p.map_data_merge: before: ' + self.repr_me())
-        # Was I participant?
-        me_was = [False] * self.levels
-        for lvl in xrange(self.levels):
-            me_was[lvl] = self.node_get(lvl, self.me[lvl]).participant
-        # Merge as usual...
-        lvl=self.nip_cmp(nip, self.me)
-        logging.log(logging.ULTRADEBUG, 'Merging a mapp2p at level ' + str(lvl))
-        logging.log(logging.ULTRADEBUG, get_stackframes(back=1))
-        Map.map_data_merge(self, (nip, plist, nblist))
-        # ... ripristine myself.
-        for lvl in xrange(self.levels):
-            if me_was[lvl]:
-                self.participant_node_add(lvl, self.me[lvl])
-        logging.log(logging.ULTRADEBUG, 'Merging a mapp2p.map_data_merge: after: ' + self.repr_me())
-
-    def repr_me(self, func_repr_node=None):
-        def repr_node_mapp2p(node):
-            if node.participant: return 'X'
-            return ' '
-        if func_repr_node is None: func_repr_node = repr_node_mapp2p
-        return Map.repr_me(self, func_repr_node)
-
 class P2P(RPCDispatcher):
     """This is the class that must be inherited to create a P2P module.
     """
                              self.maproute.me,
                              pid)

-        self.maproute.events.listen('ME_CHANGED', self.me_changed)
+        self.maproute.events.listen('ME_CHANGED', self.mapp2p.me_changed)
         self.maproute.events.listen('NODE_DELETED', self.mapp2p.node_del)

         # are we a participant?
         self.participant = False

-        self.remotable_funcs = [self.participant_add,
-                                self.participant_add_udp,
-                                self.msg_send,
-                                self.msg_send_udp]
-
+        self.remotable_funcs = [self.participant_add, self.msg_send]
         RPCDispatcher.__init__(self, root_instance=self)

-    @microfunc()
-    def me_changed(self, old_me, new_me):
-        """My nip has changed."""
-        self.mapp2p.me_changed(old_me, new_me)
-        self.re_participate()
-
     def h(self, key):
-        """This is the function h:KEY-->hIP.
+        """This is the function h:KEY-->IP.

         You should override it with your own mapping function.
         """
         return key

-    def H(self, hIP):
+    def H(self, IP):
         """This is the function that maps each IP to an existent hash node IP
-           If there are no participants, None is returned"""
+
+        If there are no participants, None is returned
+        """
+
         mp = self.mapp2p
-        logging.log(logging.ULTRADEBUG, 'H: H(' + str(hIP) + ')')
-        logging.log(logging.ULTRADEBUG, 'H: mapp2p = ' + mp.repr_me())
-        H_hIP = [None] * mp.levels
+        hIP = [None] * mp.levels
         for l in reversed(xrange(mp.levels)):
             for id in xrange(mp.gsize):
-                for sign in [-1,1]:
-                    hid=(hIP[l] + id * sign) % mp.gsize
+                for sign in [-1, 1]:
+                    hid = (IP[l] + id * sign) % mp.gsize
                     if mp.node_get(l, hid).participant:
-                        H_hIP[l] = hid
+                        hIP[l] = hid
                         break
-                if H_hIP[l] is not None:
+                if hIP[l]:
                     break
-            if H_hIP[l] is None:
-                logging.log(logging.ULTRADEBUG, 'H: H(' + str(hIP) + ') = None')
+            if hIP[l] is None:
                 return None

-            if H_hIP[l] != mp.me[l]:
+            if hIP[l] != mp.me[l]:
                 # we can stop here
                 break

-        logging.log(logging.ULTRADEBUG, 'H: H(' + str(hIP) + ') = ' + str(H_hIP))
-        return H_hIP
+        return hIP

     def neigh_get(self, hip):
         """Returns the Neigh instance of the neighbour we must use to reach
         If nothing is found, None is returned
         """

-        lvl = self.maproute.nip_cmp(hip, self.maproute.me)
+        lvl = self.mapp2p.nip_cmp(hip, self.maproute.me)
         br = self.maproute.node_get(lvl, hip[lvl]).best_route()
-
         if not br:
             return None
-        return br.gw
-
-    def re_participate(self, *args):
-        """Let's become a participant node again. Used when my nip has changed."""
-        if self.participant:
-            self.participate()
-        logging.log(logging.ULTRADEBUG, 'P2P: MapP2P updated after re_participate: ' + str(self.mapp2p.repr_me()))
+        return self.neigh.id_to_neigh(br.gw)

     def participate(self):
         """Let's become a participant node"""
-        self.participant = True
+
         self.mapp2p.participate()
-        current_nr_list = self.neigh.neigh_list(in_my_network=True)

-        # TODO handle the case where one of neighbours does not reply (raises an error)
-        for nr in current_nr_list:
-            try:
-                logging.debug('calling participant_add(myself) to %s.' % self.maproute.ip_to_nip(nr.ip))
-                self.call_participant_add_udp(nr, self.maproute.me)
-                logging.debug('done calling participant_add(myself) to %s.' % self.maproute.ip_to_nip(nr.ip))
-            except:
-                logging.debug('timeout (no problem) calling participant_add(myself) to %s.' % self.maproute.ip_to_nip(nr.ip))
+        for nr in self.neigh.neigh_list():
+            nr.ntkd.p2p.participant_add(self.maproute.pid, self.maproute.me)

-    def call_participant_add_udp(self, neigh, pIP):
-        """Use BcastClient to call etp_exec"""
-        devs = [neigh.bestdev[0]]
-        nip = self.ntkd.maproute.ip_to_nip(neigh.ip)
-        netid = neigh.netid
-        return rpc.UDP_call(nip, netid, devs, 'p2p.PID_'+str(self.mapp2p.pid)+'.participant_add_udp', (pIP, ))
-
-    def participant_add_udp(self, _rpc_caller, caller_id, callee_nip, callee_netid, pIP):
-        """Returns the result of participant_add to remote caller.
-           caller_id is the random value generated by the caller for this call.
-            It is replied back to the LAN for the caller to recognize a reply destinated to it.
-           callee_nip is the NIP of the callee;
-           callee_netid is the netid of the callee.
-            They are used by the callee to recognize a request destinated to it.
-           """
-        if self.maproute.me == callee_nip and self.neigh.netid == callee_netid:
-            self.participant_add(pIP)
-            # Since it is micro, I will reply None
-            rpc.UDP_send_reply(_rpc_caller, caller_id, None)
-
-    @microfunc(True)
     def participant_add(self, pIP):
         '''Add a participant node to the P2P service

         :param pIP: participant node's Netsukuku IP (nip)
         '''
+        continue_to_forward = False

-        continue_to_forward = False
-        current_nr_list = self.neigh.neigh_list(in_my_network=True)
         mp  = self.mapp2p
         lvl = self.maproute.nip_cmp(pIP, mp.me)
         for l in xrange(lvl, mp.levels):
-            ##
-            # We might receive the request to register a participant from a
-            # neighbour that has not yet sent us an ETP. In that case we would
-            # not have yet the route to it in the map. It's a matter of time,
-            # so we wait. (we are in a microfunc)
-            def is_node_pIP_alive():
-                    return not self.maproute.node_get(l, pIP[l]).is_free()
-            xtime.while_condition(is_node_pIP_alive, wait_millisec=100, repetitions=160)
-            ##
-
             if not mp.node_get(l, pIP[l]).participant:
-                logging.debug('registering participant (%s, %s) to service %s.' % (l, pIP[l], mp.pid))
-                mp.participant_node_add(l, pIP[l])
+                mp.node_get(l, pIP[l]).participant = True
+                mp.node_add(l, pIP[l])
                 continue_to_forward = True

         if not continue_to_forward:
             return

         # continue to advertise the new participant
-
-        # TODO handle the case where one of neighbours does not reply (raises an error)
-        # TODO do we have to skip the one who sent to us? It is not needed cause it won't forward anyway.
-
-        for nr in current_nr_list:
-            try:
-                logging.debug('forwarding participant_add(%s) to %s service %s.' % (pIP, self.maproute.ip_to_nip(nr.ip), mp.pid))
-                self.call_participant_add_udp(nr, pIP)
-                logging.debug('done forwarding participant_add(%s) to %s.' % (pIP, self.maproute.ip_to_nip(nr.ip)))
-            except:
-                logging.debug('timeout (no problem) forwarding participant_add(%s) to %s.' % (pIP, self.maproute.ip_to_nip(nr.ip)))
-
+        for nr in self.neigh.neigh_list():
+            nr.ntkd.p2p.participant_add(self.pid, pIP) # ntkd.p2p is a P2PAll
+                                                       # instance so we must
+                                                       # pass also the P2P pid

     def msg_send(self, sender_nip, hip, msg):
         """Routes a packet to hip'. Do not use this function directly, use
 
         msg: it is a (func_name, args) pair."""
 
-        logging.log(logging.ULTRADEBUG, 'Someone is asking for P2P service to ' + str(hip))
-        H_hip = self.H(hip)
-        logging.log(logging.ULTRADEBUG, ' nearest known is ' + str(H_hip))
-        if H_hip == self.mapp2p.me:
+        hip = self.H(hip)
+        if hip == self.mapp2p.me:
             # the msg has arrived
-            logging.debug('I have been asked a P2P service, as the nearest to ' + str(hip) + ' (msg=' + str(msg) + ')')
             return self.msg_exec(sender_nip, msg)
 
         # forward the message until it arrives at destination
-        n = self.neigh_get(H_hip)
+        n = self.neigh_get(hip)
         if n:
-            logging.log(logging.ULTRADEBUG, ' through ' + str(n))
-            ret = None
-            execstr = 'ret = n.ntkd.p2p.PID_' + str(self.mapp2p.pid) + '.msg_send(sender_nip, hip, msg)'
-            logging.log(logging.ULTRADEBUG, 'Executing "' + execstr + '" ...')
-            exec(execstr)
-            logging.log(logging.ULTRADEBUG, 'Executed "' + execstr + '". Returning ' + str(ret))
-            return ret
+            exec("return n.ntkd.p2p.PID_" + str(self.mapp2p.pid) +
+                 ".msg_send(sender_nip, hip, msg)")
         else:
-            # Is it possible? Don't we retry?
-            logging.warning('I don\'t know to whom I must forward. Giving up. Raising exception.')
-            logging.warning('This is mapp2p.')
-            logging.warning(self.mapp2p.repr_me())
-            logging.warning('This is maproute.')
-            logging.warning(Map.repr_me(self.maproute))
-            raise Exception('Unreachable P2P destination ' + str(H_hip) + ' from ' + str(self.maproute.me) + '.')
-
-    def call_msg_send_udp(self, neigh, sender_nip, hip, msg):
-        """Use BcastClient to call msg_send"""
-        devs = [neigh.bestdev[0]]
-        nip = self.maproute.ip_to_nip(neigh.ip)
-        netid = neigh.netid
-        return rpc.UDP_call(nip, netid, devs, 'p2p.PID_' + str(self.mapp2p.pid) + '.msg_send_udp', (sender_nip, hip, msg))
-
-    def msg_send_udp(self, _rpc_caller, caller_id, callee_nip, callee_netid, sender_nip, hip, msg):
-        """Returns the result of msg_send to remote caller.
-           caller_id is the random value generated by the caller for this call.
-            It is replied back to the LAN for the caller to recognize a reply destinated to it.
-           callee_nip is the NIP of the callee;
-           callee_netid is the netid of the callee.
-            They are used by the callee to recognize a request destinated to it.
-           """
-        if self.maproute.me == callee_nip and self.neigh.netid == callee_netid:
-            ret = None
-            rpc.UDP_send_keepalive_forever_start(_rpc_caller, caller_id)
-            try:
-                logging.log(logging.ULTRADEBUG, 'calling msg_send...')
-                ret = self.msg_send(sender_nip, hip, msg)
-                logging.log(logging.ULTRADEBUG, 'returning ' + str(ret))
-            except Exception as e:
-                ret = ('rmt_error', e.message)
-                logging.warning('msg_send_udp: returning exception ' + str(ret))
-            finally:
-                rpc.UDP_send_keepalive_forever_stop(caller_id)
-            logging.log(logging.ULTRADEBUG, 'calling UDP_send_reply...')
-            rpc.UDP_send_reply(_rpc_caller, caller_id, ret)
+            return None
 
     def msg_exec(self, sender_nip, msg):
         return self.dispatch(CallerInfo(), *msg)
 
     class RmtPeer(FakeRmt):
-        def __init__(self, p2p, hIP=None, key=None, neigh=None):
+        def __init__(self, p2p, hIP=None, key=None):
             self.p2p = p2p
             self.key = key
             self.hIP = hIP
-            self.neigh = neigh
             FakeRmt.__init__(self)
 
-        def prepare_rmt(self):
-            if self.hIP is None:
-                self.hIP = self.p2p.h(self.key)
-            if self.hIP is None:
-                raise Exception, "'key' does not map to a IP."
-            self.H_hip = self.p2p.H(self.hIP)
-
-        def peer_is_me(self):
-            return self.H_hip == self.p2p.maproute.me
-
-        def peer_get_neigh(self):
-            if self.H_hip is None:
-                return None
-            if self.peer_is_me():
-                raise Exception, "Peer is me. You shouldn't ask for neigh, without checking."
-            return self.p2p.neigh_get(self.H_hip)
-
         def rmt(self, func_name, *params):
             """Overrides FakeRmt.rmt()"""
-            self.prepare_rmt()
-            if self.neigh:
-                # We are requested to use this one as first hop via UDP.
-                logging.log(logging.ULTRADEBUG, 'P2P: Use UDP via ' + str(self.neigh) + ' to reach peer.')
-                return self.p2p.call_msg_send_udp(self.neigh, self.p2p.maproute.me, self.hIP, (func_name, params))
-            else:
-                # Use TCP version.
-                logging.log(logging.ULTRADEBUG, 'P2P: Use TCP to reach peer.')
-                return self.p2p.msg_send(self.p2p.maproute.me, self.hIP, (func_name, params))
+            if self.hIP == None:
+                self.hIP = self.p2p.H(self.p2p.h(self.key))
+            return self.p2p.msg_send(self.p2p.maproute.me,
+                                     self.hIP,
+                                     (func_name, params))
 
-    def peer(self, hIP=None, key=None, neigh=None):
+    def peer(self, hIP=None, key=None):
         if hIP is None and key is None:
-                raise Exception, "hIP and key are both None. Specify at least one"
-        return self.RmtPeer(self, hIP=hIP, key=key, neigh=neigh)
-
+            raise P2PError("hIP and key are both None. Specify at least one")
+        return self.RmtPeer(self, hIP=hIP, key=key)
 
 class P2PAll(object):
     """Class of all the registered P2P services"""
 
-    __slots__ = ['ntkd',
-                 'radar',
+    __slots__ = ['radar',
                  'neigh',
                  'maproute',
                  'service',
                  'remotable_funcs',
-                 'events',
-                 'etp']
+                 'events']
 
-    def __init__(self, ntkd, radar, maproute, etp):
-        self.ntkd = ntkd
-
+    def __init__(self, radar, maproute):
         self.radar = radar
         self.neigh = radar.neigh
         self.maproute = maproute
-        self.etp = etp
 
         self.service = {}
 
         self.remotable_funcs = [self.pid_getall]
-        self.events=Event(['P2P_HOOKED'])
-        ###self.etp.events.listen('HOOKED', self.p2p_hook)
+        self.events = Event(['P2P_HOOKED'])
+
+    def listen_hook_ev(self, hook):
+        hook.events.listen('HOOKED', self.p2p_hook)
 
     def pid_add(self, pid):
-        logging.log(logging.ULTRADEBUG, 'Called P2PAll.pid_add...')
         self.service[pid] = P2P(self.radar, self.maproute, pid)
         return self.service[pid]
 
 
     def pid_getall(self):
         return [(s, self.service[s].mapp2p.map_data_pack())
-                        for s in self.service]
-
+                    for s in self.service]
 
     def p2p_register(self, p2p):
         """Used to add for the first time a P2P instance of a module in the
            P2PAll dictionary."""
 
-        logging.log(logging.ULTRADEBUG, 'Called P2PAll.p2p_register for ' + str(p2p.pid) + '...')
         # It's possible that the stub P2P instance self.pid_get(p2p.pid)'
         # created by pid_add() has an update map of participants, which has
         # been accumulated during the time. Copy this map in the p2p'
         # instance to be sure.
-        if p2p.pid in self.service:
-            logging.log(logging.ULTRADEBUG, 'Called P2PAll.p2p_register for ' + str(p2p.pid) + '... cloning...')
-            map_pack = self.pid_get(p2p.pid).mapp2p.map_data_pack()
-            p2p.mapp2p.map_data_merge(map_pack)
+        map_pack = self.pid_get(p2p.pid).mapp2p.map_data_pack()
+        p2p.mapp2p.map_data_merge(map_pack)
         self.service[p2p.pid] = p2p
 
-    #  TODO  DELETED. Ok?
-    #def participant_add(self, pid, pIP):
-    #    self.pid_get(pid).participant_add(pIP)
+    def participant_add(self, pid, pIP):
+        self.pid_get(pid).participant_add(pIP)
 
     @microfunc()
     def p2p_hook(self, *args):
 
         It gets the P2P maps from our nearest neighbour"""
 
-        logging.log(logging.ULTRADEBUG, 'P2P hooking: started')
-        logging.log(logging.ULTRADEBUG, 'P2P hooking: My actual list of services is: ' + str(self.log_services()))
         ## Find our nearest neighbour
-        neighs_in_net = self.neigh.neigh_list(in_my_network=True)
-        while True:
-            minlvl = self.maproute.levels
-            minnr = None
-            for nr in neighs_in_net:
-                lvl = self.maproute.nip_cmp(self.maproute.me, nr.nip)
-                if lvl < minlvl:
-                    minlvl = lvl
-                    minnr  = nr
-            ##
+        minlvl = self.maproute.levels
+        minnr = None
+        for nr in self.neigh.neigh_list():
+            lvl = self.maproute.nip_cmp(self.maproute.me,
+                                        self.maproute.ip_to_nip(nr.ip))
+            if lvl < minlvl:
+                minlvl = lvl
+                minnr  = nr
+        ##
 
-            if minnr is None:
-                # nothing to do
-                logging.log(logging.ULTRADEBUG, 'P2P hooking: No neighbours to ask for the list of services.')
-                break
+        if minnr == None:
+            # nothing to do
+            return
 
-            logging.log(logging.ULTRADEBUG, 'P2P hooking: I will ask for the list of services to ' + str(minnr))
-            try:
-                nrmaps_pack = minnr.ntkd.p2p.pid_getall()
-            except:
-                logging.warning('P2P hooking: Asking to ' + str(minnr) + ' failed.')
-                neighs_in_net.remove(minnr)
-                continue
-            logging.log(logging.ULTRADEBUG, 'P2P hooking: ' + str(minnr) + ' answers ' + str(nrmaps_pack))
-            for (pid, map_pack) in nrmaps_pack:
-                self.pid_get(pid).mapp2p.map_data_merge(map_pack)
+        nrmaps_pack = minnr.ntkd.p2p.pid_getall()
+        for (pid, map_pack) in nrmaps_pack:
+            self.pid_get(pid).mapp2p.map_data_merge(map_pack)
 
-            for s in self.service:
-                    if self.service[s].participant:
-                            self.service[s].participate()
-            logging.log(logging.ULTRADEBUG, 'P2P hooking: My final list of services is: ' + str(self.log_services()))
-            break
+        for s in self.service:
+            if self.service[s].participant:
+                self.service[s].participate()
 
         self.events.send('P2P_HOOKED', ())
 
         if str[:4] == "PID_":
             return self.pid_get(int(str[4:]))
         raise AttributeError
-
-    def log_services(self):
-        return [(s, self.service[s].mapp2p.repr_me())
-                        for s in self.service]
-

# File pyntk/ntk/core/qspn.py

• Ignore whitespace
 from ntk.lib.event import Event
 from ntk.lib.micro import microfunc
 
-from ntk.config import settings
-
 def is_listlist_empty(l):
     """Returns true if l=[[],[], ...]
     :type l: a list of lists.
         for block in reversed(TPL):
                 lvl=block[0]
                 for dst, rem in reversed(block[1]):
-                        # Ok, we can reach dst' through gw'. Is it really
-                        # worth doing? If it is better than the known route,
-                        # then yes! So, let's use route_change to check.
                         if self.maproute.route_change(lvl, dst, gw, tprem):
                                 TPL_is_interesting = True
                         tprem+=rem # TODO: sometimes rem is an integer
         ## Update the map from R
         for lvl in xrange(self.maproute.levels):
                 for dst, rem in R[lvl]:
-                        # Ok, the ETP is telling us that the best way to reach
-                        # dst' through gw' is rem+tprem'.
-                        # So, if we have already such route, let's update its
-                        # rem, otherwise let's create it.
                         if not self.maproute.route_rem(lvl, dst, gw, rem+tprem):
                                 self.maproute.route_change(lvl, dst, gw, rem+tprem)
         ##

         # uhm... we are in different networks

-        ### Calculate the size of the two nets
-        lvl = self.maproute.nip_cmp(self.maproute.me, gwnip)
-        mynetsz=self.maproute.node_nb[lvl]
-        # TODO/TOCHECK: we are supposing that we are processing a new-link
-        # ETP, so that R[lvl] contains all the routes of level lvl' of the
-        # neigh's network. Thus, to count its size we simply do as follow:
-        ngnetsz=len(R[lvl])
-
-        #NOTE: assuming that the communicating vessel system is working well,
-        #      to compare the size of the two network it is sufficient to
-        #      compare the number of gnodes of level lvl'
-        ###
+        ## Calculate the size of the two nets
+        mynetsz = reduce(add, self.maproute.node_nb)
+        ngnetsz = reduce(add, map(len, R))

         if mynetsz > ngnetsz or \
            (mynetsz == ngnetsz and self.radar.netid > neigh.netid):

         ## Check if we are colliding with another (g)node of the neighbour
         ## net
-        level = self.maproute.nip_cmp(self.maproute.me, gwnip)
-        if level+1 < self.maproute.levels:
+        level = self.maproute.nip_cmp(self.maproute.me, gwnip) + 1
+        if level < self.maproute.levels:
             for dst, rem in R[level]:
                 if dst == self.maproute.me[level]:
                     # we are colliding! LET'S REHOOK
                 self.maproute.node_get(lvl, dst).route_reset()
         ##

-        ##TODO: uncomment this!
-        ##From now on, we are in the new net
-        ##logging.info('From now on, we are in the new net, our network id: %s' % neigh.netid)
-        ##self.ntkd.neighbour.netid = neigh.netid
-        ##self.events.send('COMPLETE_HOOK', ())
-
         return (False, R)

• Ignore whitespace

 from random import randint

-import time
 import ntk.lib.rpc as rpc
 import ntk.wrap.xtime as xtime

-import ntk.lib.rpc as rpc
 from ntk.config import settings
 from ntk.core.route import DeadRem, Rtt
 from ntk.lib.event import Event
 from ntk.lib.log import logger as logging
-from ntk.lib.micro import micro, micro_block, microfunc, Channel
+from ntk.lib.micro import micro
 from ntk.network.inet import ip_to_str, str_to_ip
-from ntk.lib.log import get_stackframes, log_exception_stacktrace


 class Neigh(object):

     __slots__ = ['devs', 'bestdev', 'ip', 'nip', 'id', 'rem', 'ntkd', 'netid']

-    def __init__(self, bestdev, devs, ip, netid,
-                 id=None, ntkd=None, nip=None):
+    def __init__(self, bestdev, devs, idn=None,
+                 ip=None, netid=None, ntkd=None):
         """
         ip: neighbour's ip;
-        netid: network id of the node
-              ip + netid = unique key.
+        nip: neighbour's nip;
+        ntkd: neighbour's ntk remote instance
+        idn: neighbour's id; use Neighbour.ip_to_id to create it
         devs: a dict which maps a device to the average rtt
         bestdev: a pair (d, avg_rtt), where devs[d] is the best element of
                 devs.
-
-        nip: neighbour's nip;
-        ntkd: neighbour's ntk remote instance
-        id: neighbour's id; use Neighbour.key_to_id to create it
+        netid: network id of the node
         """

         self.devs = devs
         self.bestdev = bestdev
+
         self.ip = ip
-        self.netid = netid
-
-        self.nip = nip
-        self.id = id
+        self.nip = None
+        self.id = idn
         if self.bestdev:
             # TODO(low): support the other metrics
             self.rem = Rtt(self.bestdev[1])
         else:
             self.rem = DeadRem() # The neighbour is dead
         self.ntkd = ntkd
+        self.netid = netid

     def __cmp__(self, b):
-        stacktrace = get_stackframes(back=1)
-        logging.warning('Neigh.__cmp__ called at ' + stacktrace)
         return (self.ip > b.ip) - (self.ip < b.ip)

     def __repr__(self):
-        if not self.ip: return object.__repr__(self)
-        if not self.rem: return '<Neighbour(%s in %s): No rem>' % (ip_to_str(self.ip), self.netid)
-        return '<Neighbour(%s in %s):%s>' % (ip_to_str(self.ip), self.netid, self.rem)
+        return '<Neighbour(%s):%s>' % (ip_to_str(self.ip), self.rem)

     def values(self):
         '''Returns a dict rappresentation of the neighbour
                                checks
         '''
         v = [(name, getattr(self, name)) for name in self.__slots__
-             if name != 'ntkd']
+                                            if name != 'ntkd']
         return dict(v)

 class Neighbour(object):
     """ This class manages all neighbours """

-    __slots__ = ['ntkd',
-                 'max_neigh',
+    __slots__ = ['max_neigh',
                  'rtt_variation_threshold',
-                 'ip_netid_table',
+                 'ip_table',
                  'ntk_client',
                  'translation_table',
-                 'reverse_translation_table',
+                 'netid_table',
                  'events',
                  'remotable_funcs',
-                 'xtime',
-                 'netid',
-                 'increment_wait_time',
-                 'number_of_scan_before_deleting',
-                 'missing_neighbour_keys',
-                 'channels']
+                 'xtime']

-    def __init__(self, ntkd, max_neigh=settings.MAX_NEIGH, xtimemod=xtime):
+    def __init__(self, max_neigh=settings.MAX_NEIGH, xtimemod=xtime):
         """  max_neigh: maximum number of neighbours we can have """
-        self.ntkd = ntkd

         self.max_neigh = max_neigh
         # variation on neighbours' rtt greater than this will be notified
-        # TODO changed to do less variations in netkit environment
-        #self.rtt_variation_threshold = 0.1
-        self.rtt_variation_threshold = 0.9
-        # ip_netid_table
-        # This is a dict whose key is a pair (ip, netid), that is the unique
-        # identifier of a neighbour node. The same ip could be assigned to two
-        # or more neighbours if they are from different networks.
-        # The values of this dict are instances of Neigh. The minimum attributes
-        # are valorized (bestdev, devs, ip, netid).
-        self.ip_netid_table = {}
-        # ntk_client
-        # This is a dict mapping an ip to a TCPClient instance. Only neighbours
-        # that are in our same network have a TCPClient, so netid is not in
-        # the key.
-        self.ntk_client = {}
-        # (ip, netid) => ID translation table
+        self.rtt_variation_threshold = 0.1
+        # ip_table
+        self.ip_table = {}
+        # Remote client instances table
+        self.ntk_client = {}  # ip : rpc.TCPClient(ipstr)
+        # IP => ID translation table
         self.translation_table = {}
-        # ID => (ip, netid) reverse translation table
-        self.reverse_translation_table = {}
+        # IP => netid
+        self.netid_table = {}
         # the events we raise
-        self.events = Event(['NEIGH_NEW', 'NEIGH_DELETED', 'NEIGH_REM_CHGED',
-                      'COLLIDING_NEIGH_NEW', 'COLLIDING_NEIGH_DELETED',
-                      'COLLIDING_NEIGH_REM_CHGED'])
+        self.events = Event(['NEIGH_NEW', 'NEIGH_DELETED', 'NEIGH_REM_CHGED'])
         # time module
         self.xtime = xtimemod
-        # channels for the methods to synchronize routes in the kernel table
-        self.channels = [None] * max_neigh

-        # Our netid. It's a random id used to detect network collisions.
-        self.netid = -1
+        self.remotable_funcs = [self.ip_change]

-        # To be certain, before deleting a neighbour, check a few times with
-        # a greater delay.
-        self.increment_wait_time = 1000
-        self.number_of_scan_before_deleting = 3
-        # This is a dict. The key is the neigh id, the value is missing_scans.
-        # e.g. {2:4} means neighbour 2 has not replied for 4 consecutive
-        # scans.
-        self.missing_neighbour_keys = {}
-
-        self.remotable_funcs = [self.ip_netid_change,
-                                self.ip_netid_change_udp,
-                                self.ip_netid_change_broadcast_udp]
-        self.monitor_neighbours()
-
-    @microfunc(True)
-    def monitor_neighbours(self):
-        while True:
-            xtime.swait(100)
-            known_neighs = '{'
-            for ip, netid in self.ip_netid_table:
-                nip = self.ntkd.maproute.ip_to_nip(ip)
-                known_neighs += '(' + str(nip) + ',' + str(netid) + ')  '
-            known_neighs += '}'
-            logging.log(logging.ULTRADEBUG, 'monitor_neighbours: DELETETHISLOG - Known Neighbours: ' + known_neighs)
-
-    def neigh_list(self, in_my_network=False, out_of_my_network=False,
-                         in_this_netid=None, out_of_this_netid=None):
-        """ Returns the list of neighbours.
-            If in_my_network == True, then returns only nodes
-              that are in my network.
-            Else, if out_of_my_network == True, then returns only nodes
-              that are NOT in my network.
-            Else, if in_this_netid is not None, then returns only nodes
-              that are in the network with this netid.
-            Else, if out_of_this_netid is not None, then returns only nodes
-              that are NOT in the network with this netid.
-            Else all the neighbours are returned.
-            netid == -1 is a special case. It is not in any network.
-            So, in_this_netid=-1 is a non-sense, but will simply return
-            a void list.
-            On the other hand, out_of_this_netid=-1 will return all the
-            neighbours.
-        """
-        # ATTENTION: this method MUST NOT pass schedule while
-        # gathering data from the structures.
-
-        def in_my_network_requirement(netid):
-            if netid == -1:
-                return False
-            return netid == self.netid
-        def out_of_my_network_requirement(netid):
-            if netid == -1:
-                return True
-            return netid != self.netid
-        def in_this_netid_requirement(netid):
-            if netid == -1:
-                return False
-            return netid == in_this_netid
-        def out_of_this_netid_requirement(netid):
-            if netid == -1:
-                return True
-            return netid != in_this_netid
-        def no_requirements(netid):
-            return True
-
-        requirement = no_requirements
-        if in_my_network:
-            requirement = in_my_network_requirement
-        elif out_of_my_network:
-            requirement = out_of_my_network_requirement
-        elif in_this_netid is not None:
-            requirement = in_this_netid_requirement
-        elif out_of_this_netid is not None:
-            requirement = out_of_this_netid_requirement
-
+    def neigh_list(self):
+        """ return the list of neighbours """
         nlist = []
-        for key, val in self.ip_netid_table.items():
-            ip, netid = key
-            if not requirement(netid):
-                # this one is not wanted
-                continue
-            logging.log(logging.ULTRADEBUG, 'neigh_list: preparing Neigh for nip ' + str(self.ntkd.maproute.ip_to_nip(ip)) + ', netid ' + str(netid))
+        for key, val in self.ip_table.items():
             nlist.append(Neigh(bestdev=val.bestdev,
                                devs=val.devs,
-                               ip=ip,
-                               netid=netid,
-                               id=self.translation_table[key],
-                               ntkd=self.get_ntk_client(ip, netid),
-                               nip=self.ntkd.maproute.ip_to_nip(ip)))
+                               idn=self.translation_table[key],
+                               ip=key,
+                               netid=self.netid_table[key],
+                               ntkd=self.ntk_client[key]))
         return nlist

-    def memorize(self, key, bestdev, devs):
-        """ key: pair ip, netid
-            key should not be already in translation table.
-            Inserts this neighbour in our data structures. Returns the assigned id.
-            If there is no more room, sends an exception.
+    def ip_to_id(self, ipn):
+        """ if ipn is in the translation table, return the associated id;
+            if it isn't, insert it into the translation table assigning a new id,
+            if the table isn't full
         """
-        # ATTENTION: this method MUST NOT pass schedule until the end.
-        if key in self.translation_table:
-            raise Exception('Key was already present.')
-        # Find the first available id in reverse_translation_table
-        new_id = False
-        for i in xrange(1, self.max_neigh + 1):
-            if i not in self.reverse_translation_table:
-                new_id = i
-                break
-        if not new_id:
-            raise Exception('Max Neigh Exceeded')
-        self.translation_table[key] = new_id
-        self.reverse_translation_table[new_id] = key
-        ip, netid = key
-        self.ip_netid_table[key] = Neigh(bestdev=bestdev,
-                                         devs=devs,
-                                         ip=ip,
-                                         netid=netid)
-        if self.netid == netid:
-            # It's in my network
-            self.ntk_client[ip] = rpc.TCPClient(ip_to_str(ip))

-    def unmemorize(self, key):
-        """ key: pair ip, netid
-            key should be in translation table.
-            Removes this neighbour in our data structures.
-            Returns old id.
+        if ipn in self.translation_table:
+            return self.translation_table[ipn]
+        new_id = self._find_hole_in_tt()
+        if new_id:
+            self.translation_table[ipn] = new_id
+            return new_id
+        else:
+            return False
+
+    def ip_to_neigh(self, ip):
+        """ ip: neighbour's ip
+            return a Neigh object from an ip
         """
-        # ATTENTION: this method MUST NOT pass schedule until the end.
-        if key not in self.translation_table:
-            raise Exception('Key was not present.')
-        id = self.translation_table[key]
-        ip, netid = key
-        del self.translation_table[key]
-        del self.reverse_translation_table[id]
-        del self.ip_netid_table[key]
-        if self.netid == netid:
-            # It was in my network
-            del self.ntk_client[ip]
-        return id
-
-    #############################################################
-    ######## Synchronization gateway <-> nodes
-    # Abstract:
-    #
-    # When Neighbour notice a new neighbour (gateway) it calls announce_gw.
-    # Then, Neighbour emits event NEIGH_NEW which in turn does other
-    # things...
-    # When KrnlRoute actually has added the route towards the gateway,
-    # it calls announce_gw_added.
-    #
-    # When Neighbour notice a dead link towards a neighbour it calls
-    # announce_gw_removing.
-    # Then, Neighbour emits event NEIGH_DELETED which in turn does other
-    # things...
-    # When MapRoute.routeneigh_del has finished deleting all the
-    # routes passing through it, it calls announce_gw_removable.
-    #
-    # Before actually adding a route through a gateway we must
-    # call waitfor_gw_added.
-    # Before actually removing the route towards a gateway we
-    # must call waitfor_gw_removable.
-    #
-    # This way we ensure to add a gateway before adding routes
-    # through it, and to remove routes through a gateway before
-    # removing the gateway itself.
-
-    def announce_gw(self, gwid):
-        # This place should be void and nobody should be receiving
-        # in it, but just to be sure:
-        channel = self.channels[gwid-1]
-        if channel is not None:
-            channel.bcast_send('')
-            micro_block()
-        # Now the real announce.
-        self.channels[gwid-1] = Channel(prefer_sender=True)
-
-    def waitfor_gw_added(self, gwid):
-        channel = self.channels[gwid-1]
-        if channel is None: return
-        channel.recv()
-
-    def announce_gw_added(self, gwid):
-        channel = self.channels[gwid-1]
-        if channel is None: return
-        channel.bcast_send('')
-        micro_block()
-        self.channels[gwid-1] = None
-
-    def announce_gw_removing(self, gwid):
-        # This place should be void and nobody should be receiving
-        # in it, but just to be sure:
-        channel = self.channels[gwid-1]
-        if channel is not None:
-            channel.bcast_send('')
-            micro_block()
-        # Now the real announce.
-        self.channels[gwid-1] = Channel(prefer_sender=True)
-
-    def waitfor_gw_removable(self, gwid):
-        channel = self.channels[gwid-1]
-        if channel is None: return
-        channel.recv()
-
-    def announce_gw_removable(self, gwid):
-        channel = self.channels[gwid-1]
-        if channel is None: return
-        channel.bcast_send('')
-        micro_block()
-        self.channels[gwid-1] = None
-
-    ##
-    #############################################################
-
-    def get_ntk_client(self, ip, netid):
-        """ip: neighbour's ip;
-           netid: neighbour's netid."""
-        if netid == self.netid:
-            if ip in self.ntk_client:
-                return self.ntk_client[ip]
-            else:
-                logging.log(logging.ULTRADEBUG, 'Neighbour.get_ntk_client: not present for ip ' + str(ip) + ', netid ' + str(netid))
-                return None
-        else:
-            return None
-
-    def key_to_neigh(self, key):
-        """ key: neighbour's key, that is the pair ip, netid
-            return a Neigh object from its ip and netid
-        """
-        if key not in self.translation_table:
+        if ip not in self.translation_table:
             return None
         else:
-            ip, netid = key
-            val = self.ip_netid_table[key]
-            return Neigh(bestdev=val.bestdev,
-                        devs=val.devs,
-                        ip=ip,
-                        netid=netid,
-                        id=self.translation_table[key],
-                        ntkd=self.get_ntk_client(ip, netid),
-                        nip=self.ntkd.maproute.ip_to_nip(ip))
+            return Neigh(bestdev=self.ip_table[ip].bestdev,
+                         devs=self.ip_table[ip].devs,
+                         idn=self.translation_table[ip],
+                         ip=ip,
+                         netid=self.netid_table[ip],
+                         ntkd=self.ntk_client[ip])

-    def key_to_id(self, key):
-        """ key: neighbour's key, that is the pair ip, netid
-            Returns the id of that neighbour. It should be present.
+    def id_to_ip(self, id):
+        """Returns the IP associated to id'.
+        If not found, returns None
         """
-        if key not in self.translation_table:
-            raise Exception('Key was not present.')
-        return self.translation_table[key]
-
-    def id_to_key(self, id):
-        """Returns the key (ip, netid) associated to id'.
-        id should be in reverse_translation_table.
-        """
-        if id not in self.reverse_translation_table:
-            raise Exception('ID was not present.')
-        return self.reverse_translation_table[id]
+        for ip in self.translation_table:
+            if self.translation_table[ip] == id:
+                return ip
+        return None

     def id_to_neigh(self, id):
-        """Returns a Neigh object from an id.
-        id should be in reverse_translation_table.
-        """
-        return self.key_to_neigh(self.id_to_key(id))
+        """Returns a Neigh object from an id"""
+        return self.ip_to_neigh(self.id_to_ip(id))

-    def _truncate(self, ip_netid_table):
-        """ip_netid_table: an {(ip, netid) => Neigh};
+    def _truncate(self, ip_table):
+        """ip_table: an {IP => NodeInfo};
         we want the best (with the lowest rtt) max_neigh nodes only to
         remain in the table
         """

-        # auxiliary function, to take rtt from {(ip, netid) => Neigh}
+        # auxiliary function, to take rtt from {IP => NodeInfo}
         def interesting(x):
             return x[1].bestdev[1]