User:David MacQuigg/Sandbox/Shortest path routing: Difference between revisions

From Citizendium
Jump to navigation Jump to search
imported>David MacQuigg
No edit summary
imported>David MacQuigg
No edit summary
 
(18 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Image|Shortest Path.png||350px|'''Figure 1.  Computing the shortest path through a network'''}}
'''Shortest path routing''' refers to the process of finding paths through a network that have a minimum of distance or other cost metricRouting of data packets on the [[Internet]] is an example involving millions of [[router|routers]] in a complex, worldwide, multilevel network.  Optimum routing on the Internet has a major impact on performance and cost.
{{Image|Shortest Path2.png||350px|'''Figure 1Computing the shortest path through a network'''}}
{{Image|DijkTime.png||350px|'''Figure 2Time to build routing table using program here'''}}


'''Shortest path routing''' refers to the process of finding paths through a network that have a minimum of distance or other cost metric.  Routing of data packets on the [[Internet]] is an example involving millions of routers in a complex, worldwide, multilevel networkOptimum routing on the Internet has a major impact on performance and cost.
This article will explain the basic routing algorithm <ref>E.W. Dijkstra (1959) "A note on two problems in connexion with graphs", ''Numerische Mathematik'' 1: 269–271.</ref> that underlies the [[routing|routing protocols]] used in real networksA firm understanding of this algorithm will help in studying those protocols.


This article will explain the basic routing algorithm <ref>E.W. Dijkstra (1959)</ref> that underlies the [[routing|routing protocols]] used in real networks.  A firm understanding of this algorithm will help in studying those protocols.
The algorithm is presented here in [[Python]], a computer language designed for maximum readability.  Computer networks texts often use pseudocode or C to explain algorithms.  The problem with pseudocode is it can give you a temporary feeling of understanding, which is lost when you try to actually implement the algorithm. Then you may stumble on the ambiguities you didn't notice in the pseudocode, or find that real programs just don't work that way.   The problem with C is that it is too low level.  It's great for speed and efficiency, but you may get lost in the details of pointers and indices.  You can follow every statement, and still not understand the algorithm.  If you are not familiar with Python, see [[Dijkstra59.py]] for a more heavily-annotated version of this program, or [[Dijkstra59.c]] for the same thing in C.


The algorithm is presented here in [[Python]], a computer language designed for maximum readability. Computer networks texts often use pseudocode or C to explain algorithmsThe problem with pseudocode is it can give you a temporary feeling of understanding, which is lost when you try to actually implement the algorithm, and stumble on the ambiguities you didn't notice, or find that real programs just don't work that way.   The problem with C is that it is too low level.  It's great for speed and efficiency, but you may get lost in the details of pointers and indicesYou can follow every statement, and still not understand the algorithm.  If you are not familiar with Python, see [[Dijkstra59.py]] for an annotated version of this program.
{{Image|Shortest Path.png||350px|'''Figure 1Computing the shortest path through a network'''}}
 
{{Image|Shortest Path2.png||350px|'''Figure 1Computing the shortest path through a network'''}}
{{reflist}}


<pre>
<pre>
# dijkstra59v04.py           Dijkstra's Algorithm                   DMQ 12/16/09
# dijkstra59v05.py             Dijkstra's Algorithm               DMQ 12/23/09
'''
Use Dijkstra's algorithm to compute the shortest paths from a given
source node to all other nodes in a network. Links are bi-directional,
with the same distance in either direction.
'''
'''
Use Dijkstra's algorithm to compute the shortest paths from a given source node
to all other nodes in a network. Links are bi-directional, with the same
distance in either direction.  Distance can be any measure of cost.
~'''
# Example from Figure 1 (8 nodes, 11 links)
# Example from Figure 1 (8 nodes, 11 links)
nodeset = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'}
nodeset = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'}
Line 23: Line 21:
linklist = [('A', 'B', 2), ('B', 'C', 7), ('C', 'D', 3), # (node,node,distance)
linklist = [('A', 'B', 2), ('B', 'C', 7), ('C', 'D', 3), # (node,node,distance)
             ('B', 'E', 2), ('E', 'F', 2), ('F', 'C', 3),
             ('B', 'E', 2), ('E', 'F', 2), ('F', 'C', 3),
             ('A', 'G', 6), ('G', 'E', 1), ('G', 'H', 4),
             ('A', 'G', 6), ('G', 'D', 2),              ]
             ('F', 'H', 2), ('H', 'D', 2),              ]
