Modified: qpid/dispatch/trunk/src/router_pynode.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/router_pynode.c?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/router_pynode.c (original)
+++ qpid/dispatch/trunk/src/router_pynode.c Wed Jan 21 15:22:57 2015
@@ -43,151 +43,200 @@ typedef struct {
 } RouterAdapter;
 
 
-static char *qd_add_router(qd_router_t *router, const char *address, int 
router_maskbit, int link_maskbit)
+static PyObject *qd_add_router(PyObject *self, PyObject *args)
 {
-    if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0)
-        return "Router bit mask out of range";
-
-    if (link_maskbit >= qd_bitmask_width() || link_maskbit < -1)
-        return "Link bit mask out of range";
+    RouterAdapter *adapter = (RouterAdapter*) self;
+    qd_router_t   *router  = adapter->router;
+    const char    *address;
+    int            router_maskbit;
+    char          *error = 0;
 
-    sys_mutex_lock(router->lock);
-    if (router->routers_by_mask_bit[router_maskbit] != 0) {
-        sys_mutex_unlock(router->lock);
-        return "Adding router over already existing router";
-    }
+    if (!PyArg_ParseTuple(args, "si", &address, &router_maskbit))
+        return 0;
 
-    if (link_maskbit >= 0 && router->out_links_by_mask_bit[link_maskbit] == 0) 
{
-        sys_mutex_unlock(router->lock);
-        return "Adding neighbor router with invalid link reference";
-    }
+    do {
+        if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
+            error = "Router bit mask out of range";
+            break;
+        }
 
-    //
-    // Hash lookup the address to ensure there isn't an existing router 
address.
-    //
-    qd_field_iterator_t *iter = qd_field_iterator_string(address, 
ITER_VIEW_ADDRESS_HASH);
-    qd_address_t        *addr;
+        sys_mutex_lock(router->lock);
+        if (router->routers_by_mask_bit[router_maskbit] != 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Adding router over already existing router";
+            break;
+        }
 
-    qd_hash_retrieve(router->addr_hash, iter, (void**) &addr);
-    assert(addr == 0);
+        //
+        // Hash lookup the address to ensure there isn't an existing router 
address.
+        //
+        qd_field_iterator_t *iter = qd_field_iterator_string(address, 
ITER_VIEW_ADDRESS_HASH);
+        qd_address_t        *addr;
+
+        qd_hash_retrieve(router->addr_hash, iter, (void**) &addr);
+        assert(addr == 0);
+
+        //
+        // Create an address record for this router and insert it in the hash 
table.
+        // This record will be found whenever a "foreign" topological address 
to this
+        // remote router is looked up.
+        //
+        addr = qd_address();
+        addr->semantics = router_addr_semantics;
+        qd_hash_insert(router->addr_hash, iter, addr, &addr->hash_handle);
+        DEQ_INSERT_TAIL(router->addrs, addr);
+        qd_entity_cache_add(QD_ROUTER_ADDRESS_TYPE, addr);
+        qd_field_iterator_free(iter);
 
-    //
-    // Create an address record for this router and insert it in the hash 
table.
-    // This record will be found whenever a "foreign" topological address to 
this
-    // remote router is looked up.
-    //
-    addr = qd_address();
-    addr->semantics = router_addr_semantics;
-    qd_hash_insert(router->addr_hash, iter, addr, &addr->hash_handle);
-    DEQ_INSERT_TAIL(router->addrs, addr);
-    qd_entity_cache_add(QD_ROUTER_ADDRESS_TYPE, addr);
-    qd_field_iterator_free(iter);
+        //
+        // Create a router-node record to represent the remote router.
+        //
+        qd_router_node_t *rnode = new_qd_router_node_t();
+        DEQ_ITEM_INIT(rnode);
+        rnode->owning_addr   = addr;
+        rnode->mask_bit      = router_maskbit;
+        rnode->next_hop      = 0;
+        rnode->peer_link     = 0;
+        rnode->ref_count     = 0;
+        rnode->valid_origins = qd_bitmask(0);
+
+        DEQ_INSERT_TAIL(router->routers, rnode);
+        qd_entity_cache_add(QD_ROUTER_NODE_TYPE, rnode);
+
+        //
+        // Link the router record to the address record.
+        //
+        qd_router_add_node_ref_LH(&addr->rnodes, rnode);
+
+        //
+        // Link the router record to the router address records.
+        //
+        qd_router_add_node_ref_LH(&router->router_addr->rnodes, rnode);
+        qd_router_add_node_ref_LH(&router->routerma_addr->rnodes, rnode);
+
+        //
+        // Add the router record to the mask-bit index.
+        //
+        router->routers_by_mask_bit[router_maskbit] = rnode;
 
-    //
-    // Create a router-node record to represent the remote router.
-    //
-    qd_router_node_t *rnode = new_qd_router_node_t();
-    DEQ_ITEM_INIT(rnode);
-    rnode->owning_addr   = addr;
-    rnode->mask_bit      = router_maskbit;
-    rnode->next_hop      = 0;
-    rnode->peer_link     = 0;
-    rnode->ref_count     = 0;
-    rnode->valid_origins = qd_bitmask(0);
+        sys_mutex_unlock(router->lock);
+    } while (0);
 
-    DEQ_INSERT_TAIL(router->routers, rnode);
-    qd_entity_cache_add(QD_ROUTER_NODE_TYPE, rnode);
+    if (error) {
+        PyErr_SetString(PyExc_Exception, error);
+        return 0;
+    }
 
-    //
-    // Link the router record to the address record.
-    //
-    qd_router_add_node_ref_LH(&addr->rnodes, rnode);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
 
-    //
-    // Link the router record to the router address record.
-    //
-    qd_router_add_node_ref_LH(&router->router_addr->rnodes, rnode);
 
-    //
-    // Add the router record to the mask-bit index.
-    //
-    router->routers_by_mask_bit[router_maskbit] = rnode;
+static PyObject* qd_del_router(PyObject *self, PyObject *args)
+{
+    RouterAdapter *adapter = (RouterAdapter*) self;
+    qd_router_t   *router  = adapter->router;
+    int router_maskbit;
+    char *error = 0;
 
-    //
-    // If this is a neighbor router, add the peer_link reference to the
-    // router record.
-    //
-    if (link_maskbit >= 0)
-        rnode->peer_link = router->out_links_by_mask_bit[link_maskbit];
+    if (!PyArg_ParseTuple(args, "i", &router_maskbit))
+        return 0;
 
-    sys_mutex_unlock(router->lock);
-    return 0;
-}
+    do {
+        if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
+            error = "Router bit mask out of range";
+            break;
+        }
 
+        sys_mutex_lock(router->lock);
+        if (router->routers_by_mask_bit[router_maskbit] == 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Deleting nonexistent router";
+            break;
+        }
 
-static char *qd_del_router(qd_router_t *router, int router_maskbit)
-{
-    if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0)
-        return "Router bit mask out of range";
+        qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit];
+        qd_address_t     *oaddr = rnode->owning_addr;
+        assert(oaddr);
 
-    sys_mutex_lock(router->lock);
-    if (router->routers_by_mask_bit[router_maskbit] == 0) {
-        sys_mutex_unlock(router->lock);
-        return "Deleting nonexistent router";
-    }
+        qd_entity_cache_remove(QD_ROUTER_ADDRESS_TYPE, oaddr);
+        qd_entity_cache_remove(QD_ROUTER_NODE_TYPE, rnode);
 
-    qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit];
-    qd_address_t     *oaddr = rnode->owning_addr;
-    assert(oaddr);
+        //
+        // Unlink the router node from the address record
+        //
+        qd_router_del_node_ref_LH(&oaddr->rnodes, rnode);
+
+        //
+        // While the router node has a non-zero reference count, look for 
addresses
+        // to unlink the node from.
+        //
+        qd_address_t *addr = DEQ_HEAD(router->addrs);
+        while (addr && rnode->ref_count > 0) {
+            qd_router_del_node_ref_LH(&addr->rnodes, rnode);
+            addr = DEQ_NEXT(addr);
+        }
+        assert(rnode->ref_count == 0);
 
