diff --git a/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java b/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java
index 70c80ff91801fcf82f26197725188c615bea59c3..aa675d220558af44cbe8dddfe9904efc08c3ad1e 100644
--- a/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java
+++ b/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java
@@ -18,8 +18,6 @@
 package net.floodlightcontroller.core.util;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 
@@ -38,6 +36,25 @@ public class ListenerDispatcher<U, T extends IListener<U>> {
     protected static Logger logger = LoggerFactory.getLogger(ListenerDispatcher.class);
     List<T> listeners = null;
     
+    private void visit(List<T> newlisteners, U type, HashSet<T> visited, 
+                       List<T> ordering, T listener) {
+        if (!visited.contains(listener)) {
+            visited.add(listener);
+            
+            for (T i : newlisteners) {
+                if (ispre(type, i, listener)) {
+                    visit(newlisteners, type, visited, ordering, i);
+                }
+            }
+            ordering.add(listener);
+        }
+    }
+    
+    private boolean ispre(U type, T l1, T l2) {
+        return (l2.isCallbackOrderingPrereq(type, l1.getName()) ||
+                l1.isCallbackOrderingPostreq(type, l2.getName()));
+    }
+    
     /**
      * Add a listener to the list of listeners
      * @param listener
@@ -48,31 +65,36 @@ public class ListenerDispatcher<U, T extends IListener<U>> {
             newlisteners.addAll(listeners);
 
         newlisteners.add(listener);
-        
-        // compute transitive closure of dependencies
-        HashSet<String> deps = new HashSet<String>();
-        for (T k : newlisteners) {
-            for (T i : newlisteners) {
-                for (T j : newlisteners) {
-                    boolean ispre = 
-                        (i.isCallbackOrderingPrereq(type, j.getName()) ||
-                         j.isCallbackOrderingPostreq(type, i.getName()));
-                    if (ispre || 
-                            (deps.contains(i.getName() + "|||" + k.getName()) &&
-                             deps.contains(k.getName() + "|||" + j.getName()))) {
-                        deps.add(i.getName() + "|||" + j.getName());
-                        // Check for dependency cycle
-                        if (deps.contains(j.getName() + "|||" + i.getName())) {
-                            logger.error("Cross dependency cycle between {} and {}",
-                                      i.getName(), j.getName());
-                        }
-                    }
+        // Find nodes without outgoing edges
+        List<T> terminals = new ArrayList<T>(); 
+        for (T i : newlisteners) {
+            boolean isterm = true;
+            for (T j : newlisteners) {
+                if (ispre(type, i, j)) {
+                    isterm = false;
+                    break;
                 }
             }
+            if (isterm) {
+                terminals.add(i);
+            }
         }
         
-        Collections.sort(newlisteners, new ListenerComparator(deps));
-        listeners = newlisteners;
+        if (terminals.size() == 0) {
+            logger.error("No listener dependency solution: " +
+            		     "No listeners without incoming dependencies");
+            listeners = newlisteners;
+            return;
+        }
+        
+        // visit depth-first traversing in the opposite order from
+        // the dependencies.  Note we will not generally detect cycles
+        HashSet<T> visited = new HashSet<T>();
+        List<T> ordering = new ArrayList<T>(); 
+        for (T term : terminals) {
+            visit(newlisteners, type, visited, ordering, term);
+        }
+        listeners = ordering;
     }
 
     /**
@@ -102,27 +124,4 @@ public class ListenerDispatcher<U, T extends IListener<U>> {
     public List<T> getOrderedListeners() {
         return listeners;
     }
-    
-    /**
-     * Comparator for listeners to use with computed transitive dependencies
-     * 
-     * @author readams
-     *
-     */
-    protected class ListenerComparator implements Comparator<IListener<U>> {
-        HashSet<String> deps;
-        
-        ListenerComparator(HashSet<String> deps) {
-            this.deps = deps;
-        }
-        
-        @Override
-        public int compare(IListener<U> arg0, IListener<U> arg1) {
-            if (deps.contains(arg0.getName() + "|||" + arg1.getName()))
-                return 1;
-            else if (deps.contains(arg1.getName() + "|||" + arg0.getName()))
-                return -1;
-            return 0;  // strictly partial ordering
-        }
-    }
 }