'E', 1), ('G', 'H', 4),
 
             ('F', 'H', 2), ('H',
INF = int(1e9)  # larger than any possible path
INF = int(1e9)  # larger than any possible path
'''
'''
Line 37: Line 35:
show its distance from the source, and the previous node on the path from which
show its distance from the source, and the previous node on the path from which
that distance was computed.  As new nodes are first probed, they are added to a
that distance was computed.  As new nodes are first probed, they are added to a
working set, shown with an open circle.  After each probe cycle, we look at the
working set, shown with a darkened open circle.  After each probe cycle, we look
entire set of working nodes.  The node with the shortest path is moved to a
at the entire set of working nodes.  The node with the shortest path is moved to
final set, shown with a solid circle.  Figure 1b shows the situation after the
a final set, shown with a solid circle.  Figure 1b shows the situation after the
first probes from node 'A', with one node in the final set, and two nodes in the
first probes from node 'A', with one node in the final set, and two nodes in the
working set.
working set.
Line 49: Line 47:
method works.  The node with the shortest path in a working set can never get
method works.  The node with the shortest path in a working set can never get
any shorter, because subsequent probes can only come from other working nodes,
any shorter, because subsequent probes can only come from other working nodes,
and those paths are already at least as long.
and those paths are already at least as long.  There are no negative links.


Figure 1i shows the final tree for node A.  The light dotted lines are links not
Figure 1i shows the final tree for node A.  The light dotted lines are links not
Line 55: Line 53:
however.  Each node in a network can compute its own shortest path tree, given
however.  Each node in a network can compute its own shortest path tree, given
the linklist for the entire network.
the linklist for the entire network.
'''
~'''
def get_anodes(nodeset, linklist):
 
     '''Create a dictionary to quickly look up the adjacent nodes for any given
def get_LSDB(nodeset, linklist):
node.
     '''Create a Link State Database to quickly look up the adjacent nodes for
any given node.


>>> get_anodes(nodeset, linklist)
>>> get_LSDB(nodeset, linklist)
{'A': {('B', 2), ('G', 6)}, 'C': {('B', 7), ('F', 3), ('D', 3)}, \
{'A': {('B', 2), ('G', 6)}, 'C': {('B', 7), ('F', 3), ('D', 3)}, \
'B': {('C', 7), ('E', 2), ('A', 2)}, 'E': {('B', 2), ('G', 1), ('F', 2)}, \
'B': {('C', 7), ('E', 2), ('A', 2)}, 'E': {('B', 2), ('G', 1), ('F', 2)}, \
Line 66: Line 65:
'F': {('H', 2), ('E', 2), ('C', 3)}, 'H': {('G', 4), ('D', 2), ('F', 2)}}
'F': {('H', 2), ('E', 2), ('C', 3)}, 'H': {('G', 4), ('D', 2), ('F', 2)}}


     '''
     ~'''
     anodes = {n:set() for n in nodeset} # start with empty set for each node
     LSDB = {n:set() for n in nodeset} # start with empty set for each node
     for (n1, n2, x) in linklist:
     for (n1, n2, d) in linklist:
         anodes[n1].add((n2, x))
         LSDB[n1].add((n2, d))
         anodes[n2].add((n1, x))
         LSDB[n2].add((n1, d))
          
          
     return anodes
     return LSDB


def build_tree(src, anodes):
def build_tree(src, LSDB):
     '''Given a source node and a table of adjacent nodes for every node in a
     '''Given a source node and a Link State Database for the network, return a
network, return a table with two values for each node - the distance on the
table with two values for each node - the distance on the shortest path from the
shortest path from the source to that node, and the name of the next-to-last
source to that node, and the name of the last node on that path before the final
node on that path.
node.  Saving the previous node makes it easy to re-construct an entire path,
from any leaf to the root of the tree.


A tree is more versatile than a routing table, because the last link along
>>> build_tree('A', LSDB)
every path is preserved, making it easy to reconstruct the path, as in Figure 1.
   
>>> build_tree('A', anodes)
{'A': ('A', 0), 'C': ('B', 9), 'B': ('A', 2), 'E': ('B', 4), \
{'A': ('A', 0), 'C': ('B', 9), 'B': ('A', 2), 'E': ('B', 4), \
'D': ('H', 10), 'G': ('E', 5), 'F': ('E', 6), 'H': ('F', 8)}
'D': ('H', 10), 'G': ('E', 5), 'F': ('E', 6), 'H': ('F', 8)}
     '''
 
     # Current working node, and its distance from src
     ~'''
     wrk = src; dist = 0
     # Current working node
     wrk = src
      
      
     # Nodes in the working set and final set, saved as dictionaries.
     # Nodes in the working set and final set, saved as dictionaries.
     #  {key: value} = {nodename: label}
     #  {key: value} = {nodename: (previous node, distance from src) }
    #      label = (previous node along path, distance from src)
     Wset = {}; Fset = {}
     Wset = {}; Fset = {}
     Fset[wrk] = (wrk, 0) # starting node is always in Fset
     Wset[wrk] = (wrk, 0)           # {'A': ('A', 0)}
    for (n, d) in anodes[wrk]:
        label = (wrk, d)
        Wset[n] = label


     while Wset:  # loop until the working set is empty
     while Wset:  # loop until the work set is empty
    
    
         # Find the shortest distance in the working set, and make that node the
         # Select next wrk node
        # new working node. The distance of that node will never get smaller.
         dist = INF
         dist = INF
         for node in Wset:
         for node in Wset:           # Find the shortest distance in the
             d = Wset[node][1]
             (prev, d) = Wset[node] # working set, and make that node the
             if d < dist:
             if d < dist:           # new working node. The distance of that
                 dist = d
                 dist = d           # node will never get smaller.
                 wrk = node
                 wrk = node
 
       
         # Move the new working node to the final set.         
         # Move the new working node to the final set.         
         Fset[wrk] = Wset[wrk]
         Fset[wrk] = Wset[wrk]
         del Wset[wrk]
         del Wset[wrk]
        last = wrk                  # last node before end of path


         # Probe the nodes adjacent to wrk.     
         # Expand the work set
         for (n, d) in anodes[wrk]:
         for (n, d) in LSDB[wrk]:     # Probe the nodes adjacent to wrk     


             new_dist = dist + d
             new_dist = dist + d         # probe distance
              
              
             if n in Fset:               # skip this node, already finalized
             if n in Fset:
                continue
                continue                # skip this node, already finalized
              
              
             elif (n in Wset) and (new_dist >= Wset[n][1]):
             elif (n in Wset) and (new_dist >= Wset[n][1]):
                 continue                # skip this probe, too long           
                 continue                # skip this node, probe too long           


             else:  # Add new node to working set, or update existing node.
             else:  # Add new node to working set, or update existing node
                 Wset[n] = (wrk, new_dist)
                 Wset[n] = (last, new_dist)
      
      
     return Fset
     return Fset


def build_routing_table(src, anodes):
def build_RT(src, LSDB):
     '''Build a routing table directly from the anodes map.  The table has two
     '''Given a source node and a Link State Database for the network, return a
items for every destination node - the first step from src, and the total
table with three values for each node - the distance on the shortest path from
distance along the shortest path.
the source to that destination node, and the names of the first and last nodes
on the path, not including the endpoints. The first node is needed in a routing
table.  The last node is needed to construct a tree with src at the root.
 
>>> build_RT('A', LSDB)
{'A': ('A', 'A', 0), 'C': ('B', 'B', 9), 'B': ('B', 'A', 2), \
'E': ('B', 'B', 4), 'D': ('B', 'H', 10), 'G': ('B', 'E', 5), \
'F': ('B', 'E', 6), 'H': ('B', 'F', 8)}
 
    ~~'''
    # Current working node
    wrk = src


>>> build_routing_table('A', anodes)
{'A': ('A', 0), 'C': ('B', 9), 'B': ('B', 2), 'E': ('B', 4), 'D': ('B', 10), \
'G': ('B', 5), 'F': ('B', 6), 'H': ('B', 8)}
    '''
    # Current working node, and its distance from src
    wrk = src; dist = 0
   
     # Nodes in the working set and final set, saved as dictionaries.
     # Nodes in the working set and final set, saved as dictionaries.
     #  {key: value} = {nodename: label}
     #  {key: value} = {nodename: (first, last, distance from src)}
    #      label = (first node along path, distance from src)
     Wset = {}; Fset = {}
     Wset = {}; Fset = {}
    # Special setup for first step
    Fset[wrk] = (wrk, wrk, 0)      # {'A': ('A', 'A', 0)}
    for (n, d) in LSDB[wrk]:
        first = n                  # first step on the new route
        last = wrk
        Wset[n] = (first, last, d) # {'B': ('B', 'A', 2), 'G': ('G', 'A', 6)}
      
      
    Fset[wrk] = (wrk, 0)  # starting node is always in Fset
    for (n, d) in anodes[wrk]:
        first = n            # first step on the new route
        Wset[n] = (first, d)  # label each new node in working set
     while Wset:  # loop until the working set is empty
     while Wset:  # loop until the working set is empty
       
 
        # Select next wrk node
         dist = INF
         dist = INF
         for node in Wset:     # Find the shortest distance in the
         for node in Wset:           # Find the shortest distance in the
             d = Wset[node][1]  # working set, and make that node the
             (first, last, d) = Wset[node]  # working set, and make that node
             if d < dist:       # new working node. The distance of
             if d < dist:           # the new working node. The distance of
                 dist = d       # that node will never get smaller.
                 dist = d           # that node will never get smaller.
                 wrk = node
                 wrk = node
 
       
         # Move the new working node to the final set.        
         # Move the new working node to the final set         
         Fset[wrk] = Wset[wrk]
         Fset[wrk] = Wset[wrk]
        first = Wset[wrk][0]  # preserve the first step on the route.
         del Wset[wrk]
         del Wset[wrk]
        # Update first and last hops
        first = Fset[wrk][0]
        last = wrk


         # Probe the nodes adjacent to wrk.
         # Expand the work set
         for (n, d) in anodes[wrk]:
         for (n, d) in LSDB[wrk]:     # Probe the nodes adjacent to wrk     


             new_dist = dist + d
             new_dist = dist + d         # probe distance
              
              
             if n in Fset:               # skip this node, already finalized.
             if n in Fset:
                continue
                continue                # skip this node, already finalized
              
              
             elif (n in Wset) and (new_dist >= Wset[n][1]):
             elif (n in Wset) and (new_dist >= Wset[n][2]):
                 continue                # skip this probe, too long.            
                 continue                # skip this node, probe too long           


             else:  # Add new node to working set, or update existing node.
             else:  # Add new node to working set, or update existing node
                 Wset[n] = (first, new_dist)
                 Wset[n] = (first, last, new_dist)
      
      
     return Fset
     return Fset
</pre>
{{Image|DijkTime.png||350px|'''Figure 2.  Time to build routing table using the Python program here'''}}
== Limitations ==
The main limitations of simple shortest-path routing have to do with real-world problems that occur in large networks.  We can't just keep adding nodes to a huge routing table at every node.  As shown in Figure 2, the time to build (or re-build) a table increases as the square of the number of nodes.  Also, as nodes are added, the number of failing links, changes in topology, and other events that trigger re-builds throughout the network - these events will occur more frequently. 
Aside from these technical limitations, there are administrative headaches that come with huge networks, and these often set a size limit far short of what is technically possible.  A campus-wide network might have 100 nodes with only two connections to the outside world, and no desire to add nodes managed by businesses in the same city.  Those businesses might be better served by a city-wide network that includes one of the campus "gateway" nodes.  The city-wide network might include a few hundred nodes that all have routing table entries for each other, but only one entry for all the nodes on campus.  Similarly, the city network might look like just one node in a larger regional network.  [[Hierarchical routing]] is one way to partition a network.
A routing algorithm is not enough to design a network.  We need a complete routing protocol to deal with real-world issues.  The [[Routing protocol] articles will discuss how we handle issues such as:
partitioning - hierarchical is not the only possibility<br>
rapid recovery - minimize the time that the routing tables are "out of sync" with the actual topology<br>
preferential routing - voice packets must not have a noticeable delay<br>
load balancing - don't overload the shortest path<br>
security - keep the bad guys from diverting traffic<br>
policy overrides - block our competitors, even if they are coming through one of our customers<br>


def get_path(dest, tree):
    '''Given destination node, and the dictionary returned by build_tree(),
return the shortest path from the top of the tree to dest.


>>> get_path('D', tree)
{{reflist}}
['A', 'B', 'E', 'F', 'H', 'D']
    '''
    wrk = dest  # Work backward from the destination node.
    prev = tree[wrk][0]  # previous node along path
    path = [wrk]
   
    while wrk != prev:      # top has no step back (wrk = prev)
        path.insert(0, prev)    # insert at beginning of list
        wrk = prev
        prev = tree[wrk][0]


    return path
=== Parent topics ===
[[Computer network]]<br />
[[Routing]]<br />


</pre>
=== Related topics ===
[[Routing protocol]]<br />

Latest revision as of 21:06, 15 January 2021

Shortest path routing refers to the process of finding paths through a network that have a minimum of distance or other cost metric. Routing of data packets on the Internet is an example involving millions of routers in a complex, worldwide, multilevel network. Optimum routing on the Internet has a major impact on performance and cost.

This article will explain the basic routing algorithm [1] that underlies the routing protocols used in real networks. A firm understanding of this algorithm will help in studying those protocols.

The algorithm is presented here in Python, a computer language designed for maximum readability. Computer networks texts often use pseudocode or C to explain algorithms. The problem with pseudocode is it can give you a temporary feeling of understanding, which is lost when you try to actually implement the algorithm. Then you may stumble on the ambiguities you didn't notice in the pseudocode, or find that real programs just don't work that way. The problem with C is that it is too low level. It's great for speed and efficiency, but you may get lost in the details of pointers and indices. You can follow every statement, and still not understand the algorithm. If you are not familiar with Python, see Dijkstra59.py for a more heavily-annotated version of this program, or Dijkstra59.c for the same thing in C.

Figure 1. Computing the shortest path through a network
Figure 1. Computing the shortest path through a network
# dijkstra59v05.py              Dijkstra's Algorithm               DMQ 12/23/09
'''
Use Dijkstra's algorithm to compute the shortest paths from a given source node
to all other nodes in a network. Links are bi-directional, with the same
distance in either direction.  Distance can be any measure of cost.
~'''

# Example from Figure 1 (8 nodes, 11 links)
nodeset = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'}

linklist = [('A', 'B', 2), ('B', 'C', 7), ('C', 'D', 3), # (node,node,distance)
            ('B', 'E', 2), ('E', 'F', 2), ('F', 'C', 3),
            ('A', 'G', 6), ('G', 'D', 2),               ]
 'E', 1), ('G', 'H', 4),
            ('F', 'H', 2), ('H',
INF = int(1e9)  # larger than any possible path
'''
The strategy is to start at the source node, send probes to each of its adjacent
nodes, pick the node with the shortest path from the source, and make that the
new working node.  Send probes from the new working node, pick the next shortest
path, and make that the next working node.  Continue selecting the shortest
possible path until every every node in the network has been selected.

Figure 1 shows the first few steps in our example network. Labels on each node
show its distance from the source, and the previous node on the path from which
that distance was computed.  As new nodes are first probed, they are added to a
working set, shown with a darkened open circle.  After each probe cycle, we look
at the entire set of working nodes.  The node with the shortest path is moved to
a final set, shown with a solid circle.  Figure 1b shows the situation after the
first probes from node 'A', with one node in the final set, and two nodes in the
working set.

The labels on nodes in the working set are tentative.  They will be replaced if
another probe arrives with a shorter total path.  Figure 1d shows node G getting
an update of its label after a probe from node E.  The updates at a node stop
when no other working set node has a shorter path.  This is the proof that the
method works.  The node with the shortest path in a working set can never get
any shorter, because subsequent probes can only come from other working nodes,
and those paths are already at least as long.  There are no negative links.

Figure 1i shows the final tree for node A.  The light dotted lines are links not
used in any shortest path from node A.  They might be used in another tree,
however.  Each node in a network can compute its own shortest path tree, given
the linklist for the entire network.
~'''

def get_LSDB(nodeset, linklist):
    '''Create a Link State Database to quickly look up the adjacent nodes for
any given node.

>>> get_LSDB(nodeset, linklist)
{'A': {('B', 2), ('G', 6)}, 'C': {('B', 7), ('F', 3), ('D', 3)}, \
'B': {('C', 7), ('E', 2), ('A', 2)}, 'E': {('B', 2), ('G', 1), ('F', 2)}, \
'D': {('H', 2), ('C', 3)}, 'G': {('A', 6), ('E', 1), ('H', 4)}, \
'F': {('H', 2), ('E', 2), ('C', 3)}, 'H': {('G', 4), ('D', 2), ('F', 2)}}

    ~'''
    LSDB = {n:set() for n in nodeset} # start with empty set for each node
    for (n1, n2, d) in linklist:
        LSDB[n1].add((n2, d))
        LSDB[n2].add((n1, d))
        
    return LSDB

def build_tree(src, LSDB):
    '''Given a source node and a Link State Database for the network, return a
table with two values for each node - the distance on the shortest path from the
source to that node, and the name of the last node on that path before the final
node.  Saving the previous node makes it easy to re-construct an entire path,
from any leaf to the root of the tree.

>>> build_tree('A', LSDB)
{'A': ('A', 0), 'C': ('B', 9), 'B': ('A', 2), 'E': ('B', 4), \
'D': ('H', 10), 'G': ('E', 5), 'F': ('E', 6), 'H': ('F', 8)}

    ~'''
    # Current working node
    wrk = src
    
    # Nodes in the working set and final set, saved as dictionaries.
    #   {key: value} = {nodename: (previous node, distance from src) }
    Wset = {}; Fset = {}
    Wset[wrk] = (wrk, 0)            # {'A': ('A', 0)}

    while Wset:  # loop until the work set is empty
  
        # Select next wrk node
        dist = INF
        for node in Wset:           # Find the shortest distance in the
            (prev, d) = Wset[node]  # working set, and make that node the
            if d < dist:            # new working node. The distance of that
                dist = d            # node will never get smaller.
                wrk = node
        
        # Move the new working node to the final set.        
        Fset[wrk] = Wset[wrk]
        del Wset[wrk]
        last = wrk                  # last node before end of path

        # Expand the work set
        for (n, d) in LSDB[wrk]:      # Probe the nodes adjacent to wrk      

            new_dist = dist + d          # probe distance
            
            if n in Fset:
                continue                 # skip this node, already finalized
            
            elif (n in Wset) and (new_dist >= Wset[n][1]):
                continue                 # skip this node, probe too long           

            else:  # Add new node to working set, or update existing node
                Wset[n] = (last, new_dist)
    
    return Fset

def build_RT(src, LSDB):
    '''Given a source node and a Link State Database for the network, return a
table with three values for each node - the distance on the shortest path from
the source to that destination node, and the names of the first and last nodes
on the path, not including the endpoints.  The first node is needed in a routing
table.  The last node is needed to construct a tree with src at the root.

>>> build_RT('A', LSDB)
{'A': ('A', 'A', 0), 'C': ('B', 'B', 9), 'B': ('B', 'A', 2), \
'E': ('B', 'B', 4), 'D': ('B', 'H', 10), 'G': ('B', 'E', 5), \
'F': ('B', 'E', 6), 'H': ('B', 'F', 8)}

    ~~'''
    # Current working node
    wrk = src

    # Nodes in the working set and final set, saved as dictionaries.
    #   {key: value} = {nodename: (first, last, distance from src)}
    Wset = {}; Fset = {}

    # Special setup for first step
    Fset[wrk] = (wrk, wrk, 0)      # {'A': ('A', 'A', 0)}
    for (n, d) in LSDB[wrk]:
        first = n                  # first step on the new route
        last = wrk
        Wset[n] = (first, last, d) # {'B': ('B', 'A', 2), 'G': ('G', 'A', 6)}
    
    while Wset:  # loop until the working set is empty
  
        # Select next wrk node
        dist = INF
        for node in Wset:           # Find the shortest distance in the
            (first, last, d) = Wset[node]  # working set, and make that node
            if d < dist:            # the new working node. The distance of
                dist = d            # that node will never get smaller.
                wrk = node
        
        # Move the new working node to the final set        
        Fset[wrk] = Wset[wrk]
        del Wset[wrk]
        # Update first and last hops
        first = Fset[wrk][0]
        last = wrk

        # Expand the work set
        for (n, d) in LSDB[wrk]:      # Probe the nodes adjacent to wrk      

            new_dist = dist + d          # probe distance
            
            if n in Fset:
                continue                 # skip this node, already finalized
            
            elif (n in Wset) and (new_dist >= Wset[n][2]):
                continue                 # skip this node, probe too long           

            else:  # Add new node to working set, or update existing node
                Wset[n] = (first, last, new_dist)
    
    return Fset
Figure 2. Time to build routing table using the Python program here

Limitations

The main limitations of simple shortest-path routing have to do with real-world problems that occur in large networks. We can't just keep adding nodes to a huge routing table at every node. As shown in Figure 2, the time to build (or re-build) a table increases as the square of the number of nodes. Also, as nodes are added, the number of failing links, changes in topology, and other events that trigger re-builds throughout the network - these events will occur more frequently.

Aside from these technical limitations, there are administrative headaches that come with huge networks, and these often set a size limit far short of what is technically possible. A campus-wide network might have 100 nodes with only two connections to the outside world, and no desire to add nodes managed by businesses in the same city. Those businesses might be better served by a city-wide network that includes one of the campus "gateway" nodes. The city-wide network might include a few hundred nodes that all have routing table entries for each other, but only one entry for all the nodes on campus. Similarly, the city network might look like just one node in a larger regional network. Hierarchical routing is one way to partition a network.

A routing algorithm is not enough to design a network. We need a complete routing protocol to deal with real-world issues. The [[Routing protocol] articles will discuss how we handle issues such as:

partitioning - hierarchical is not the only possibility
rapid recovery - minimize the time that the routing tables are "out of sync" with the actual topology
preferential routing - voice packets must not have a noticeable delay
load balancing - don't overload the shortest path
security - keep the bad guys from diverting traffic
policy overrides - block our competitors, even if they are coming through one of our customers


  1. E.W. Dijkstra (1959) "A note on two problems in connexion with graphs", Numerische Mathematik 1: 269–271.

Parent topics

Computer network
Routing

Related topics

Routing protocol