-    qd_entity_cache_remove(QD_ROUTER_ADDRESS_TYPE, oaddr);
-    qd_entity_cache_remove(QD_ROUTER_NODE_TYPE, rnode);
+        //
+        // Free the router node and the owning address records.
+        //
+        qd_bitmask_free(rnode->valid_origins);
+        DEQ_REMOVE(router->routers, rnode);
+        free_qd_router_node_t(rnode);
+
+        qd_hash_remove_by_handle(router->addr_hash, oaddr->hash_handle);
+        DEQ_REMOVE(router->addrs, oaddr);
+        qd_hash_handle_free(oaddr->hash_handle);
+        router->routers_by_mask_bit[router_maskbit] = 0;
+        free_qd_address_t(oaddr);
 
-    //
-    // Unlink the router node from the address record
-    //
-    qd_router_del_node_ref_LH(&oaddr->rnodes, rnode);
+        sys_mutex_unlock(router->lock);
+    } while(0);
 
-    //
-    // While the router node has a non-zero reference count, look for addresses
-    // to unlink the node from.
-    //
-    qd_address_t *addr = DEQ_HEAD(router->addrs);
-    while (addr && rnode->ref_count > 0) {
-        qd_router_del_node_ref_LH(&addr->rnodes, rnode);
-        addr = DEQ_NEXT(addr);
+    if (error) {
+        PyErr_SetString(PyExc_Exception, error);
+        return 0;
     }
-    assert(rnode->ref_count == 0);
 
-    //
-    // Free the router node and the owning address records.
-    //
-    qd_bitmask_free(rnode->valid_origins);
-    DEQ_REMOVE(router->routers, rnode);
-    free_qd_router_node_t(rnode);
-
-    qd_hash_remove_by_handle(router->addr_hash, oaddr->hash_handle);
-    DEQ_REMOVE(router->addrs, oaddr);
-    qd_hash_handle_free(oaddr->hash_handle);
-    router->routers_by_mask_bit[router_maskbit] = 0;
-    free_qd_address_t(oaddr);
-
-    sys_mutex_unlock(router->lock);
-    return 0;
+    Py_INCREF(Py_None);
+    return Py_None;
 }
 
 