diff --git a/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java b/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java
index a253245a031a6a4f1ed679d6bb9ab2d47665d35d..0829aa447f4d211b0e207c45a0527b7a825906b9 100644
--- a/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java
+++ b/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java
@@ -22,6 +22,10 @@ import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
 import org.junit.Test;
 import org.openflow.protocol.OFType;
 
@@ -30,57 +34,120 @@ import net.floodlightcontroller.test.FloodlightTestCase;
 
 public class MessageDispatcherTest extends FloodlightTestCase {
 
-    /**
-     * Verify that our callbacks are ordered with respect to the order specified
-     * @throws Exception
-     */
-    @Test
-    public void testCallbackOrderingBase() throws Exception {
-        testCallbackOrdering(new String[] {"topology"}, new String[] {"topology"});
-        testCallbackOrdering(new String[] {"learningswitch","topology"}, new String[] {"learningswitch","topology"});
-        testCallbackOrdering(new String[] {"topology","devicemanager","learningswitch"}, new String[] {"topology","devicemanager","learningswitch"});
-        testCallbackOrdering(new String[] {"topology","devicemanager","routing","learningswitch"}, new String[] {"topology","devicemanager","routing","learningswitch"});
-        testCallbackOrdering(new String[] {"devicemanager","topology","learningswitch","routing"}, new String[] {"topology","devicemanager","routing","learningswitch"});
+    IOFMessageListener createLMock(String name) {
+        IOFMessageListener mock = createNiceMock(IOFMessageListener.class);
+        expect(mock.getName()).andReturn(name).anyTimes();
+        return mock;
     }
-
-    protected void testCallbackOrdering(String[] addOrder, String[] verifyOrder) throws Exception {
+    
+    void addPrereqs(IOFMessageListener mock, String... deps) {
+        for (String dep : deps) {
+            expect(mock.isCallbackOrderingPrereq(OFType.PACKET_IN, dep)).andReturn(true).anyTimes();
+        }
+    }
+    
+    void testOrdering(ArrayList<IOFMessageListener> inputListeners) {
         ListenerDispatcher<OFType, IOFMessageListener> ld = 
-            new ListenerDispatcher<OFType, IOFMessageListener>();
-
-        IOFMessageListener topology = createNiceMock(IOFMessageListener.class);
-        IOFMessageListener devicemanager = createNiceMock(IOFMessageListener.class);
-        IOFMessageListener routing = createNiceMock(IOFMessageListener.class);
-        IOFMessageListener learningswitch = createNiceMock(IOFMessageListener.class);
-
-        expect(topology.getName()).andReturn("topology").anyTimes();
-        expect(devicemanager.getName()).andReturn("devicemanager").anyTimes();
-        expect(routing.getName()).andReturn("routing").anyTimes();
-        expect(learningswitch.getName()).andReturn("learningswitch").anyTimes();
-
-        expect(devicemanager.isCallbackOrderingPrereq(OFType.PACKET_IN, "topology")).andReturn(true).anyTimes();
-        expect(routing.isCallbackOrderingPrereq(OFType.PACKET_IN, "topology")).andReturn(true).anyTimes();
-        expect(routing.isCallbackOrderingPrereq(OFType.PACKET_IN, "devicemanager")).andReturn(true).anyTimes();
-        expect(learningswitch.isCallbackOrderingPrereq(OFType.PACKET_IN, "routing")).andReturn(true).anyTimes();
-        expect(learningswitch.isCallbackOrderingPrereq(OFType.PACKET_IN, "devicemanager")).andReturn(true).anyTimes();
+                new ListenerDispatcher<OFType, IOFMessageListener>();
+        
+        for (IOFMessageListener l : inputListeners) {
+            ld.addListener(OFType.PACKET_IN, l);
+        }
+        for (IOFMessageListener l : inputListeners) {
+            verify(l);
+        }
+        
+        List<IOFMessageListener> result = ld.getOrderedListeners();
+        System.out.print("Ordering: ");
+        for (IOFMessageListener l : result) {
+            System.out.print(l.getName());
+            System.out.print(",");
+        }
+        System.out.print("\n");
 
-        replay(topology, devicemanager, routing, learningswitch);
-        for (String o : addOrder) {
-            if ("topology".equals(o)) {
-                ld.addListener(OFType.PACKET_IN, topology);
-            } else if ("devicemanager".equals(o)) {
-                ld.addListener(OFType.PACKET_IN, devicemanager);
-            } else if ("routing".equals(o)) {
-                ld.addListener(OFType.PACKET_IN, routing);
-            } else {
-                ld.addListener(OFType.PACKET_IN, learningswitch);
+        for (int ind_i = 0; ind_i < result.size(); ind_i++) {
+            IOFMessageListener i = result.get(ind_i);
+            for (int ind_j = ind_i+1; ind_j < result.size(); ind_j++) {
+                IOFMessageListener j = result.get(ind_j);
+                
+                boolean orderwrong = 
+                        (i.isCallbackOrderingPrereq(OFType.PACKET_IN, j.getName()) ||
+                         j.isCallbackOrderingPostreq(OFType.PACKET_IN, i.getName()));
+                assertFalse("Invalid order: " + 
+                            ind_i + " (" + i.getName() + ") " + 
+                            ind_j + " (" + j.getName() + ") ", orderwrong);
             }
         }
+    }
+    
+    void randomTestOrdering(ArrayList<IOFMessageListener> mocks) {
+        Random rand = new Random(0);
+        ArrayList<IOFMessageListener> random = 
+                new ArrayList<IOFMessageListener>();
+        random.addAll(mocks);
+        for (int i = 0; i < 20; i++) {
+            for (int j = 0; j < random.size(); j++) {
+                int ind = rand.nextInt(mocks.size()-1);
+                IOFMessageListener tmp = random.get(j);
+                random.set(j, random.get(ind));
+                random.set(ind, tmp);
+            }
+            testOrdering(random);
+        }
+    }
+    
+    @Test
+    public void testCallbackOrderingSimple() throws Exception {
+        ArrayList<IOFMessageListener> mocks = 
+                new ArrayList<IOFMessageListener>();
+        for (int i = 0; i < 10; i++) {
+            mocks.add(createLMock(""+i));
+        }
+        for (int i = 1; i < 10; i++) {
+            addPrereqs(mocks.get(i), ""+(i-1));
+        }
+        for (IOFMessageListener l : mocks) {
+            replay(l);
+        }
+        randomTestOrdering(mocks);
+    }
 
-        verify(topology, devicemanager, routing, learningswitch);
-        for (int i = 0; i < verifyOrder.length; ++i) {
-            String o = verifyOrder[i];
-            assertEquals(o, ld.getOrderedListeners().get(i).getName());
+    @Test
+    public void testCallbackOrderingPartial() throws Exception {
+        ArrayList<IOFMessageListener> mocks = 
+                new ArrayList<IOFMessageListener>();
+        for (int i = 0; i < 10; i++) {
+            mocks.add(createLMock(""+i));
+        }
+        for (int i = 1; i < 5; i++) {
+            addPrereqs(mocks.get(i), ""+(i-1));
+        }
+        for (int i = 6; i < 10; i++) {
+            addPrereqs(mocks.get(i), ""+(i-1));
         }
+        for (IOFMessageListener l : mocks) {
+            replay(l);
+        }
+        randomTestOrdering(mocks);
     }
+    
 
+    @Test
+    public void testCallbackOrderingPartial2() throws Exception {
+        ArrayList<IOFMessageListener> mocks = 
+                new ArrayList<IOFMessageListener>();
+        for (int i = 0; i < 10; i++) {
+            mocks.add(createLMock(""+i));
+        }
+        for (int i = 2; i < 5; i++) {
+            addPrereqs(mocks.get(i), ""+(i-1));
+        }
+        for (int i = 6; i < 9; i++) {
+            addPrereqs(mocks.get(i), ""+(i-1));
+        }
+        for (IOFMessageListener l : mocks) {
+            replay(l);
+        }
+        randomTestOrdering(mocks);
+    }
 }