-static PyObject* qd_add_remote_router(PyObject *self, PyObject *args)
+static PyObject* qd_set_link(PyObject *self, PyObject *args)
 {
     RouterAdapter *adapter = (RouterAdapter*) self;
     qd_router_t   *router  = adapter->router;
-    const char    *address;
     int            router_maskbit;
+    int            link_maskbit;
+    char          *error = 0;
 
-    if (!PyArg_ParseTuple(args, "si", &address, &router_maskbit))
+    if (!PyArg_ParseTuple(args, "ii", &router_maskbit, &link_maskbit))
         return 0;
 
-    char *error = qd_add_router(router, address, router_maskbit, -1);
+    do {
+        if (link_maskbit >= qd_bitmask_width() || link_maskbit < 0) {
+            error = "Link bit mask out of range";
+            break;
+        }
+
+        sys_mutex_lock(router->lock);
+        if (router->out_links_by_mask_bit[link_maskbit] == 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Adding neighbor router with invalid link reference";
+            break;
+        }
+
+        //
+        // Add the peer_link reference to the router record.
+        //
+        qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit];
+        rnode->peer_link = router->out_links_by_mask_bit[link_maskbit];
+
+        sys_mutex_unlock(router->lock);
+    } while (0);
+
     if (error) {
         PyErr_SetString(PyExc_Exception, error);
         return 0;
@@ -198,16 +247,23 @@ static PyObject* qd_add_remote_router(Py
 }
 
 
-static PyObject* qd_del_remote_router(PyObject *self, PyObject *args)
+static PyObject* qd_remove_link(PyObject *self, PyObject *args)
 {
     RouterAdapter *adapter = (RouterAdapter*) self;
     qd_router_t   *router  = adapter->router;
-    int router_maskbit;
+    int            router_maskbit;
+    char          *error = 0;
 
     if (!PyArg_ParseTuple(args, "i", &router_maskbit))
         return 0;
 
-    char *error = qd_del_router(router, router_maskbit);
+    do {
+        sys_mutex_lock(router->lock);
+        qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit];
+        rnode->peer_link = 0;
+        sys_mutex_unlock(router->lock);
+    } while (0);
+
     if (error) {
         PyErr_SetString(PyExc_Exception, error);
         return 0;
@@ -224,33 +280,45 @@ static PyObject* qd_set_next_hop(PyObjec
     qd_router_t   *router  = adapter->router;
     int            router_maskbit;
     int            next_hop_maskbit;
+    char          *error = 0;
 
     if (!PyArg_ParseTuple(args, "ii", &router_maskbit, &next_hop_maskbit))
         return 0;
 
-    if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
-        PyErr_SetString(PyExc_Exception, "Router bit mask out of range");
-        return 0;
-    }
+    do {
+        if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
+            error = "Router bit mask out of range";
+            break;
+        }
 
-    if (next_hop_maskbit >= qd_bitmask_width() || next_hop_maskbit < 0) {
-        PyErr_SetString(PyExc_Exception, "Next Hop bit mask out of range");
-        return 0;
-    }
+        if (next_hop_maskbit >= qd_bitmask_width() || next_hop_maskbit < 0) {
+            error = "Next Hop bit mask out of range";
+            break;
+        }
 
-    if (router->routers_by_mask_bit[router_maskbit] == 0) {
-        PyErr_SetString(PyExc_Exception, "Router Not Found");
-        return 0;
-    }
+        sys_mutex_lock(router->lock);
+        if (router->routers_by_mask_bit[router_maskbit] == 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Router Not Found";
+            break;
+        }
 
-    if (router->routers_by_mask_bit[next_hop_maskbit] == 0) {
-        PyErr_SetString(PyExc_Exception, "Next Hop Not Found");
-        return 0;
-    }
+        if (router->routers_by_mask_bit[next_hop_maskbit] == 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Next Hop Not Found";
+            break;
+        }
 
-    if (router_maskbit != next_hop_maskbit) {
-        qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit];
-        rnode->next_hop = router->routers_by_mask_bit[next_hop_maskbit];
+        if (router_maskbit != next_hop_maskbit) {
+            qd_router_node_t *rnode = 
router->routers_by_mask_bit[router_maskbit];
+            rnode->next_hop = router->routers_by_mask_bit[next_hop_maskbit];
+        }
+        sys_mutex_unlock(router->lock);
+    } while (0);
+
+    if (error) {
+        PyErr_SetString(PyExc_Exception, error);
+        return 0;
     }
 
     Py_INCREF(Py_None);
@@ -258,55 +326,38 @@ static PyObject* qd_set_next_hop(PyObjec
 }
 
 
-static PyObject* qd_set_valid_origins(PyObject *self, PyObject *args)
+static PyObject* qd_remove_next_hop(PyObject *self, PyObject *args)
 {
     RouterAdapter *adapter = (RouterAdapter*) self;
     qd_router_t   *router  = adapter->router;
     int            router_maskbit;
-    PyObject      *origin_list;
-    Py_ssize_t     idx;
-
-    if (!PyArg_ParseTuple(args, "iO", &router_maskbit, &origin_list))
-        return 0;
-
-    if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
-        PyErr_SetString(PyExc_Exception, "Router bit mask out of range");
-        return 0;
-    }
-
-    if (router->routers_by_mask_bit[router_maskbit] == 0) {
-        PyErr_SetString(PyExc_Exception, "Router Not Found");
-        return 0;
-    }
+    char          *error = 0;
 
-    if (!PyList_Check(origin_list)) {
-        PyErr_SetString(PyExc_Exception, "Expected List as argument 2");
+    if (!PyArg_ParseTuple(args, "i", &router_maskbit))
         return 0;
-    }
-
-    Py_ssize_t        origin_count = PyList_Size(origin_list);
-    qd_router_node_t *rnode        = 
router->routers_by_mask_bit[router_maskbit];
-    int               maskbit;
 
-    for (idx = 0; idx < origin_count; idx++) {
-        maskbit = PyInt_AS_LONG(PyList_GetItem(origin_list, idx));
-
-        if (maskbit >= qd_bitmask_width() || maskbit < 0) {
-            PyErr_SetString(PyExc_Exception, "Origin bit mask out of range");
-            return 0;
+    do {
+        if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
+            error = "Router bit mask out of range";
+            break;
         }
 
-        if (router->routers_by_mask_bit[maskbit] == 0) {
-            PyErr_SetString(PyExc_Exception, "Origin router Not Found");
-            return 0;
+        sys_mutex_lock(router->lock);
+        if (router->routers_by_mask_bit[router_maskbit] == 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Router Not Found";
+            break;
         }
-    }
 
-    qd_bitmask_clear_all(rnode->valid_origins);
-    qd_bitmask_set_bit(rnode->valid_origins, 0);  // This router is a valid 
origin for all destinations
-    for (idx = 0; idx < origin_count; idx++) {
-        maskbit = PyInt_AS_LONG(PyList_GetItem(origin_list, idx));
-        qd_bitmask_set_bit(rnode->valid_origins, maskbit);
+        qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit];
+        rnode->next_hop = 0;
+
+        sys_mutex_unlock(router->lock);
+    } while (0);
+
+    if (error) {
+        PyErr_SetString(PyExc_Exception, error);
+        return 0;
     }
 
     Py_INCREF(Py_None);
@@ -314,38 +365,66 @@ static PyObject* qd_set_valid_origins(Py
 }
 
 
-static PyObject* qd_add_neighbor_router(PyObject *self, PyObject *args)
+static PyObject* qd_set_valid_origins(PyObject *self, PyObject *args)
 {
     RouterAdapter *adapter = (RouterAdapter*) self;
     qd_router_t   *router  = adapter->router;
-    const char    *address;
     int            router_maskbit;
-    int            link_maskbit;
+    PyObject      *origin_list;
+    Py_ssize_t     idx;
+    char          *error = 0;
 
-    if (!PyArg_ParseTuple(args, "sii", &address, &router_maskbit, 
&link_maskbit))
+    if (!PyArg_ParseTuple(args, "iO", &router_maskbit, &origin_list))
         return 0;
 
-    char *error = qd_add_router(router, address, router_maskbit, link_maskbit);
-    if (error) {
-        PyErr_SetString(PyExc_Exception, error);
-        return 0;
-    }
+    do {
+        if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) {
+            error = "Router bit mask out of range";
+            break;
+        }
 
-    Py_INCREF(Py_None);
-    return Py_None;
-}
+        if (!PyList_Check(origin_list)) {
+            error = "Expected List as argument 2";
+            break;
+        }
+
+        sys_mutex_lock(router->lock);
+        if (router->routers_by_mask_bit[router_maskbit] == 0) {
+            sys_mutex_unlock(router->lock);
+            error = "Router Not Found";
+            break;
+        }
 
+        Py_ssize_t        origin_count = PyList_Size(origin_list);
+        qd_router_node_t *rnode        = 
router->routers_by_mask_bit[router_maskbit];
+        int               maskbit;
+
+        for (idx = 0; idx < origin_count; idx++) {
+            maskbit = PyInt_AS_LONG(PyList_GetItem(origin_list, idx));
+
+            if (maskbit >= qd_bitmask_width() || maskbit < 0) {
+                error = "Origin bit mask out of range";
+                break;
+            }
+
+            if (router->routers_by_mask_bit[maskbit] == 0) {
+                error = "Origin router Not Found";
+                break;
+            }
+        }
 
-static PyObject* qd_del_neighbor_router(PyObject *self, PyObject *args)
-{
-    RouterAdapter *adapter = (RouterAdapter*) self;
-    qd_router_t   *router  = adapter->router;
-    int router_maskbit;
+        if (error == 0) {
+            qd_bitmask_clear_all(rnode->valid_origins);
+            qd_bitmask_set_bit(rnode->valid_origins, 0);  // This router is a 
valid origin for all destinations
+            for (idx = 0; idx < origin_count; idx++) {
+                maskbit = PyInt_AS_LONG(PyList_GetItem(origin_list, idx));
+                qd_bitmask_set_bit(rnode->valid_origins, maskbit);
+            }
+        }
 
-    if (!PyArg_ParseTuple(args, "i", &router_maskbit))
-        return 0;
+        sys_mutex_unlock(router->lock);
+    } while (0);
 
-    char *error = qd_del_router(router, router_maskbit);
     if (error) {
         PyErr_SetString(PyExc_Exception, error);
         return 0;
@@ -478,15 +557,16 @@ static PyObject* qd_get_agent(PyObject *
 }
 
 static PyMethodDef RouterAdapter_methods[] = {
-    {"add_remote_router",   qd_add_remote_router,   METH_VARARGS, "A new 
remote/reachable router has been discovered"},
-    {"del_remote_router",   qd_del_remote_router,   METH_VARARGS, "We've lost 
reachability to a remote router"},
-    {"set_next_hop",        qd_set_next_hop,        METH_VARARGS, "Set the 
next hop for a remote router"},
-    {"set_valid_origins",   qd_set_valid_origins,   METH_VARARGS, "Set the 
valid origins for a remote router"},
-    {"add_neighbor_router", qd_add_neighbor_router, METH_VARARGS, "A new 
neighbor router has been discovered"},
-    {"del_neighbor_router", qd_del_neighbor_router, METH_VARARGS, "We've lost 
reachability to a neighbor router"},
-    {"map_destination",     qd_map_destination,     METH_VARARGS, "Add a newly 
discovered destination mapping"},
-    {"unmap_destination",   qd_unmap_destination,   METH_VARARGS, "Delete a 
destination mapping"},
-    {"get_agent",           qd_get_agent,           METH_VARARGS, "Get the 
management agent"},
+    {"add_router",          qd_add_router,        METH_VARARGS, "A new 
remote/reachable router has been discovered"},
+    {"del_router",          qd_del_router,        METH_VARARGS, "We've lost 
reachability to a remote router"},
+    {"set_link",            qd_set_link,          METH_VARARGS, "Set the link 
for a neighbor router"},
+    {"remove_link",         qd_remove_link,       METH_VARARGS, "Remove the 
link for a neighbor router"},
+    {"set_next_hop",        qd_set_next_hop,      METH_VARARGS, "Set the next 
hop for a remote router"},
+    {"remove_next_hop",     qd_remove_next_hop,   METH_VARARGS, "Remove the 
next hop for a remote router"},
+    {"set_valid_origins",   qd_set_valid_origins, METH_VARARGS, "Set the valid 
origins for a remote router"},
+    {"map_destination",     qd_map_destination,   METH_VARARGS, "Add a newly 
discovered destination mapping"},
+    {"unmap_destination",   qd_unmap_destination, METH_VARARGS, "Delete a 
destination mapping"},
+    {"get_agent",           qd_get_agent,         METH_VARARGS, "Get the 
management agent"},
     {0, 0, 0, 0}
 };
 
@@ -544,7 +624,7 @@ static PyTypeObject RouterAdapterType =
 qd_error_t qd_router_python_setup(qd_router_t *router)
 {
     qd_error_clear();
-    log_source = qd_log_source("PYROUTER");
+    log_source = qd_log_source("ROUTER");
 
     //
     // If we are not operating as an interior router, don't start the

Modified: qpid/dispatch/trunk/tests/config-2/A.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-2/A.conf?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/config-2/A.conf (original)
+++ qpid/dispatch/trunk/tests/config-2/A.conf Wed Jan 21 15:22:57 2015
@@ -85,3 +85,9 @@ fixed-address {
     prefix: /
     fanout: multiple
 }
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+

Modified: qpid/dispatch/trunk/tests/config-2/B.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-2/B.conf?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/config-2/B.conf (original)
+++ qpid/dispatch/trunk/tests/config-2/B.conf Wed Jan 21 15:22:57 2015
@@ -85,3 +85,8 @@ fixed-address {
     prefix: /
     fanout: multiple
 }
+
+log {
+    module: ROUTER
+    enable: trace+
+}

Modified: qpid/dispatch/trunk/tests/config-3-linear/A.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-3-linear/A.conf?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/config-3-linear/A.conf (original)
+++ qpid/dispatch/trunk/tests/config-3-linear/A.conf Wed Jan 21 15:22:57 2015
@@ -64,5 +64,13 @@ router {
     router-id: QDR.A
 }
 
+log {
+    module: ROUTER
+    enable: trace+
+}
 
+log {
+    module: ROUTER_LS
+    enable: trace+
+}
 

Modified: qpid/dispatch/trunk/tests/config-3-linear/B.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-3-linear/B.conf?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/config-3-linear/B.conf (original)
+++ qpid/dispatch/trunk/tests/config-3-linear/B.conf Wed Jan 21 15:22:57 2015
@@ -65,3 +65,13 @@ router {
     mode: interior
     router-id: QDR.B
 }
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_LS
+    enable: trace+
+}

Modified: qpid/dispatch/trunk/tests/config-3-linear/C.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-3-linear/C.conf?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/config-3-linear/C.conf (original)
+++ qpid/dispatch/trunk/tests/config-3-linear/C.conf Wed Jan 21 15:22:57 2015
@@ -58,3 +58,13 @@ router {
     mode: interior
     router-id: QDR.C
 }
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_LS
+    enable: trace+
+}

Added: qpid/dispatch/trunk/tests/config-6/A.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/A.conf?rev=1653556&view=auto
==============================================================================
--- qpid/dispatch/trunk/tests/config-6/A.conf (added)
+++ qpid/dispatch/trunk/tests/config-6/A.conf Wed Jan 21 15:22:57 2015
@@ -0,0 +1,81 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##   http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License
+##
+
+
+##
+## Container section - Configures the general operation of the AMQP container.
+##
+container {
+    worker-threads: 4
+    container-name: QDR.A
+}
+
+
+##
+## Listeners and Connectors
+##
+listener {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20001
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20002
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20003
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20004
+    sasl-mechanisms: ANONYMOUS
+}
+
+router {
+    mode: interior
+    area: A
+    router-id: QDR.A
+}
+
+fixed-address {
+    prefix: /closest/
+    fanout: single
+    bias: closest
+}
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_MA
+    enable: trace+
+}

Added: qpid/dispatch/trunk/tests/config-6/B.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/B.conf?rev=1653556&view=auto
==============================================================================
--- qpid/dispatch/trunk/tests/config-6/B.conf (added)
+++ qpid/dispatch/trunk/tests/config-6/B.conf Wed Jan 21 15:22:57 2015
@@ -0,0 +1,74 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##   http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License
+##
+
+
+##
+## Container section - Configures the general operation of the AMQP container.
+##
+container {
+    worker-threads: 4
+    container-name: QDR.B
+}
+
+
+##
+## Listeners and Connectors
+##
+listener {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20002
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20003
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20004
+    sasl-mechanisms: ANONYMOUS
+}
+
+router {
+    mode: interior
+    area: A
+    router-id: QDR.B
+}
+
+fixed-address {
+    prefix: /closest/
+    fanout: single
+    bias: closest
+}
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_MA
+    enable: trace+
+}

Added: qpid/dispatch/trunk/tests/config-6/C.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/C.conf?rev=1653556&view=auto
==============================================================================
--- qpid/dispatch/trunk/tests/config-6/C.conf (added)
+++ qpid/dispatch/trunk/tests/config-6/C.conf Wed Jan 21 15:22:57 2015
@@ -0,0 +1,69 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##   http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License
+##
+
+
+##
+## Container section - Configures the general operation of the AMQP container.
+##
+container {
+    worker-threads: 4
+    container-name: QDR.C
+}
+
+
+##
+## Listeners and Connectors
+##
+listener {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20003
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20004
+    sasl-mechanisms: ANONYMOUS
+}
+
+router {
+    mode: interior
+    area: A
+    router-id: QDR.C
+}
+
+fixed-address {
+    prefix: /closest/
+    fanout: single
+    bias: closest
+}
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_MA
+    enable: trace+
+}
+
+

Added: qpid/dispatch/trunk/tests/config-6/D.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/D.conf?rev=1653556&view=auto
==============================================================================
--- qpid/dispatch/trunk/tests/config-6/D.conf (added)
+++ qpid/dispatch/trunk/tests/config-6/D.conf Wed Jan 21 15:22:57 2015
@@ -0,0 +1,62 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##   http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License
+##
+
+
+##
+## Container section - Configures the general operation of the AMQP container.
+##
+container {
+    worker-threads: 4
+    container-name: QDR.D
+}
+
+
+##
+## Listeners and Connectors
+##
+listener {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20004
+    sasl-mechanisms: ANONYMOUS
+}
+
+router {
+    mode: interior
+    area: A
+    router-id: QDR.D
+}
+
+fixed-address {
+    prefix: /closest/
+    fanout: single
+    bias: closest
+}
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_MA
+    enable: trace+
+}
+
+

Added: qpid/dispatch/trunk/tests/config-6/X.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/X.conf?rev=1653556&view=auto
==============================================================================
--- qpid/dispatch/trunk/tests/config-6/X.conf (added)
+++ qpid/dispatch/trunk/tests/config-6/X.conf Wed Jan 21 15:22:57 2015
@@ -0,0 +1,75 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##   http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License
+##
+
+
+##
+## Container section - Configures the general operation of the AMQP container.
+##
+container {
+    worker-threads: 4
+    container-name: QDR.X
+}
+
+
+##
+## Listeners and Connectors
+##
+listener {
+    addr: 0.0.0.0
+    port: amqp
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20001
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20002
+    sasl-mechanisms: ANONYMOUS
+}
+
+router {
+    mode: interior
+    area: A
+    router-id: QDR.X
+}
+
+fixed-address {
+    prefix: /closest/
+    fanout: single
+    bias: closest
+}
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_MA
+    enable: trace+
+}
+
+

Added: qpid/dispatch/trunk/tests/config-6/Y.conf
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/Y.conf?rev=1653556&view=auto
==============================================================================
--- qpid/dispatch/trunk/tests/config-6/Y.conf (added)
+++ qpid/dispatch/trunk/tests/config-6/Y.conf Wed Jan 21 15:22:57 2015
@@ -0,0 +1,73 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##   http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License
+##
+
+
+##
+## Container section - Configures the general operation of the AMQP container.
+##
+container {
+    worker-threads: 4
+    container-name: QDR.Y
+}
+
+
+##
+## Listeners and Connectors
+##
+listener {
+    addr: 0.0.0.0
+    port: 20005
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20003
+    sasl-mechanisms: ANONYMOUS
+}
+
+connector {
+    role: inter-router
+    addr: 0.0.0.0
+    port: 20004
+    sasl-mechanisms: ANONYMOUS
+}
+
+router {
+    mode: interior
+    area: A
+    router-id: QDR.Y
+}
+
+fixed-address {
+    prefix: /closest/
+    fanout: single
+    bias: closest
+}
+
+log {
+    module: ROUTER
+    enable: trace+
+}
+
+log {
+    module: ROUTER_MA
+    enable: trace+
+}

Copied: qpid/dispatch/trunk/tests/config-6/topology.txt (from r1650165, 
qpid/dispatch/trunk/tests/config-3-linear/topology.txt)
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/config-6/topology.txt?p2=qpid/dispatch/trunk/tests/config-6/topology.txt&p1=qpid/dispatch/trunk/tests/config-3-linear/topology.txt&r1=1650165&r2=1653556&rev=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/config-3-linear/topology.txt (original)
+++ qpid/dispatch/trunk/tests/config-6/topology.txt Wed Jan 21 15:22:57 2015
@@ -19,12 +19,24 @@
 
 
   +----------+          +----------+          +----------+
-  |QDR.A     |          |QDR.B     |          |QDR.C     |
+  |QDR.X     |          |QDR.A     |          |QDR.C     |
   |port:     |          |port:     |          |port:     |
-  | 20001    |--------->| 20002    |--------->| 20003    |
-  |          |          |          |          |          |
-  |          |          |          |          |          |
-  +----------+          +----------+          +----------+
+  | 5672     |--------->| 20001    |--------->| 20003    |
+  |          |          |          |          |          |<------+
+  |          |--+       |          |    +---->|          |       |
+  +----------+  |       +----------+    |     +----------+       |
+                |            |    |     |             |          |
+                |            |    +--------------+    |          |
+                |            |          |        |    |          |
+                |            v          |        v    v          |
+                |       +----------+    |     +----------+       |  
+----------+
+                |       |QDR.B     |----+     |QDR.D     |       +--|QDR.Y     
|
+                +------>|port:     |          |port:     |          |port:     
|
+                        | 20002    |--------->| 20004    |<---------| 20005    
|
+                        |          |          |          |          |          
|
+                        |          |          |          |          |          
|
+                        +----------+          +----------+          
+----------+
+
 
  * The direction of the arrow shows the direction of the connection setup
    Connector --> Listener

Modified: qpid/dispatch/trunk/tests/router_engine_test.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/router_engine_test.py?rev=1653556&r1=1653555&r2=1653556&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/router_engine_test.py (original)
+++ qpid/dispatch/trunk/tests/router_engine_test.py Wed Jan 21 15:22:57 2015
@@ -24,7 +24,7 @@ import unittest
 sys.path.append(os.path.join(os.environ["SOURCE_DIR"], "python"))
 sys.path.append(os.path.join(os.path.dirname(__file__), "mock")) # Mock 
modules for tests
 
-from qpid_dispatch_internal.router.engine import NeighborEngine, PathEngine, 
NodeTracker
+from qpid_dispatch_internal.router.engine import HelloProtocol, PathEngine, 
NodeTracker
 from qpid_dispatch_internal.router.data import LinkState, MessageHELLO
 from qpid_dispatch.management.entity import EntityBase
 from system_test import main_module
@@ -52,14 +52,12 @@ class Adapter(object):
 
 class DataTest(unittest.TestCase):
     def test_link_state(self):
-        ls = LinkState(None, 'R1', 'area', 1, ['R2', 'R3'])
+        ls = LinkState(None, 'R1', 1, ['R2', 'R3'])
         self.assertEqual(ls.id, 'R1')
-        self.assertEqual(ls.area, 'area')
         self.assertEqual(ls.ls_seq, 1)
         self.assertEqual(ls.peers, ['R2', 'R3'])
         ls.bump_sequence()
         self.assertEqual(ls.id, 'R1')
-        self.assertEqual(ls.area, 'area')
         self.assertEqual(ls.ls_seq, 2)
         self.assertEqual(ls.peers, ['R2', 'R3'])
 
@@ -80,22 +78,19 @@ class DataTest(unittest.TestCase):
         encoded = ls.to_dict()
         new_ls = LinkState(encoded)
         self.assertEqual(new_ls.id, 'R1')
-        self.assertEqual(new_ls.area, 'area')
         self.assertEqual(new_ls.ls_seq, 2)
         self.assertEqual(new_ls.peers, ['R2', 'R4'])
 
 
     def test_hello_message(self):
-        msg1 = MessageHELLO(None, 'R1', 'area', ['R2', 'R3', 'R4'])
+        msg1 = MessageHELLO(None, 'R1', ['R2', 'R3', 'R4'])
         self.assertEqual(msg1.get_opcode(), "HELLO")
         self.assertEqual(msg1.id, 'R1')
-        self.assertEqual(msg1.area, 'area')
         self.assertEqual(msg1.seen_peers, ['R2', 'R3', 'R4'])
         encoded = msg1.to_dict()
         msg2 = MessageHELLO(encoded)
         self.assertEqual(msg2.get_opcode(), "HELLO")
         self.assertEqual(msg2.id, 'R1')
-        self.assertEqual(msg2.area, 'area')
         self.assertEqual(msg2.seen_peers, ['R2', 'R3', 'R4'])
         self.assertTrue(msg2.is_seen('R3'))
         self.assertFalse(msg2.is_seen('R9'))
@@ -133,149 +128,32 @@ class NodeTrackerTest(unittest.TestCase)
         self.address    = None
         self.router_bit = None
         self.link_bit   = None
-        self.area       = "area"
         self.calls      = 0
 
-    def test_node_tracker_limits(self):
-        tracker = NodeTracker(self, 5)
-
-        self.reset()
-        tracker.new_neighbor('A', 1, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/A')
-        self.assertEqual(self.link_bit, 1)
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        tracker.new_neighbor('B', 5, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/B')
-        self.assertEqual(self.link_bit, 5)
-        self.assertEqual(self.router_bit, 2)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        tracker.new_neighbor('C', 6, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/C')
-        self.assertEqual(self.link_bit, 6)
-        self.assertEqual(self.router_bit, 3)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        tracker.new_neighbor('D', 7, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/D')
-        self.assertEqual(self.link_bit, 7)
-        self.assertEqual(self.router_bit, 4)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        try:
-            tracker.new_neighbor('E', 9, 0)
-            self.fail("We shouldn't be here")
-        except:
-            pass
-
-        self.reset()
-        tracker.lost_neighbor('C')
-        self.assertEqual(self.router_bit, 3)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        tracker.new_neighbor('E', 9, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/E')
-        self.assertEqual(self.link_bit, 9)
-        self.assertEqual(self.router_bit, 3)
-        self.assertEqual(self.calls, 1)
-
-
-    def test_node_tracker_remote_neighbor(self):
-        tracker = NodeTracker(self, 5)
-
-        self.reset()
-        tracker.new_node('A', 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/A')
-        self.assertFalse(self.link_bit)
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        tracker.new_neighbor('A', 3, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/A')
-        self.assertEqual(self.link_bit, 3)
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 2)
-
-        self.reset()
-        tracker.lost_node('A')
-        self.assertFalse(self.address)
-        self.assertFalse(self.link_bit)
-        self.assertFalse(self.router_bit)
-        self.assertEqual(self.calls, 0)
-
-        self.reset()
-        tracker.lost_neighbor('A')
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 1)
-
-
-    def test_node_tracker_neighbor_remote(self):
-        tracker = NodeTracker(self, 5)
-
-        self.reset()
-        tracker.new_neighbor('A', 3, 0)
-        self.assertEqual(self.address, 'amqp:/_topo/area/A')
-        self.assertEqual(self.link_bit, 3)
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 1)
-
-        self.reset()
-        tracker.new_node('A', 0)
-        self.assertFalse(self.address)
-        self.assertFalse(self.link_bit)
-        self.assertFalse(self.router_bit)
-        self.assertEqual(self.calls, 0)
-
-        self.reset()
-        tracker.lost_neighbor('A')
-        self.assertEqual(self.address, 'amqp:/_topo/area/A')
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 2)
-
-        self.reset()
-        tracker.lost_node('A')
-        self.assertEqual(self.router_bit, 1)
-        self.assertEqual(self.calls, 1)
-
 
 class NeighborTest(unittest.TestCase):
     def log(self, level, text):
         pass
 
+    def log_hello(self, level, text):
+        pass
+
     def send(self, dest, msg):
         self.sent.append((dest, msg))
 
-    def local_link_state_changed(self, link_state):
-        self.local_link_state = link_state
-
-    def new_neighbor(self, rid, lbit, instance):
-        self.neighbors[rid] = None
-
-    def lost_neighbor(self, rid):
-        self.neighbors.pop(rid)
-
-    def touch_node(self, rid, instance):
-        pass
+    def neighbor_refresh(self, node_id, instance, link_id, now):
+        self.neighbors[node_id] = (instance, link_id, now)
 
     def setUp(self):
         self.sent = []
-        self.local_link_state = None
+        self.neighbors = {}
         self.id = "R1"
-        self.area = "area"
         self.instance = 0
         # Fake configuration
         self.config = EntityBase({
-            'helloInterval'      :  1.0,
-            'helloMaxAge'       :  3.0,
-            'raInterval'         : 30.0,
+            'helloInterval'    :  1.0,
+            'helloMaxAge'      :  3.0,
+            'raInterval'       : 30.0,
             'remoteLsMaxAge'   : 60.0,
             'mobileAddrMaxAge' : 60.0  })
         self.neighbors = {}
@@ -283,7 +161,7 @@ class NeighborTest(unittest.TestCase):
     def test_hello_sent(self):
         self.sent = []
         self.local_link_state = None
-        self.engine = NeighborEngine(self)
+        self.engine = HelloProtocol(self, self)
         self.engine.tick(0.5)
         self.assertEqual(self.sent, [])
         self.engine.tick(1.5)
@@ -292,15 +170,14 @@ class NeighborTest(unittest.TestCase):
         self.assertEqual(dest, "amqp:/_local/qdhello")
         self.assertEqual(msg.get_opcode(), "HELLO")
         self.assertEqual(msg.id, self.id)
-        self.assertEqual(msg.area, self.area)
         self.assertEqual(msg.seen_peers, [])
         self.assertEqual(self.local_link_state, None)
 
     def test_sees_peer(self):
         self.sent = []
-        self.local_link_state = None
-        self.engine = NeighborEngine(self)
-        self.engine.handle_hello(MessageHELLO(None, 'R2', 'area', []), 2.0, 0)
+        self.neighbors = {}
+        self.engine = HelloProtocol(self, self)
+        self.engine.handle_hello(MessageHELLO(None, 'R2', []), 2.0, 0)
         self.engine.tick(5.0)
         self.assertEqual(len(self.sent), 1)
         dest, msg = self.sent.pop(0)
@@ -308,65 +185,40 @@ class NeighborTest(unittest.TestCase):
 
     def test_establish_peer(self):
         self.sent = []
-        self.local_link_state = None
-        self.engine = NeighborEngine(self)
-        self.engine.handle_hello(MessageHELLO(None, 'R2', 'area', ['R1']), 
0.5, 0)
+        self.neighbors = {}
+        self.engine = HelloProtocol(self, self)
+        self.engine.handle_hello(MessageHELLO(None, 'R2', ['R1']), 0.5, 0)
         self.engine.tick(1.0)
         self.engine.tick(2.0)
         self.engine.tick(3.0)
-        self.assertEqual(self.local_link_state.id, 'R1')
-        self.assertEqual(self.local_link_state.area, 'area')
-        self.assertEqual(self.local_link_state.ls_seq, 1)
-        self.assertEqual(self.local_link_state.peers, ['R2'])
+        self.assertEqual(len(self.neighbors), 1)
+        self.assertEqual(self.neighbors.keys(), ['R2'])
 
     def test_establish_multiple_peers(self):
         self.sent = []
-        self.local_link_state = None
-        self.engine = NeighborEngine(self)
-        self.engine.handle_hello(MessageHELLO(None, 'R2', 'area', ['R1']), 
0.5, 0)
+        self.neighbors = {}
+        self.engine = HelloProtocol(self, self)
+        self.engine.handle_hello(MessageHELLO(None, 'R2', ['R1']), 0.5, 0)
         self.engine.tick(1.0)
-        self.engine.handle_hello(MessageHELLO(None, 'R3', 'area', ['R1', 
'R2']), 1.5, 0)
+        self.engine.handle_hello(MessageHELLO(None, 'R3', ['R1', 'R2']), 1.5, 
0)
         self.engine.tick(2.0)
-        self.engine.handle_hello(MessageHELLO(None, 'R4', 'area', ['R1']), 
2.5, 0)
-        self.engine.handle_hello(MessageHELLO(None, 'R5', 'area', ['R2']), 
2.5, 0)
-        self.engine.handle_hello(MessageHELLO(None, 'R6', 'area', ['R1']), 
2.5, 0)
+        self.engine.handle_hello(MessageHELLO(None, 'R4', ['R1']), 2.5, 0)
+        self.engine.handle_hello(MessageHELLO(None, 'R5', ['R2']), 2.5, 0)
+        self.engine.handle_hello(MessageHELLO(None, 'R6', ['R1']), 2.5, 0)
         self.engine.tick(3.0)
-        self.assertEqual(self.local_link_state.id, 'R1')
-        self.assertEqual(self.local_link_state.area, 'area')
-        self.assertEqual(self.local_link_state.ls_seq, 3)
-        self.local_link_state.peers.sort()
-        self.assertEqual(self.local_link_state.peers, ['R2', 'R3', 'R4', 'R6'])
-
-    def test_timeout_peer(self):
-        self.sent = []
-        self.local_link_state = None
-        self.engine = NeighborEngine(self)
-        self.engine.handle_hello(MessageHELLO(None, 'R2', 'area', ['R3', 
'R1']), 2.0, 0)
-        self.engine.tick(5.0)
-        self.engine.tick(17.1)
-        self.assertEqual(self.local_link_state.id, 'R1')
-        self.assertEqual(self.local_link_state.area, 'area')
-        self.assertEqual(self.local_link_state.ls_seq, 2)
-        self.assertEqual(self.local_link_state.peers, [])
+        keys = self.neighbors.keys()
+        keys.sort()
+        self.assertEqual(keys, ['R2', 'R3', 'R4', 'R6'])
 
 
 class PathTest(unittest.TestCase):
     def setUp(self):
         self.id = 'R1'
-        self.area = 'area'
-        self.next_hops = None
-        self.valid_origins = None
         self.engine = PathEngine(self)
 
     def log(self, level, text):
         pass
 
-    def next_hops_changed(self, nh):
-        self.next_hops = nh
-
-    def valid_origins_changed(self, vo):
-        self.valid_origins = vo
-
     def test_topology1(self):
         """
 
@@ -375,19 +227,18 @@ class PathTest(unittest.TestCase):
         +====+      +----+      +----+
 
         """
-        collection = { 'R1': LinkState(None, 'R1', 'area', 1, ['R2']),
-                       'R2': LinkState(None, 'R2', 'area', 1, ['R1', 'R3']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R2']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 2)
-        self.assertEqual(self.next_hops['R2'], 'R2')
-        self.assertEqual(self.next_hops['R3'], 'R2')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.assertEqual(self.valid_origins['R2'], [])
-        self.assertEqual(self.valid_origins['R3'], [])
+        collection = { 'R1': LinkState(None, 'R1', 1, ['R2']),
+                       'R2': LinkState(None, 'R2', 1, ['R1', 'R3']),
+                       'R3': LinkState(None, 'R3', 1, ['R2']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 2)
+        self.assertEqual(next_hops['R2'], 'R2')
+        self.assertEqual(next_hops['R3'], 'R2')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        self.assertEqual(valid_origins['R2'], [])
+        self.assertEqual(valid_origins['R3'], [])
 
     def test_topology2(self):
         """
@@ -401,31 +252,30 @@ class PathTest(unittest.TestCase):
                     +----+      +----+      +----+
 
         """
-        collection = { 'R1': LinkState(None, 'R1', 'area', 1, ['R2']),
-                       'R2': LinkState(None, 'R2', 'area', 1, ['R1', 'R3', 
'R4']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R2', 'R5']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R2', 'R5']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R3', 'R4', 
'R6']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 5)
-        self.assertEqual(self.next_hops['R2'], 'R2')
-        self.assertEqual(self.next_hops['R3'], 'R2')
-        self.assertEqual(self.next_hops['R4'], 'R2')
-        self.assertEqual(self.next_hops['R5'], 'R2')
-        self.assertEqual(self.next_hops['R6'], 'R2')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.valid_origins['R6'].sort()
-        self.assertEqual(self.valid_origins['R2'], [])
-        self.assertEqual(self.valid_origins['R3'], [])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], [])
-        self.assertEqual(self.valid_origins['R6'], [])
+        collection = { 'R1': LinkState(None, 'R1', 1, ['R2']),
+                       'R2': LinkState(None, 'R2', 1, ['R1', 'R3', 'R4']),
+                       'R3': LinkState(None, 'R3', 1, ['R2', 'R5']),
+                       'R4': LinkState(None, 'R4', 1, ['R2', 'R5']),
+                       'R5': LinkState(None, 'R5', 1, ['R3', 'R4', 'R6']),
+                       'R6': LinkState(None, 'R6', 1, ['R5']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 5)
+        self.assertEqual(next_hops['R2'], 'R2')
+        self.assertEqual(next_hops['R3'], 'R2')
+        self.assertEqual(next_hops['R4'], 'R2')
+        self.assertEqual(next_hops['R5'], 'R2')
+        self.assertEqual(next_hops['R6'], 'R2')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        valid_origins['R6'].sort()
+        self.assertEqual(valid_origins['R2'], [])
+        self.assertEqual(valid_origins['R3'], [])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], [])
+        self.assertEqual(valid_origins['R6'], [])
 
     def test_topology3(self):
         """
@@ -439,31 +289,30 @@ class PathTest(unittest.TestCase):
                     +====+      +----+      +----+
 
         """
-        collection = { 'R2': LinkState(None, 'R2', 'area', 1, ['R3']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R1', 'R2', 
'R4']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R3', 'R5']),
-                       'R1': LinkState(None, 'R1', 'area', 1, ['R3', 'R5']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R1', 'R4', 
'R6']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 5)
-        self.assertEqual(self.next_hops['R2'], 'R3')
-        self.assertEqual(self.next_hops['R3'], 'R3')
-        self.assertEqual(self.next_hops['R4'], 'R3')
-        self.assertEqual(self.next_hops['R5'], 'R5')
-        self.assertEqual(self.next_hops['R6'], 'R5')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.valid_origins['R6'].sort()
-        self.assertEqual(self.valid_origins['R2'], ['R5', 'R6'])
-        self.assertEqual(self.valid_origins['R3'], ['R5', 'R6'])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R6'], ['R2', 'R3'])
+        collection = { 'R2': LinkState(None, 'R2', 1, ['R3']),
+                       'R3': LinkState(None, 'R3', 1, ['R1', 'R2', 'R4']),
+                       'R4': LinkState(None, 'R4', 1, ['R3', 'R5']),
+                       'R1': LinkState(None, 'R1', 1, ['R3', 'R5']),
+                       'R5': LinkState(None, 'R5', 1, ['R1', 'R4', 'R6']),
+                       'R6': LinkState(None, 'R6', 1, ['R5']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 5)
+        self.assertEqual(next_hops['R2'], 'R3')
+        self.assertEqual(next_hops['R3'], 'R3')
+        self.assertEqual(next_hops['R4'], 'R3')
+        self.assertEqual(next_hops['R5'], 'R5')
+        self.assertEqual(next_hops['R6'], 'R5')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        valid_origins['R6'].sort()
+        self.assertEqual(valid_origins['R2'], ['R5', 'R6'])
+        self.assertEqual(valid_origins['R3'], ['R5', 'R6'])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R6'], ['R2', 'R3'])
 
     def test_topology4(self):
         """
@@ -477,34 +326,33 @@ class PathTest(unittest.TestCase):
                     +====+      +----+      +----+
 
         """
-        collection = { 'R2': LinkState(None, 'R2', 'area', 1, ['R3']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R1', 'R2', 
'R4']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R3', 'R5']),
-                       'R1': LinkState(None, 'R1', 'area', 1, ['R3', 'R5']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R1', 'R4', 
'R6']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5', 'R7']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 6)
-        self.assertEqual(self.next_hops['R2'], 'R3')
-        self.assertEqual(self.next_hops['R3'], 'R3')
-        self.assertEqual(self.next_hops['R4'], 'R3')
-        self.assertEqual(self.next_hops['R5'], 'R5')
-        self.assertEqual(self.next_hops['R6'], 'R5')
-        self.assertEqual(self.next_hops['R7'], 'R5')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.valid_origins['R6'].sort()
-        self.valid_origins['R7'].sort()
-        self.assertEqual(self.valid_origins['R2'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R3'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R6'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R7'], ['R2', 'R3'])
+        collection = { 'R2': LinkState(None, 'R2', 1, ['R3']),
+                       'R3': LinkState(None, 'R3', 1, ['R1', 'R2', 'R4']),
+                       'R4': LinkState(None, 'R4', 1, ['R3', 'R5']),
+                       'R1': LinkState(None, 'R1', 1, ['R3', 'R5']),
+                       'R5': LinkState(None, 'R5', 1, ['R1', 'R4', 'R6']),
+                       'R6': LinkState(None, 'R6', 1, ['R5', 'R7']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 6)
+        self.assertEqual(next_hops['R2'], 'R3')
+        self.assertEqual(next_hops['R3'], 'R3')
+        self.assertEqual(next_hops['R4'], 'R3')
+        self.assertEqual(next_hops['R5'], 'R5')
+        self.assertEqual(next_hops['R6'], 'R5')
+        self.assertEqual(next_hops['R7'], 'R5')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        valid_origins['R6'].sort()
+        valid_origins['R7'].sort()
+        self.assertEqual(valid_origins['R2'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R3'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R6'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R7'], ['R2', 'R3'])
 
     def test_topology5(self):
         """
@@ -518,34 +366,33 @@ class PathTest(unittest.TestCase):
                     +====+      +----+      +----+
 
         """
-        collection = { 'R2': LinkState(None, 'R2', 'area', 1, ['R3', 'R1']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R1', 'R2', 
'R4']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R3', 'R5']),
-                       'R1': LinkState(None, 'R1', 'area', 1, ['R3', 'R5', 
'R2']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R1', 'R4', 
'R6']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5', 'R7']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 6)
-        self.assertEqual(self.next_hops['R2'], 'R2')
-        self.assertEqual(self.next_hops['R3'], 'R3')
-        self.assertEqual(self.next_hops['R4'], 'R3')
-        self.assertEqual(self.next_hops['R5'], 'R5')
-        self.assertEqual(self.next_hops['R6'], 'R5')
-        self.assertEqual(self.next_hops['R7'], 'R5')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.valid_origins['R6'].sort()
-        self.valid_origins['R7'].sort()
-        self.assertEqual(self.valid_origins['R2'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R3'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R6'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R7'], ['R2', 'R3'])
+        collection = { 'R2': LinkState(None, 'R2', 1, ['R3', 'R1']),
+                       'R3': LinkState(None, 'R3', 1, ['R1', 'R2', 'R4']),
+                       'R4': LinkState(None, 'R4', 1, ['R3', 'R5']),
+                       'R1': LinkState(None, 'R1', 1, ['R3', 'R5', 'R2']),
+                       'R5': LinkState(None, 'R5', 1, ['R1', 'R4', 'R6']),
+                       'R6': LinkState(None, 'R6', 1, ['R5', 'R7']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 6)
+        self.assertEqual(next_hops['R2'], 'R2')
+        self.assertEqual(next_hops['R3'], 'R3')
+        self.assertEqual(next_hops['R4'], 'R3')
+        self.assertEqual(next_hops['R5'], 'R5')
+        self.assertEqual(next_hops['R6'], 'R5')
+        self.assertEqual(next_hops['R7'], 'R5')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        valid_origins['R6'].sort()
+        valid_origins['R7'].sort()
+        self.assertEqual(valid_origins['R2'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R3'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R6'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R7'], ['R2', 'R3'])
 
     def test_topology5_with_asymmetry1(self):
         """
@@ -559,34 +406,33 @@ class PathTest(unittest.TestCase):
                     +====+      +----+      +----+
 
         """
-        collection = { 'R2': LinkState(None, 'R2', 'area', 1, ['R3']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R1', 'R2', 
'R4']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R3', 'R5']),
-                       'R1': LinkState(None, 'R1', 'area', 1, ['R3', 'R5', 
'R2']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R1', 'R4', 
'R6']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5', 'R7']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 6)
-        self.assertEqual(self.next_hops['R2'], 'R2')
-        self.assertEqual(self.next_hops['R3'], 'R3')
-        self.assertEqual(self.next_hops['R4'], 'R3')
-        self.assertEqual(self.next_hops['R5'], 'R5')
-        self.assertEqual(self.next_hops['R6'], 'R5')
-        self.assertEqual(self.next_hops['R7'], 'R5')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.valid_origins['R6'].sort()
-        self.valid_origins['R7'].sort()
-        self.assertEqual(self.valid_origins['R2'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R3'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R6'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R7'], ['R2', 'R3'])
+        collection = { 'R2': LinkState(None, 'R2', 1, ['R3']),
+                       'R3': LinkState(None, 'R3', 1, ['R1', 'R2', 'R4']),
+                       'R4': LinkState(None, 'R4', 1, ['R3', 'R5']),
+                       'R1': LinkState(None, 'R1', 1, ['R3', 'R5', 'R2']),
+                       'R5': LinkState(None, 'R5', 1, ['R1', 'R4', 'R6']),
+                       'R6': LinkState(None, 'R6', 1, ['R5', 'R7']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 6)
+        self.assertEqual(next_hops['R2'], 'R2')
+        self.assertEqual(next_hops['R3'], 'R3')
+        self.assertEqual(next_hops['R4'], 'R3')
+        self.assertEqual(next_hops['R5'], 'R5')
+        self.assertEqual(next_hops['R6'], 'R5')
+        self.assertEqual(next_hops['R7'], 'R5')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        valid_origins['R6'].sort()
+        valid_origins['R7'].sort()
+        self.assertEqual(valid_origins['R2'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R3'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R6'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R7'], ['R2', 'R3'])
 
     def test_topology5_with_asymmetry2(self):
         """
@@ -600,34 +446,33 @@ class PathTest(unittest.TestCase):
                     +====+      +----+      +----+
 
         """
-        collection = { 'R2': LinkState(None, 'R2', 'area', 1, ['R3', 'R1']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R1', 'R2', 
'R4']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R3', 'R5']),
-                       'R1': LinkState(None, 'R1', 'area', 1, ['R3', 'R5']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R1', 'R4', 
'R6']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5', 'R7']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 6)
-        self.assertEqual(self.next_hops['R2'], 'R3')
-        self.assertEqual(self.next_hops['R3'], 'R3')
-        self.assertEqual(self.next_hops['R4'], 'R3')
-        self.assertEqual(self.next_hops['R5'], 'R5')
-        self.assertEqual(self.next_hops['R6'], 'R5')
-        self.assertEqual(self.next_hops['R7'], 'R5')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.valid_origins['R6'].sort()
-        self.valid_origins['R7'].sort()
-        self.assertEqual(self.valid_origins['R2'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R3'], ['R5', 'R6', 'R7'])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R6'], ['R2', 'R3'])
-        self.assertEqual(self.valid_origins['R7'], ['R2', 'R3'])
+        collection = { 'R2': LinkState(None, 'R2', 1, ['R3', 'R1']),
+                       'R3': LinkState(None, 'R3', 1, ['R1', 'R2', 'R4']),
+                       'R4': LinkState(None, 'R4', 1, ['R3', 'R5']),
+                       'R1': LinkState(None, 'R1', 1, ['R3', 'R5']),
+                       'R5': LinkState(None, 'R5', 1, ['R1', 'R4', 'R6']),
+                       'R6': LinkState(None, 'R6', 1, ['R5', 'R7']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 6)
+        self.assertEqual(next_hops['R2'], 'R3')
+        self.assertEqual(next_hops['R3'], 'R3')
+        self.assertEqual(next_hops['R4'], 'R3')
+        self.assertEqual(next_hops['R5'], 'R5')
+        self.assertEqual(next_hops['R6'], 'R5')
+        self.assertEqual(next_hops['R7'], 'R5')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        valid_origins['R6'].sort()
+        valid_origins['R7'].sort()
+        self.assertEqual(valid_origins['R2'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R3'], ['R5', 'R6', 'R7'])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R6'], ['R2', 'R3'])
+        self.assertEqual(valid_origins['R7'], ['R2', 'R3'])
 
     def test_topology5_with_asymmetry3(self):
         """
@@ -641,28 +486,27 @@ class PathTest(unittest.TestCase):
                     +====+      +----+      +----+
 
         """
-        collection = { 'R2': LinkState(None, 'R2', 'area', 1, ['R3', 'R1']),
-                       'R3': LinkState(None, 'R3', 'area', 1, ['R1', 'R2', 
'R4']),
-                       'R4': LinkState(None, 'R4', 'area', 1, ['R3', 'R5']),
-                       'R1': LinkState(None, 'R1', 'area', 1, ['R3', 'R5']),
-                       'R5': LinkState(None, 'R5', 'area', 1, ['R1', 'R4']),
-                       'R6': LinkState(None, 'R6', 'area', 1, ['R5', 'R7']) }
-        self.engine.ls_collection_changed(collection)
-        self.engine.tick(1.0)
-        self.assertEqual(len(self.next_hops), 4)
-        self.assertEqual(self.next_hops['R2'], 'R3')
-        self.assertEqual(self.next_hops['R3'], 'R3')
-        self.assertEqual(self.next_hops['R4'], 'R3')
-        self.assertEqual(self.next_hops['R5'], 'R5')
-
-        self.valid_origins['R2'].sort()
-        self.valid_origins['R3'].sort()
-        self.valid_origins['R4'].sort()
-        self.valid_origins['R5'].sort()
-        self.assertEqual(self.valid_origins['R2'], ['R5'])
-        self.assertEqual(self.valid_origins['R3'], ['R5'])
-        self.assertEqual(self.valid_origins['R4'], [])
-        self.assertEqual(self.valid_origins['R5'], ['R2', 'R3'])
+        collection = { 'R2': LinkState(None, 'R2', 1, ['R3', 'R1']),
+                       'R3': LinkState(None, 'R3', 1, ['R1', 'R2', 'R4']),
+                       'R4': LinkState(None, 'R4', 1, ['R3', 'R5']),
+                       'R1': LinkState(None, 'R1', 1, ['R3', 'R5']),
+                       'R5': LinkState(None, 'R5', 1, ['R1', 'R4']),
+                       'R6': LinkState(None, 'R6', 1, ['R5', 'R7']) }
+        next_hops, valid_origins = self.engine.calculate_routes(collection)
+        self.assertEqual(len(next_hops), 4)
+        self.assertEqual(next_hops['R2'], 'R3')
+        self.assertEqual(next_hops['R3'], 'R3')
+        self.assertEqual(next_hops['R4'], 'R3')
+        self.assertEqual(next_hops['R5'], 'R5')
+
+        valid_origins['R2'].sort()
+        valid_origins['R3'].sort()
+        valid_origins['R4'].sort()
+        valid_origins['R5'].sort()
+        self.assertEqual(valid_origins['R2'], ['R5'])
+        self.assertEqual(valid_origins['R3'], ['R5'])
+        self.assertEqual(valid_origins['R4'], [])
+        self.assertEqual(valid_origins['R5'], ['R2', 'R3'])
 
 
 if __name__ == '__main__':



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to