merge with HEAD
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Fri, 28 Nov 2008 08:56:47 +0100
changeset 3954 f6bc20790cb6
parent 3953 4ac29a986eef (current diff)
parent 3949 016c554c4f6d (diff)
child 3955 4ddcca845f07
merge with HEAD
--- a/CHANGES.html	Fri Nov 28 08:55:24 2008 +0100
+++ b/CHANGES.html	Fri Nov 28 08:56:47 2008 +0100
@@ -106,6 +106,14 @@
 </li>
 </ul>
 
+<li>17-11-2008; changeset 
+<a href="http://code.nsnam.org/ns-3-dev/rev/756887a9bbea">756887a9bbea</a></li>
+<ul>
+<li>
+Global routing supports bridge devices.
+</li>
+</ul>
+
 <hr>
 <h1>changes from ns-3.1 to ns-3.2</h1>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-bridge-one-hop.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -0,0 +1,246 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// Network topology
+//
+//         bridge1         The node named bridge1 (node 5 in the nodelist)
+//   ------------------        has three CMSA net devices that are bridged
+//   CSMA   CSMA   CSMA        together using a BridgeNetDevice.
+//     |      |      |
+//     |      |      |     The bridge node talks over three CSMA channels
+//     |      |      |
+//   CSMA   CSMA   CSMA    to three other CSMA net devices
+//   ----   ----   ----    
+//    n0     n1     n2     Node two acts as a router and talks to another
+//                 ----        bridge that connects the remaining nodes.
+//                 CSMA
+//                   |
+//    n3     n4      |
+//   ----   ----     |
+//   CSMA   CSMA     |
+//     |      |      |
+//     |      |      |
+//     |      |      |
+//   CSMA   CSMA   CSMA    The node named bridge2 (node 6 in the nodelist)
+//   ------------------        has three CMSA net devices that are bridged
+//        bridge2              together using a BridgeNetDevice.
+//
+// Or, more abstractly, recognizing that bridge 1 and bridge 2 are nodes 
+// with three net devices:
+//
+//        n0     n1                (n0 = 10.1.1.2)
+//        |      |                 (n1 = 10.1.1.3)  Note odd addressing
+//       -----------               (n2 = 10.1.1.1)
+//       | bridge1 | <- n5  
+//       -----------
+//           |    
+//         router    <- n2
+//           |
+//       -----------
+//       | bridge2 | <- n6
+//       -----------               (n2 = 10.1.2.1)
+//        |      |                 (n3 = 10.1.2.2)
+//        n3     n4                (n4 = 10.1.2.3)
+//
+// So, this example shows two broadcast domains, each interconnected by a bridge
+// with a router node (n2) interconnecting the layer-2 broadcast domains
+// 
+// It is meant to mirror somewhat the csma-bridge example but adds another
+// bridged link separated by a router.
+// 
+// - CBR/UDP flows from n0 (10.1.1.2) to n1 (10.1.1.3) and from n3 (10.1.2.2) to n0 (10.1.1.3)
+// - DropTail queues 
+// - Global static routing
+// - Tracing of queues and packet receptions to file "csma-bridge-one-hop.tr"
+
+#include <iostream>
+#include <fstream>
+
+#include "ns3/simulator-module.h"
+#include "ns3/node-module.h"
+#include "ns3/core-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/bridge-module.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaBridgeOneHopExample");
+
+int 
+main (int argc, char *argv[])
+{
+  //
+  // Users may find it convenient to turn on explicit debugging
+  // for selected modules; the below lines suggest how to do this
+  //
+#if 0 
+  LogComponentEnable ("CsmaBridgeOneHopExample", LOG_LEVEL_INFO);
+#endif
+
+  //
+  // Make the random number generators generate reproducible results.
+  //
+  RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
+
+  //
+  // Allow the user to override any of the defaults and the above Bind() at
+  // run-time, via command-line arguments
+  //
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  //
+  // Explicitly create the nodes required by the topology (shown above).
+  //
+  NS_LOG_INFO ("Create nodes.");
+
+  Ptr<Node> n0 = CreateObject<Node> ();
+  Ptr<Node> n1 = CreateObject<Node> ();
+  Ptr<Node> n2 = CreateObject<Node> ();
+  Ptr<Node> n3 = CreateObject<Node> ();
+  Ptr<Node> n4 = CreateObject<Node> ();
+
+  Ptr<Node> bridge1 = CreateObject<Node> ();
+  Ptr<Node> bridge2 = CreateObject<Node> ();
+
+  NS_LOG_INFO ("Build Topology");
+  CsmaHelper csma;
+  csma.SetChannelAttribute ("DataRate", DataRateValue (5000000));
+  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+
+  // Create the csma links, from each terminal to the bridge
+  // This will create six network devices; we'll keep track separately
+  // of the devices on and off the bridge respectively, for later configuration 
+  NetDeviceContainer topLanDevices;
+  NetDeviceContainer topBridgeDevices;
+
+  // It is easier to iterate the nodes in C++ if we put them into a container
+  NodeContainer topLan (n2, n0, n1);
+
+  for (int i = 0; i < 3; i++)
+    {
+      // install a csma channel between the ith toplan node and the bridge node
+      NetDeviceContainer link = csma.Install (NodeContainer (topLan.Get (i), bridge1));
+      topLanDevices.Add (link.Get (0));
+      topBridgeDevices.Add (link.Get (1));
+    }
+
+  //
+  // Now, Create the bridge netdevice, which will do the packet switching.  The
+  // bridge lives on the node bridge1 and bridges together the topBridgeDevices
+  // which are the three CSMA net devices on the node in the diagram above.
+  //
+  BridgeHelper bridge;
+  bridge.Install (bridge1, topBridgeDevices);
+
+  // Add internet stack to the topLan nodes
+  InternetStackHelper internet;
+  internet.Install (topLan);
+
+  // Repeat for bottom bridged LAN
+  NetDeviceContainer bottomLanDevices;
+  NetDeviceContainer bottomBridgeDevices;
+  NodeContainer bottomLan (n2, n3, n4);
+  for (int i = 0; i < 3; i++)
+    {
+      NetDeviceContainer link = csma.Install (NodeContainer (bottomLan.Get (i), bridge2));
+      bottomLanDevices.Add (link.Get (0));
+      bottomBridgeDevices.Add (link.Get (1));
+    }
+  bridge.Install (bridge2, bottomBridgeDevices);
+
+  // Add internet stack to the bottomLan nodes
+  internet.Install (NodeContainer (n3, n4));
+
+  // We've got the "hardware" in place.  Now we need to add IP addresses.
+  NS_LOG_INFO ("Assign IP Addresses.");
+  Ipv4AddressHelper ipv4;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  ipv4.Assign (topLanDevices);
+  ipv4.SetBase ("10.1.2.0", "255.255.255.0");
+  ipv4.Assign (bottomLanDevices);
+
+  // 
+  // Create router nodes, initialize routing database and set up the routing
+  // tables in the nodes.  We excuse the bridge nodes from having to serve as
+  // routers, since they don't even have internet stacks on them.
+  //
+  NodeContainer routerNodes (n0, n1, n2, n3, n4);
+  GlobalRouteManager::PopulateRoutingTables (routerNodes);
+
+  //
+  // Create an OnOff application to send UDP datagrams from node zero to node 1.
+  //
+  NS_LOG_INFO ("Create Applications.");
+  uint16_t port = 9;   // Discard port (RFC 863)
+
+  OnOffHelper onoff ("ns3::UdpSocketFactory", 
+                     Address (InetSocketAddress (Ipv4Address ("10.1.1.3"), port)));
+  onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
+  onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
+
+  ApplicationContainer app = onoff.Install (n0);
+  // Start the application
+  app.Start (Seconds (1.0));
+  app.Stop (Seconds (10.0));
+
+  // Create an optional packet sink to receive these packets
+  PacketSinkHelper sink ("ns3::UdpSocketFactory",
+                         Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
+  ApplicationContainer sink1 = sink.Install (n1);
+  sink1.Start (Seconds (1.0));
+  sink1.Stop (Seconds (10.0));
+
+  // 
+  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+  //
+  onoff.SetAttribute ("Remote", 
+                      AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.2"), port)));
+  ApplicationContainer app2 = onoff.Install (n3);
+  app2.Start (Seconds (1.1));
+  app2.Stop (Seconds (10.0));
+
+  ApplicationContainer sink2 = sink.Install (n0);
+  sink2.Start (Seconds (1.1));
+  sink2.Stop (Seconds (10.0));
+
+  //
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+  // Trace output will be sent to the file "csma-bridge-one-hop.tr"
+  //
+  NS_LOG_INFO ("Configure Tracing.");
+  std::ofstream ascii;
+  ascii.open ("csma-bridge-one-hop.tr");
+  CsmaHelper::EnableAsciiAll (ascii);
+
+  //
+  // Also configure some tcpdump traces; each interface will be traced.
+  // The output files will be named:
+  //     csma-bridge.pcap-<nodeId>-<interfaceId>
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  //
+  CsmaHelper::EnablePcapAll ("csma-bridge-one-hop");
+
+  //
+  // Now, do the actual simulation.
+  //
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- a/examples/wifi-wired-bridging.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/examples/wifi-wired-bridging.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -1,4 +1,46 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// Default network topology includes some number of AP nodes specified by
+// the variable nWifis (defaults to two).  Off of each AP node, there are some
+// number of STA nodes specified by the variable nStas (defaults to two).
+// Each AP talks to its associated STA nodes.  There are bridge net devices
+// on each AP node that bridge the whole thing into one network.
+//
+//      +-----+      +-----+            +-----+      +-----+
+//      | STA |      | STA |            | STA |      | STA | 
+//      +-----+      +-----+            +-----+      +-----+
+//    192.168.0.3  192.168.0.4        192.168.0.5  192.168.0.6
+//      --------     --------           --------     --------
+//      WIFI STA     WIFI STA           WIFI STA     WIFI STA
+//      --------     --------           --------     --------
+//        ((*))       ((*))       |      ((*))        ((*))
+//                                |   
+//              ((*))             |             ((*))
+//             -------                         -------
+//             WIFI AP   CSMA ========= CSMA   WIFI AP 
+//             -------   ----           ----   -------
+//             ##############           ##############
+//                 BRIDGE                   BRIDGE
+//             ##############           ############## 
+//               192.168.0.1              192.168.0.2
+//               +---------+              +---------+  
+//               | AP Node |              | AP Node |
+//               +---------+              +---------+  
+//
 
 #include "ns3/core-module.h"
 #include "ns3/simulator-module.h"
@@ -46,7 +88,6 @@
   stack.Install (backboneNodes);
 
   backboneDevices = csma.Install (backboneNodes);
-  backboneInterfaces = ip.Assign (backboneDevices);
 
   double wifiX = 0.0;
   for (uint32_t i = 0; i < nWifis; ++i)
@@ -69,7 +110,6 @@
       wifiPhy.SetChannel (wifiChannel.Create ());
 
       sta.Create (nStas);
-      ip.NewNetwork ();
       mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
 				     "MinX", DoubleValue (wifiX),
 				     "MinY", DoubleValue (0.0),
@@ -87,8 +127,12 @@
 		   "BeaconGeneration", BooleanValue (true),
 		   "BeaconInterval", TimeValue (Seconds (2.5)));
       apDev = wifi.Install (wifiPhy, backboneNodes.Get (i));
-      apInterface = ip.Assign (apDev);
-      bridge.Install (backboneNodes.Get (i), NetDeviceContainer (apDev, backboneDevices.Get (i)));
+
+      NetDeviceContainer bridgeDev;
+      bridgeDev = bridge.Install (backboneNodes.Get (i), NetDeviceContainer (apDev, backboneDevices.Get (i)));
+
+      // assign AP IP address to bridge, not wifi
+      apInterface = ip.Assign (bridgeDev);
 
       // setup the STAs
       stack.Install (sta);
--- a/examples/wscript	Fri Nov 28 08:55:24 2008 +0100
+++ b/examples/wscript	Fri Nov 28 08:56:47 2008 +0100
@@ -28,6 +28,10 @@
                                  ['bridge', 'csma', 'internet-stack'])
     obj.source = 'csma-bridge.cc'
 
+    obj = bld.create_ns3_program('csma-bridge-one-hop',
+                                 ['bridge', 'csma', 'internet-stack'])
+    obj.source = 'csma-bridge-one-hop.cc'
+
     obj = bld.create_ns3_program('udp-echo',
                                  ['csma', 'internet-stack'])
     obj.source = 'udp-echo.cc'
--- a/src/applications/v4ping/v4ping.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/applications/v4ping/v4ping.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -149,6 +149,7 @@
 V4Ping::StopApplication (void)
 {
   NS_LOG_FUNCTION (this);
+  m_socket->Close ();
 }
 
 
--- a/src/core/abort.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/core/abort.h	Fri Nov 28 08:56:47 2008 +0100
@@ -21,6 +21,16 @@
 
 #include "fatal-error.h"
 
+#define NS_ABORT_MSG(msg)                                       \
+  do {								\
+    std::cerr << "file=" << __FILE__ <<                         \
+      ", line=" << __LINE__ << ", abort, msg=\"" <<             \
+      msg << "\"" << std::endl;                                 \
+    int *a = 0;                                                 \
+    *a = 0;							\
+  } while (false)
+
+
 #define NS_ABORT_IF(cond)					\
   do {								\
     if (cond)							\
--- a/src/devices/bridge/bridge-net-device.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/bridge/bridge-net-device.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -57,6 +57,7 @@
     m_ifIndex (0),
     m_mtu (0xffff)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_channel = CreateObject<BridgeChannel> ();
 }
 
@@ -100,6 +101,7 @@
 BridgeNetDevice::ForwardUnicast (Ptr<NetDevice> incomingPort, Ptr<const Packet> packet,
                                  uint16_t protocol, Mac48Address src, Mac48Address dst)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   NS_LOG_DEBUG ("LearningBridgeForward (incomingPort=" << incomingPort->GetName ()
                 << ", packet=" << packet << ", protocol="<<protocol
                 << ", src=" << src << ", dst=" << dst << ")");
@@ -133,6 +135,7 @@
 BridgeNetDevice::ForwardBroadcast (Ptr<NetDevice> incomingPort, Ptr<const Packet> packet,
                                         uint16_t protocol, Mac48Address src, Mac48Address dst)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   NS_LOG_DEBUG ("LearningBridgeForward (incomingPort=" << incomingPort->GetName ()
                 << ", packet=" << packet << ", protocol="<<protocol
                 << ", src=" << src << ", dst=" << dst << ")");
@@ -154,6 +157,7 @@
 
 void BridgeNetDevice::Learn (Mac48Address source, Ptr<NetDevice> port)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   if (m_enableLearning)
     {
       LearnedState &state = m_learnState[source];
@@ -164,6 +168,7 @@
 
 Ptr<NetDevice> BridgeNetDevice::GetLearnedState (Mac48Address source)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   if (m_enableLearning)
     {
       Time now = Simulator::Now ();
@@ -185,9 +190,25 @@
   return NULL;
 }
 
+uint32_t
+BridgeNetDevice::GetNBridgePorts (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ports.size ();
+}
+
+
+Ptr<NetDevice>
+BridgeNetDevice::GetBridgePort (uint32_t n) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ports[n];
+}
+
 void 
 BridgeNetDevice::AddBridgePort (Ptr<NetDevice> bridgePort)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   NS_ASSERT (bridgePort != this);
   if (!Mac48Address::IsMatchingType (bridgePort->GetAddress ()))
     {
@@ -212,42 +233,49 @@
 void 
 BridgeNetDevice::SetName(const std::string name)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_name = name;
 }
 
 std::string 
 BridgeNetDevice::GetName(void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return m_name;
 }
 
 void 
 BridgeNetDevice::SetIfIndex(const uint32_t index)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_ifIndex = index;
 }
 
 uint32_t 
 BridgeNetDevice::GetIfIndex(void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return m_ifIndex;
 }
 
 Ptr<Channel> 
 BridgeNetDevice::GetChannel (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return m_channel;
 }
 
 Address 
 BridgeNetDevice::GetAddress (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return m_address;
 }
 
 bool 
 BridgeNetDevice::SetMtu (const uint16_t mtu)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_mtu = mtu;
   return true;
 }
@@ -255,6 +283,7 @@
 uint16_t 
 BridgeNetDevice::GetMtu (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return m_mtu;
 }
 
@@ -262,6 +291,7 @@
 bool 
 BridgeNetDevice::IsLinkUp (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return true;
 }
 
@@ -274,6 +304,7 @@
 bool 
 BridgeNetDevice::IsBroadcast (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return true;
 }
 
@@ -281,12 +312,14 @@
 Address
 BridgeNetDevice::GetBroadcast (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return Mac48Address ("ff:ff:ff:ff:ff:ff");
 }
 
 bool
 BridgeNetDevice::IsMulticast (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return true;
 }
 
@@ -302,13 +335,22 @@
 bool 
 BridgeNetDevice::IsPointToPoint (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return false;
 }
 
+bool 
+BridgeNetDevice::IsBridge (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
 
 bool 
 BridgeNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   for (std::vector< Ptr<NetDevice> >::iterator iter = m_ports.begin ();
          iter != m_ports.end (); iter++)
     {
@@ -322,6 +364,7 @@
 bool 
 BridgeNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   for (std::vector< Ptr<NetDevice> >::iterator iter = m_ports.begin ();
          iter != m_ports.end (); iter++)
     {
@@ -336,6 +379,7 @@
 Ptr<Node> 
 BridgeNetDevice::GetNode (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return m_node;
 }
 
@@ -343,6 +387,7 @@
 void 
 BridgeNetDevice::SetNode (Ptr<Node> node)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_node = node;
 }
 
@@ -350,6 +395,7 @@
 bool 
 BridgeNetDevice::NeedsArp (void) const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return true;
 }
 
@@ -357,25 +403,28 @@
 void 
 BridgeNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_rxCallback = cb;
 }
 
 void 
 BridgeNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_promiscRxCallback = cb;
 }
 
 bool
 BridgeNetDevice::SupportsSendFrom () const
 {
+  NS_LOG_FUNCTION_NOARGS ();
   return true;
 }
 
-
 void
 BridgeNetDevice::DoDispose (void)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_node = 0;
   NetDevice::DoDispose ();
 }
--- a/src/devices/bridge/bridge-net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/bridge/bridge-net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -82,6 +82,10 @@
    */
   void AddBridgePort (Ptr<NetDevice> bridgePort);
 
+  uint32_t GetNBridgePorts (void) const;
+
+  Ptr<NetDevice> GetBridgePort (uint32_t n) const;
+
   // inherited from NetDevice base class.
   virtual void SetName(const std::string name);
   virtual std::string GetName(void) const;
@@ -98,6 +102,7 @@
   virtual bool IsMulticast (void) const;
   virtual Address GetMulticast (Ipv4Address multicastGroup) const;
   virtual bool IsPointToPoint (void) const;
+  virtual bool IsBridge (void) const;
   virtual bool Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
   virtual bool SendFrom (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
   virtual Ptr<Node> GetNode (void) const;
--- a/src/devices/csma/csma-net-device.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/csma/csma-net-device.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -837,6 +837,13 @@
   return false;
 }
 
+  bool 
+CsmaNetDevice::IsBridge (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return false;
+}
+
   bool
 CsmaNetDevice::Send (Ptr<Packet> packet,const Address& dest, uint16_t protocolNumber)
 {
--- a/src/devices/csma/csma-net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/csma/csma-net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -351,6 +351,12 @@
   virtual bool IsPointToPoint (void) const;
 
   /**
+   * Is this a bridge?
+   * \returns false.
+   */
+  virtual bool IsBridge (void) const;
+
+  /**
    * Start sending a packet down the channel.
    */
   virtual bool Send (Ptr<Packet> packet, const Address& dest, 
--- a/src/devices/emu/emu-net-device.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/emu/emu-net-device.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -882,6 +882,12 @@
   return false;
 }
 
+bool 
+EmuNetDevice::IsBridge (void) const
+{
+  return false;
+}
+
 void
 EmuNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
 {
--- a/src/devices/emu/emu-net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/emu/emu-net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -165,6 +165,12 @@
    */
   virtual bool IsPointToPoint (void) const;
 
+  /**
+   * Is this a bridge?
+   * \returns false.
+   */
+  virtual bool IsBridge (void) const;
+
   virtual bool Send(Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
 
   virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
--- a/src/devices/point-to-point/point-to-point-net-device.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -392,6 +392,12 @@
 }
 
   bool 
+PointToPointNetDevice::IsBridge (void) const
+{
+  return false;
+}
+
+  bool 
 PointToPointNetDevice::Send(
   Ptr<Packet> packet, 
   const Address &dest, 
--- a/src/devices/point-to-point/point-to-point-net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -252,6 +252,7 @@
   virtual Address GetMulticast (Ipv4Address multicastGroup) const;
 
   virtual bool IsPointToPoint (void) const;
+  virtual bool IsBridge (void) const;
 
   virtual bool Send(Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
   virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
--- a/src/devices/wifi/wifi-net-device.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/wifi/wifi-net-device.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -238,6 +238,11 @@
   return false;
 }
 bool 
+WifiNetDevice::IsBridge (void) const
+{
+  return false;
+}
+bool 
 WifiNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
 {
   NS_ASSERT (Mac48Address::IsMatchingType (dest));
--- a/src/devices/wifi/wifi-net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/devices/wifi/wifi-net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -90,6 +90,7 @@
   virtual bool IsMulticast (void) const;
   virtual Address GetMulticast (Ipv4Address multicastGroup) const;
   virtual bool IsPointToPoint (void) const;
+  virtual bool IsBridge (void) const;
   virtual bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
   virtual Ptr<Node> GetNode (void) const;
   virtual void SetNode (Ptr<Node> node);
--- a/src/helper/bridge-helper.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/helper/bridge-helper.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -1,24 +1,49 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
 #include "bridge-helper.h"
-
+#include "ns3/log.h"
 #include "ns3/bridge-net-device.h"
 #include "ns3/node.h"
 
+NS_LOG_COMPONENT_DEFINE ("BridgeHelper");
+
 namespace ns3 {
 
 BridgeHelper::BridgeHelper ()
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_deviceFactory.SetTypeId ("ns3::BridgeNetDevice");
 }
 
 void 
 BridgeHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   m_deviceFactory.Set (n1, v1);
 }
 
 NetDeviceContainer
 BridgeHelper::Install (Ptr<Node> node, NetDeviceContainer c)
 {
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_LOGIC ("**** Install bridge device on node " << node->GetId ());
+
   NetDeviceContainer devs;
   Ptr<BridgeNetDevice> dev = m_deviceFactory.Create<BridgeNetDevice> ();
   devs.Add (dev);
@@ -26,6 +51,7 @@
 
   for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i)
     {
+      NS_LOG_LOGIC ("**** Add BridgePort "<< *i);
       dev->AddBridgePort (*i);
     }
   return devs;
--- a/src/helper/node-container.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/helper/node-container.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -50,6 +50,17 @@
   Add (d);
 }
 
+NodeContainer::NodeContainer (const NodeContainer &a, const NodeContainer &b, 
+                              const NodeContainer &c, const NodeContainer &d,
+                              const NodeContainer &e)
+{
+  Add (a);
+  Add (b);
+  Add (c);
+  Add (d);
+  Add (e);
+}
+
 NodeContainer::Iterator 
 NodeContainer::Begin (void) const
 {
--- a/src/helper/node-container.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/helper/node-container.h	Fri Nov 28 08:56:47 2008 +0100
@@ -64,6 +64,8 @@
 
   NodeContainer (const NodeContainer &a, const NodeContainer &b, const NodeContainer &c);
   NodeContainer (const NodeContainer &a, const NodeContainer &b, const NodeContainer &c, const NodeContainer &d);
+  NodeContainer (const NodeContainer &a, const NodeContainer &b, const NodeContainer &c, const NodeContainer &d,
+                 const NodeContainer &e);
 
   /**
    * \returns an iterator to the start of the vector of node pointers.
--- a/src/node/net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/node/net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -184,6 +184,15 @@
   virtual Address GetMulticast (Ipv6Address addr) const = 0;
 
   /**
+   * \brief Return true if the net device is acting as a bridge.
+   *
+   * \return value of m_isBridge flag
+   */
+  virtual bool IsBridge (void) const = 0;
+
+  /**
+   * \brief Return true if the net device is on a point-to-point link.
+   *
    * \return value of m_isPointToPoint flag
    */
   virtual bool IsPointToPoint (void) const = 0;
--- a/src/node/simple-net-device.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/node/simple-net-device.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -163,6 +163,13 @@
 {
   return false;
 }
+
+bool 
+SimpleNetDevice::IsBridge (void) const
+{
+  return false;
+}
+
 bool 
 SimpleNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
 {
--- a/src/node/simple-net-device.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/node/simple-net-device.h	Fri Nov 28 08:56:47 2008 +0100
@@ -61,6 +61,7 @@
   virtual bool IsMulticast (void) const;
   virtual Address GetMulticast (Ipv4Address multicastGroup) const;
   virtual bool IsPointToPoint (void) const;
+  virtual bool IsBridge (void) const;
   virtual bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
   virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
   virtual Ptr<Node> GetNode (void) const;
--- a/src/routing/global-routing/global-route-manager-impl.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/routing/global-routing/global-route-manager-impl.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -97,7 +97,7 @@
   void 
 SPFVertex::SetVertexType (SPFVertex::VertexType type)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (type);
   m_vertexType = type;
 }
 
@@ -111,7 +111,7 @@
   void 
 SPFVertex::SetVertexId (Ipv4Address id)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (id);
   m_vertexId = id;
 }
 
@@ -125,7 +125,7 @@
   void 
 SPFVertex::SetLSA (GlobalRoutingLSA* lsa)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (lsa);
   m_lsa = lsa;
 }
 
@@ -139,7 +139,7 @@
   void 
 SPFVertex::SetDistanceFromRoot (uint32_t distance)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (distance);
   m_distanceFromRoot = distance;
 }
 
@@ -153,7 +153,7 @@
   void 
 SPFVertex::SetOutgoingTypeId (uint32_t id)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (id);
   m_rootOif = id;
 }
 
@@ -167,7 +167,7 @@
   void 
 SPFVertex::SetNextHop (Ipv4Address nextHop)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (nextHop);
   m_nextHop = nextHop;
 }
 
@@ -181,7 +181,7 @@
   void
 SPFVertex::SetParent (SPFVertex* parent)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (parent);
   m_parent = parent;
 }
 
@@ -202,7 +202,7 @@
   SPFVertex* 
 SPFVertex::GetChild (uint32_t n) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (n);
   uint32_t j = 0;
 
   for ( ListOfSPFVertex_t::const_iterator i = m_children.begin ();
@@ -214,14 +214,14 @@
           return *i;
         }
     }
-  NS_ASSERT_MSG(false, "Index <n> out of range.");
+  NS_ASSERT_MSG (false, "Index <n> out of range.");
   return 0;
 }
 
   uint32_t 
 SPFVertex::AddChild (SPFVertex* child)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (child);
   m_children.push_back (child);
   return m_children.size ();
 }
@@ -268,14 +268,14 @@
   void
 GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRoutingLSA* lsa)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (addr << lsa);
   m_database.insert (LSDBPair_t (addr, lsa));
 }
 
   GlobalRoutingLSA*
 GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (addr);
 //
 // Look up an LSA by its address.
 //
@@ -293,7 +293,7 @@
   GlobalRoutingLSA*
 GlobalRouteManagerLSDB::GetLSAByLinkData (Ipv4Address addr) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (addr);
 //
 // Look up an LSA by its address.
 //
@@ -341,7 +341,7 @@
   void
 GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (lsdb);
   if (m_lsdb)
     {
       delete m_lsdb;
@@ -351,8 +351,7 @@
 
 //
 // In order to build the routing database, we need at least one of the nodes
-// to participate as a router.  Eventually we expect to provide a mechanism
-// for selecting a subset of the nodes to participate; for now, we just make
+// to participate as a router.  This is a convenience function that makes
 // all nodes routers.  We do this by walking the list of nodes in the system
 // and aggregating a Global Router Interface to each of the nodes.
 //
@@ -371,6 +370,21 @@
     }
 }
 
+  void
+GlobalRouteManagerImpl::SelectRouterNodes (NodeContainer c) 
+{
+  NS_LOG_FUNCTION (&c);
+  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); i++)
+    {
+      Ptr<Node> node = *i;
+      NS_LOG_LOGIC ("Adding GlobalRouter interface to node " << 
+        node->GetId ());
+
+      Ptr<GlobalRouter> globalRouter = CreateObject<GlobalRouter> ();
+      node->AggregateObject (globalRouter);
+    }
+}
+
 //
 // In order to build the routing database, we need to walk the list of nodes
 // in the system and look for those that support the GlobalRouter interface.
@@ -385,14 +399,14 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 //
-// Walk the list of nodes looking for the GlobalRouter Interface.
+// Walk the list of nodes looking for the GlobalRouter Interface.  Nodes with
+// global router interfaces are, not too surprisingly, our routers.
 //
   for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
     {
       Ptr<Node> node = *i;
 
-      Ptr<GlobalRouter> rtr = 
-        node->GetObject<GlobalRouter> ();
+      Ptr<GlobalRouter> rtr = node->GetObject<GlobalRouter> ();
 //      
 // Ignore nodes that aren't participating in routing.
 //
@@ -504,7 +518,7 @@
   void
 GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (v << &candidate);
 
   SPFVertex* w = 0;
   GlobalRoutingLSA* w_lsa = 0;
@@ -706,13 +720,13 @@
   GlobalRoutingLinkRecord* l,
   uint32_t distance)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (v << w << l << distance);
 //
 // If w is a NetworkVertex, l should be null
 /*
   if (w->GetVertexType () == SPFVertex::VertexNetwork && l)
     {
-        NS_ASSERT_MSG(0, "Error:  SPFNexthopCalculation parameter problem");
+        NS_ASSERT_MSG (0, "Error:  SPFNexthopCalculation parameter problem");
     }
 */
 
@@ -764,7 +778,7 @@
 // return the link record describing the link from <w> to <v>.  Think of it as
 // SPFGetLink.
 //
-          NS_ASSERT(l);
+          NS_ASSERT (l);
           GlobalRoutingLinkRecord *linkRemote = 0;
           linkRemote = SPFGetNextLink (w, v, linkRemote);
 // 
@@ -778,7 +792,7 @@
 // from the root node to the host represented by vertex <w>, you have to send
 // the packet to the next hop address specified in w->m_nextHop.
 //
-          w->SetNextHop(linkRemote->GetLinkData ());
+          w->SetNextHop (linkRemote->GetLinkData ());
 // 
 // Now find the outgoing interface corresponding to the point to point link
 // from the perspective of <v> -- remember that <l> is the link "from"
@@ -832,7 +846,7 @@
  * use can then be derived from the next hop IP address (or 
  * it can be inherited from the parent network).
  */
-                w->SetNextHop(linkRemote->GetLinkData ());
+                w->SetNextHop (linkRemote->GetLinkData ());
                 w->SetOutgoingTypeId (v->GetOutgoingTypeId ());
                 NS_LOG_LOGIC ("Next hop from " << 
                   v->GetVertexId () << " to " << w->GetVertexId () << 
@@ -891,7 +905,7 @@
   SPFVertex* w,
   GlobalRoutingLinkRecord* prev_link) 
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (v << w << prev_link);
 
   bool skip = true;
   bool found_prev_link = false;
@@ -966,7 +980,7 @@
   void
 GlobalRouteManagerImpl::DebugSPFCalculate (Ipv4Address root)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (root);
   SPFCalculate (root);
 }
 
@@ -987,7 +1001,7 @@
 // of the tree.  Initially, this queue is empty.
 //
   CandidateQueue candidate;
-  NS_ASSERT(candidate.Size () == 0);
+  NS_ASSERT (candidate.Size () == 0);
 //
 // Initialize the shortest-path tree to only contain the router doing the 
 // calculation.  Each router (and corresponding network) is a vertex in the
@@ -1094,7 +1108,7 @@
         }
       else
         {
-          NS_ASSERT_MSG(0, "illegal SPFVertex type");
+          NS_ASSERT_MSG (0, "illegal SPFVertex type");
         }
 //
 // RFC2328 16.1. (5). 
@@ -1123,7 +1137,7 @@
   uint32_t
 GlobalRouteManagerImpl::FindOutgoingTypeId (Ipv4Address a, Ipv4Mask amask)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (a << amask);
 //
 // We have an IP address <a> and a vertex ID of the root of the SPF tree.  
 // The question is what interface index does this address correspond to.
@@ -1199,7 +1213,7 @@
   void
 GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (v);
 
   NS_ASSERT_MSG (m_spfroot, 
     "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set");
@@ -1316,7 +1330,7 @@
   void
 GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (v);
 
   NS_ASSERT_MSG (m_spfroot, 
     "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set");
@@ -1409,7 +1423,7 @@
   void
 GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (v);
   v->GetParent ()->AddChild (v);
 }
 
--- a/src/routing/global-routing/global-route-manager-impl.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/routing/global-routing/global-route-manager-impl.h	Fri Nov 28 08:56:47 2008 +0100
@@ -29,6 +29,7 @@
 #include "ns3/object.h"
 #include "ns3/ptr.h"
 #include "ns3/ipv4-address.h"
+#include "ns3/node-container.h"
 #include "global-router-interface.h"
 
 namespace ns3 {
@@ -708,6 +709,14 @@
   virtual void SelectRouterNodes ();
 
 /**
+ * @brief Select which nodes in the system are to be router nodes and 
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+  virtual void SelectRouterNodes (NodeContainer c);
+
+/**
  * @brief Build the routing database by gathering Link State Advertisements
  * from each node exporting a GlobalRouter interface.
  * @internal
--- a/src/routing/global-routing/global-route-manager.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/routing/global-routing/global-route-manager.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -21,6 +21,7 @@
 #include "ns3/assert.h"
 #include "ns3/log.h"
 #include "ns3/simulation-singleton.h"
+#include "ns3/node-container.h"
 #include "global-route-manager.h"
 #include "global-route-manager-impl.h"
 
@@ -33,7 +34,7 @@
 // ---------------------------------------------------------------------------
 
   void
-GlobalRouteManager::PopulateRoutingTables () 
+GlobalRouteManager::PopulateRoutingTables (void) 
 {
   SelectRouterNodes ();
   BuildGlobalRoutingDatabase ();
@@ -41,28 +42,43 @@
 }
 
   void
-GlobalRouteManager::SelectRouterNodes () 
+GlobalRouteManager::PopulateRoutingTables (NodeContainer c) 
+{
+  SelectRouterNodes (c);
+  BuildGlobalRoutingDatabase ();
+  InitializeRoutes ();
+}
+
+  void
+GlobalRouteManager::SelectRouterNodes (void) 
 {
   SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
     SelectRouterNodes ();
 }
 
   void
-GlobalRouteManager::BuildGlobalRoutingDatabase () 
+GlobalRouteManager::SelectRouterNodes (NodeContainer c) 
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    SelectRouterNodes (c);
+}
+
+  void
+GlobalRouteManager::BuildGlobalRoutingDatabase (void) 
 {
   SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
     BuildGlobalRoutingDatabase ();
 }
 
   void
-GlobalRouteManager::InitializeRoutes ()
+GlobalRouteManager::InitializeRoutes (void)
 {
   SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
     InitializeRoutes ();
 }
 
   uint32_t
-GlobalRouteManager::AllocateRouterId ()
+GlobalRouteManager::AllocateRouterId (void)
 {
   static uint32_t routerId = 0;
   return routerId++;
--- a/src/routing/global-routing/global-route-manager.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/routing/global-routing/global-route-manager.h	Fri Nov 28 08:56:47 2008 +0100
@@ -22,6 +22,8 @@
 #ifndef GLOBAL_ROUTE_MANAGER_H
 #define GLOBAL_ROUTE_MANAGER_H
 
+#include "ns3/node-container.h"
+
 namespace ns3 {
 
 /**
@@ -40,7 +42,8 @@
 public:
 /**
  * @brief Build a routing database and initialize the routing tables of
- * the nodes in the simulation.
+ * the nodes in the simulation.  Makes all nodes in the simulation into
+ * routers.
  *
  * All this function does is call  BuildGlobalRoutingDatabase () and
  * InitializeRoutes ().
@@ -51,6 +54,19 @@
   static void PopulateRoutingTables ();
 
 /**
+ * @brief Build a routing database and initialize the routing tables of
+ * the nodes in the simulation.  Makes the nodes in the provided container
+ * into routers.
+ *
+ * All this function does is call  BuildGlobalRoutingDatabase () and
+ * InitializeRoutes ().
+ *
+ * @see BuildGlobalRoutingDatabase ();
+ * @see InitializeRoutes ();
+ */
+  static void PopulateRoutingTables (NodeContainer c);
+
+/**
  * @brief Allocate a 32-bit router ID from monotonically increasing counter.
  */
   static uint32_t AllocateRouterId ();
@@ -65,6 +81,14 @@
   static void SelectRouterNodes ();
 
 /**
+ * @brief Select which nodes in the system are to be router nodes and 
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+  static void SelectRouterNodes (NodeContainer c);
+
+/**
  * @brief Build the routing database by gathering Link State Advertisements
  * from each node exporting a GlobalRouter interface.
  * @internal
--- a/src/routing/global-routing/global-router-interface.cc	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/routing/global-routing/global-router-interface.cc	Fri Nov 28 08:56:47 2008 +0100
@@ -20,11 +20,15 @@
 
 #include "ns3/log.h"
 #include "ns3/assert.h"
+#include "ns3/abort.h"
 #include "ns3/channel.h"
 #include "ns3/net-device.h"
 #include "ns3/node.h"
 #include "ns3/ipv4.h"
+#include "ns3/bridge-net-device.h"
+#include "ns3/net-device-container.h"
 #include "global-router-interface.h"
+#include <vector>
 
 NS_LOG_COMPONENT_DEFINE ("GlobalRouter");
 
@@ -365,8 +369,7 @@
           return *i;
         }
     }
-  NS_ASSERT_MSG(false, 
-    "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
+  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
   return Ipv4Address("0.0.0.0");
 }
 
@@ -380,9 +383,25 @@
   void 
 GlobalRoutingLSA::Print (std::ostream &os) const
 {
-  os << "m_lsType = " << m_lsType << std::endl <<
-        "m_linkStateId = " << m_linkStateId << std::endl <<
-        "m_advertisingRtr = " << m_advertisingRtr << std::endl;
+  os << std::endl;
+  os << "========== Global Routing LSA ==========" << std::endl;
+  os << "m_lsType = " << m_lsType;
+  if (m_lsType == GlobalRoutingLSA::RouterLSA) 
+    {
+      os << " (GlobalRoutingLSA::RouterLSA)";
+    }
+  else if (m_lsType == GlobalRoutingLSA::NetworkLSA) 
+    {
+      os << " (GlobalRoutingLSA::NetworkLSA)";
+    }
+  else
+    {
+      os << "(Unknown LSType)";
+    }
+  os << std::endl;
+
+  os << "m_linkStateId = " << m_linkStateId << " (Router ID)" << std::endl;
+  os << "m_advertisingRtr = " << m_advertisingRtr << " (Router ID)" << std::endl;
 
   if (m_lsType == GlobalRoutingLSA::RouterLSA) 
     {
@@ -391,30 +410,49 @@
             i++)
         {
           GlobalRoutingLinkRecord *p = *i;
-          os << "----------" << std::endl;
-          os << "m_linkId = " << p->GetLinkId () << std::endl;
-          os << "m_linkData = " << p->GetLinkData () << std::endl;
-          os << "m_metric = " << p->GetMetric () << std::endl;
+
+          os << "---------- RouterLSA Link Record ----------" << std::endl;
+          os << "m_linkType = " << p->m_linkType;
+          if (p->m_linkType == GlobalRoutingLinkRecord::TransitNetwork)
+            {
+              os << " (GlobalRoutingLinkRecord::TransitNetwork)" << std::endl;
+              os << "m_linkId = " << p->m_linkId << " (Designated router for network)" << std::endl;
+              os << "m_linkData = " << p->m_linkData << " (This router's IP address)" << std::endl;
+              os << "m_metric = " << p->m_metric << std::endl;
+            }
+          else if (p->GetLinkType () == GlobalRoutingLinkRecord::StubNetwork)
+            {
+              os << "(GlobalRoutingLinkRecord::StubNetwork)" << std::endl;
+              os << "m_linkId = " << p->m_linkId << " (Network number of attached network)" << std::endl;
+              os << "m_linkData = " << p->m_linkData << " (Network mask of attached network)" << std::endl;
+              os << "m_metric = " << p->m_metric << std::endl;
+            }
+          else
+            {
+              os << "(Unknown LinkType)" << std::endl;
+              os << "m_linkId = " << p->m_linkId << std::endl;
+              os << "m_linkData = " << p->m_linkData << std::endl;
+              os << "m_metric = " << p->m_metric << std::endl;
+            }
+          os << "---------- End RouterLSA Link Record ----------" << std::endl;
         }
     }
   else if (m_lsType == GlobalRoutingLSA::NetworkLSA) 
     {
-      os << "----------" << std::endl;
-      os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask 
-         << std::endl;
-      for ( ListOfAttachedRouters_t::const_iterator i = 
-            m_attachedRouters.begin ();
-            i != m_attachedRouters.end (); 
-            i++)
+      os << "---------- NetworkLSA Link Record ----------" << std::endl;
+      os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask << std::endl;
+      for ( ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin (); i != m_attachedRouters.end (); i++)
         {
           Ipv4Address p = *i;
           os << "attachedRouter = " << p << std::endl;
         }
+      os << "---------- End NetworkLSA Link Record ----------" << std::endl;
     }
   else 
     {
       NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
     }
+  os << "========== End Global Routing LSA ==========" << std::endl;
 }
 
 std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa)
@@ -487,53 +525,79 @@
 }
 
 //
-// Go out and discover any adjacent routers and build the Link State 
-// Advertisements that reflect them and their associated networks.
+// DiscoverLSAs is called on all nodes in the system that have a GlobalRouter
+// interface aggregated.  We need to go out and discover any adjacent routers 
+// and build the Link State Advertisements that reflect them and their associated
+// networks.
 // 
   uint32_t 
 GlobalRouter::DiscoverLSAs (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
   Ptr<Node> node = GetObject<Node> ();
-  NS_LOG_LOGIC("For node " << node->GetId () );
-  NS_ASSERT_MSG(node, 
-    "GlobalRouter::DiscoverLSAs (): <Node> interface not set");
+  NS_ABORT_MSG_UNLESS (node, "GlobalRouter::DiscoverLSAs (): GetObject for <Node> interface failed");
+  NS_LOG_LOGIC ("For node " << node->GetId () );
 
   ClearLSAs ();
 
-// While building the router-LSA, keep a list of those NetDevices for
-// which I am the designated router and need to later build a NetworkLSA
-  std::list<Ptr<NetDevice> > listOfDRInterfaces;
+  //
+  // While building the Router-LSA, keep a list of those NetDevices for
+  // which the current node is the designated router and we will later build 
+  // a NetworkLSA for.
+  //
+  NetDeviceContainer c;
 
-//
-// We're aggregated to a node.  We need to ask the node for a pointer to its
-// Ipv4 interface.  This is where the information regarding the attached 
-// interfaces lives.
-//
+  //
+  // We're aggregated to a node.  We need to ask the node for a pointer to its
+  // Ipv4 interface.  This is where the information regarding the attached 
+  // interfaces lives.  If we're a router, we had better have an Ipv4 interface.
+  //
   Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4> ();
-  NS_ASSERT_MSG(ipv4Local, 
-    "GlobalRouter::DiscoverLSAs (): QI for <Ipv4> interface failed");
-//
-// Each node originates a Router-LSA
-//
+  NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::DiscoverLSAs (): GetObject for <Ipv4> interface failed");
+
+  //
+  // Every router node originates a Router-LSA
+  //
   GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
   pLSA->SetLSType (GlobalRoutingLSA::RouterLSA);
   pLSA->SetLinkStateId (m_routerId);
   pLSA->SetAdvertisingRouter (m_routerId);
   pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
-//
-// We need to ask the node for the number of net devices attached. This isn't
-// necessarily equal to the number of links to adjacent nodes (other routers)
-// as the number of devices may include those for stub networks (e.g., 
-// ethernets, etc.).  
-//
+
+  //
+  // Ask the node for the number of net devices attached. This isn't necessarily 
+  // equal to the number of links to adjacent nodes (other routers) as the number
+  // of devices may include those for stub networks (e.g., ethernets, etc.) and 
+  // bridge devices also take up an "extra" net device.
+  //
   uint32_t numDevices = node->GetNDevices();
-  NS_LOG_LOGIC ("numDevices = " << numDevices);
+
+  //
+  // Iterate through the devices on the node and walk the channel to see what's
+  // on the other side of the standalone devices..
+  //
   for (uint32_t i = 0; i < numDevices; ++i)
     {
       Ptr<NetDevice> ndLocal = node->GetDevice(i);
 
-      // Check if it is an IP interface (could be a pure L2 NetDevice)
+      //
+      // There is an assumption that bridge ports must never have an IP address 
+      // associated with them.  This turns out to be a very convenient place to
+      // check and make sure that this is the case.
+      //
+      if (NetDeviceIsBridged (ndLocal))
+        {
+          uint32_t ifIndexBridge;
+          bool rc = FindIfIndexForDevice(node, ndLocal, ifIndexBridge);
+          NS_ABORT_MSG_IF (rc, "GlobalRouter::DiscoverLSAs(): Bridge ports must not have an IPv4 interface index");
+        }
+
+      //
+      // Check to see if the net device we just got has a corresponding IP 
+      // interface (could be a pure L2 NetDevice) -- for example a net device
+      // associated with a bridge.  We are only going to involve devices with 
+      // IP addresses in routing.
+      //
       bool isIp = false;
       for (uint32_t i = 0; i < ipv4Local->GetNInterfaces (); ++i )
         {
@@ -543,240 +607,723 @@
               break;
             }
         }
+
       if (!isIp)
         {
+          NS_LOG_LOGIC ("Net device " << ndLocal << "has no IP interface, skipping");
           continue;
         }
 
+      //
+      // We have a net device that we need to check out.  If it suports 
+      // broadcast and is not a point-point link, then it will be either a stub 
+      // network or a transit network depending on the number of routers on
+      // the segment.  We add the appropriate link record to the LSA.
+      //
+      // If the device is a point to point link, we treat it separately.  In
+      // that case, there always two link records added.
+      //
       if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () )
         {
           NS_LOG_LOGIC ("Broadcast link");
-          GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
-//
-// We need to determine whether we are on a transit or stub network
-// If we find at least one more router on this channel, we are a transit
-//
-//
-// Now, we have to find the Ipv4 interface whose netdevice is the one we 
-// just found.  This is still the IP on the local side of the channel.  There 
-// is a function to do this used down in the guts of the stack, but it's not 
-// exported so we had to whip up an equivalent.
-//
-          uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
-          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
-          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
-          NS_LOG_LOGIC ("Working with local address " << addrLocal);
-          uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal);
-//
-// Now, we're going to walk over to the remote net device on the other end of 
-// the point-to-point channel we now know we have.  This is where our adjacent 
-// router (to use OSPF lingo) is running.  
-//
-          Ptr<Channel> ch = ndLocal->GetChannel();
-          uint32_t nDevices = ch->GetNDevices();
-          if (nDevices == 1)
-            {
-              // This is a stub broadcast interface
-              NS_LOG_LOGIC("Router-LSA stub broadcast link");
-              // XXX in future, need to consider if >1 includes other routers
-              plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
-              // Link ID is IP network number of attached network
-              plr->SetLinkId (addrLocal.CombineMask(maskLocal));
-              // Link Data is network mask; convert to Ipv4Address
-              Ipv4Address maskLocalAddr;
-              maskLocalAddr.Set(maskLocal.Get ());
-              plr->SetLinkData (maskLocalAddr);
-              plr->SetMetric (metricLocal);
-              pLSA->AddLinkRecord(plr);
-              plr = 0;
-              continue;
-            }
-          else
-            {
-              NS_LOG_LOGIC ("Router-LSA Broadcast link");
-              // multiple routers on a broadcast interface
-              // lowest IP address is designated router
-              plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
-              // Link ID is IP interface address of designated router
-              Ipv4Address desigRtr = 
-                FindDesignatedRouterForLink (node, ndLocal);
-              if (desigRtr == addrLocal) 
-                {
-                  listOfDRInterfaces.push_back (ndLocal);
-                  NS_LOG_LOGIC (node->GetId () << " is a DR");
-                }
-              plr->SetLinkId (desigRtr);
-              // Link Data is router's own IP address
-              plr->SetLinkData (addrLocal);
-              plr->SetMetric (metricLocal);
-              pLSA->AddLinkRecord (plr);
-              plr = 0;
-              continue;
-            }
+          ProcessBroadcastLink (ndLocal, pLSA, c);
         }
       else if (ndLocal->IsPointToPoint () )
         {
-          NS_LOG_LOGIC ("Router-LSA Point-to-point device");
-//
-// Now, we have to find the Ipv4 interface whose netdevice is the one we 
-// just found.  This is still the IP on the local side of the channel.  There 
-// is a function to do this used down in the guts of the stack, but it's not 
-// exported so we had to whip up an equivalent.
-//
-          uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
-//
-// Now that we have the Ipv4 interface index, we can get the address and mask
-// we need.
-//
-          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
-          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
-          NS_LOG_LOGIC ("Working with local address " << addrLocal);
-          uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal);
-//
-// Now, we're going to walk over to the remote net device on the other end of 
-// the point-to-point channel we now know we have.  This is where our adjacent 
-// router (to use OSPF lingo) is running.  
-//
-          Ptr<Channel> ch = ndLocal->GetChannel();
-          if (ch == NULL)
-            {
-              continue;
-            }
-          Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
-//
-// The adjacent net device is aggregated to a node.  We need to ask that net 
-// device for its node, then ask that node for its Ipv4 interface.
-//
-          Ptr<Node> nodeRemote = ndRemote->GetNode();
-          Ptr<Ipv4> ipv4Remote = nodeRemote->GetObject<Ipv4> ();
-          NS_ASSERT_MSG(ipv4Remote, 
-            "GlobalRouter::DiscoverLSAs (): QI for remote <Ipv4> failed");
-//
-// Per the OSPF spec, we're going to need the remote router ID, so we might as
-// well get it now.
-//
-          Ptr<GlobalRouter> srRemote = 
-            nodeRemote->GetObject<GlobalRouter> ();
-          NS_ASSERT_MSG(srRemote, 
-            "GlobalRouter::DiscoverLSAs():QI for remote <GlobalRouter> failed");
-          Ipv4Address rtrIdRemote = srRemote->GetRouterId();
-          NS_LOG_LOGIC ("Working with remote router " << rtrIdRemote);
-//
-// Now, just like we did above, we need to get the IP interface index for the 
-// net device on the other end of the point-to-point channel.
-//
-          uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote);
-//
-// Now that we have the Ipv4 interface, we can get the (remote) address and
-// mask we need.
-//
-          Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote);
-          Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote);
-          NS_LOG_LOGIC ("Working with remote address " << addrRemote);
-//
-// Now we can fill out the link records for this link.  There are always two
-// link records; the first is a point-to-point record describing the link and
-// the second is a stub network record with the network number.
-//
-          GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
-          plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint);
-          plr->SetLinkId (rtrIdRemote);
-          plr->SetLinkData (addrLocal);
-          plr->SetMetric (metricLocal);
-          pLSA->AddLinkRecord (plr);
-          plr = 0;
-
-          plr = new GlobalRoutingLinkRecord;
-          plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
-          plr->SetLinkId (addrRemote);
-          plr->SetLinkData (Ipv4Address(maskRemote.Get()));  // Frown
-          plr->SetMetric (metricLocal);
-          pLSA->AddLinkRecord (plr);
-          plr = 0;
+          NS_LOG_LOGIC ("Point=to-point link");
+          ProcessPointToPointLink (ndLocal, pLSA);
         }
       else
         {
           NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
         }
+    }
 
-    }
-//
-// The LSA goes on a list of LSAs in case we want to begin exporting other
-// kinds of advertisements (than Router LSAs).
-  m_LSAs.push_back (pLSA);
+  NS_LOG_LOGIC ("========== LSA for node " << node->GetId () << " ==========");
   NS_LOG_LOGIC (*pLSA);
+  m_LSAs.push_back (pLSA);
+  pLSA = 0;
 
-// Now, determine whether we need to build a NetworkLSA
-  if (listOfDRInterfaces.size () > 0)
+  // 
+  // Now, determine whether we need to build a NetworkLSA.  This is the case if
+  // we found at least one designated router.
+  //
+  uint32_t nDesignatedRouters = c.GetN ();
+  if (nDesignatedRouters > 0)
+    {
+      NS_LOG_LOGIC ("Build Network LSAs");
+      BuildNetworkLSAs (c);
+    }
+
+  return m_LSAs.size ();
+}
+
+  void
+GlobalRouter::ProcessBroadcastLink (Ptr<NetDevice> nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c)
+{
+  NS_LOG_FUNCTION (nd << pLSA << &c);
+
+  if (nd->IsBridge ())
+    {
+      ProcessBridgedBroadcastLink (nd, pLSA, c);
+    }
+  else
+    {
+      ProcessSingleBroadcastLink (nd, pLSA, c);
+    }
+}
+
+  void
+GlobalRouter::ProcessSingleBroadcastLink (Ptr<NetDevice> nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c)
+{
+  NS_LOG_FUNCTION (nd << pLSA << &c);
+
+  GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+  NS_ABORT_MSG_IF (plr == 0, "GlobalRouter::ProcessSingleBroadcastLink(): Can't alloc link record");
+
+  //
+  // We have some preliminaries to do to get enough information to proceed.
+  // This information we need comes from the internet stack, so notice that
+  // there is an implied assumption that global routing is only going to 
+  // work with devices attached to the internet stack (have an ipv4 interface
+  // associated to them.
+  //
+  Ptr<Node> node = nd->GetNode ();
+
+  uint32_t ifIndexLocal;
+  bool rc = FindIfIndexForDevice(node, nd, ifIndexLocal);
+  NS_ABORT_MSG_IF (rc == false, "GlobalRouter::ProcessSingleBroadcastLink(): No interface index associated with device");
+
+  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4> ();
+  NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::ProcessSingleBroadcastLink (): GetObject for <Ipv4> interface failed");
+
+  Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+  Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+  NS_LOG_LOGIC ("Working with local address " << addrLocal);
+  uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal);
+
+  //
+  // Check to see if the net device is connected to a channel/network that has
+  // another router on it.  If there is no other router on the link (but us) then
+  // this is a stub network.  If we find another router, then what we have here
+  // is a transit network.
+  //
+  if (AnotherRouterOnLink (nd, true) == false)
+    {
+      //
+      // This is a net device connected to a stub network
+      //
+      NS_LOG_LOGIC("Router-LSA Stub Network");
+      plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+
+      // 
+      // According to OSPF, the Link ID is the IP network number of 
+      // the attached network.
+      //
+      plr->SetLinkId (addrLocal.CombineMask(maskLocal));
+
+      //
+      // and the Link Data is the network mask; converted to Ipv4Address
+      //
+      Ipv4Address maskLocalAddr;
+      maskLocalAddr.Set(maskLocal.Get ());
+      plr->SetLinkData (maskLocalAddr);
+      plr->SetMetric (metricLocal);
+      pLSA->AddLinkRecord(plr);
+      plr = 0;
+    }
+  else
     {
-      for (std::list<Ptr<NetDevice> >::iterator i = listOfDRInterfaces.begin ();
-        i != listOfDRInterfaces.end (); i++)
+      //
+      // We have multiple routers on a broadcast interface, so this is
+      // a transit network.
+      //
+      NS_LOG_LOGIC ("Router-LSA Transit Network");
+      plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
+
+      // 
+      // By definition, the router with the lowest IP address is the
+      // designated router for the network.  OSPF says that the Link ID
+      // gets the IP interface address of the designated router in this 
+      // case.
+      //
+      Ipv4Address desigRtr = FindDesignatedRouterForLink (nd, true);
+
+      //
+      // Let's double-check that any designated router we find out on our
+      // network is really on our network.
+      //
+      if (desigRtr != "255.255.255.255")
+        {
+          Ipv4Address networkHere = addrLocal.CombineMask (maskLocal);
+          Ipv4Address networkThere = desigRtr.CombineMask (maskLocal);
+          NS_ABORT_MSG_UNLESS (networkHere == networkThere, 
+                               "GlobalRouter::ProcessSingleBroadcastLink(): Network number confusion");
+        }
+      if (desigRtr == addrLocal) 
+        {
+          c.Add (nd);
+          NS_LOG_LOGIC ("Node " << node->GetId () << " elected a designated router");
+        }
+      plr->SetLinkId (desigRtr);
+      
+      //
+      // OSPF says that the Link Data is this router's own IP address.
+      //
+      plr->SetLinkData (addrLocal);
+      plr->SetMetric (metricLocal);
+      pLSA->AddLinkRecord (plr);
+      plr = 0;
+    }
+}
+
+  void
+GlobalRouter::ProcessBridgedBroadcastLink (Ptr<NetDevice> nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c)
+{
+  NS_LOG_FUNCTION (nd << pLSA << &c);
+  NS_ASSERT_MSG (nd->IsBridge (), "GlobalRouter::ProcessBridgedBroadcastLink(): Called with non-bridge net device");
+
+#if 0
+  //
+  // It is possible to admit the possibility that a bridge device on a node
+  // can also participate in routing.  This would surprise people who don't
+  // come from Microsoft-land where they do use such a construct.  Based on
+  // the principle of least-surprise, we will leave the relatively simple
+  // code in place to do this, but not enable it until someone really wants
+  // the capability.  Even then, we will not enable this code as a default
+  // but rather something you will have to go and turn on.
+  //
+
+  Ptr<BridgeNetDevice> bnd = nd->GetObject<BridgeNetDevice> ();
+  NS_ABORT_MSG_UNLESS (bnd, "GlobalRouter::DiscoverLSAs (): GetObject for <BridgeNetDevice> failed");
+
+  //
+  // We have some preliminaries to do to get enough information to proceed.
+  // This information we need comes from the internet stack, so notice that
+  // there is an implied assumption that global routing is only going to 
+  // work with devices attached to the internet stack (have an ipv4 interface
+  // associated to them.
+  //
+  Ptr<Node> node = nd->GetNode ();
+
+  uint32_t ifIndexLocal;
+  bool rc = FindIfIndexForDevice(node, nd, ifIndexLocal);
+  NS_ABORT_MSG_IF (rc == false, "GlobalRouter::ProcessBridgedBroadcastLink(): No interface index associated with device");
+
+  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4> ();
+  NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::ProcessBridgedBroadcastLink (): GetObject for <Ipv4> interface failed");
+
+  Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+  Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+  NS_LOG_LOGIC ("Working with local address " << addrLocal);
+  uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal);
+
+  //
+  // We need to handle a bridge on the router.  This means that we have been 
+  // given a net device that is a BridgeNetDevice.  It has an associated Ipv4
+  // interface index and address.  Some number of other net devices live "under"
+  // the bridge device as so-called bridge ports.  In a nutshell, what we have
+  // to do is to repeat what is done for a single broadcast link on all of 
+  // those net devices living under the bridge (trolls?)
+  //
+
+  bool areTransitNetwork = false;
+  Ipv4Address desigRtr ("255.255.255.255");
+
+  for (uint32_t i = 0; i < bnd->GetNBridgePorts (); ++i)
+    {
+      Ptr<NetDevice> ndTemp = bnd->GetBridgePort (i);
+
+      //
+      // We have to decide if we are a transit network.  This is characterized
+      // by the presence of another router on the network segment.  If we find
+      // another router on any of our bridged links, we are a transit network.
+      //
+      if (AnotherRouterOnLink (ndTemp, true))
         {
-// Build one NetworkLSA for each interface that is a DR
-          Ptr<NetDevice> ndLocal = *i;
-          uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
-          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
-          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+          areTransitNetwork = true;
+
+          //
+          // If we're going to be a transit network, then we have got to elect
+          // a designated router for the whole bridge.  This means finding the
+          // router with the lowest IP address on the whole bridge.  We ask 
+          // for the lowest address on each segment and pick the lowest of them
+          // all.
+          //
+          Ipv4Address desigRtrTemp = FindDesignatedRouterForLink (ndTemp, true);
+
+          //
+          // Let's double-check that any designated router we find out on our
+          // network is really on our network.
+          //
+          if (desigRtrTemp != "255.255.255.255")
+            {
+              Ipv4Address networkHere = addrLocal.CombineMask (maskLocal);
+              Ipv4Address networkThere = desigRtrTemp.CombineMask (maskLocal);
+              NS_ABORT_MSG_UNLESS (networkHere == networkThere, 
+                                   "GlobalRouter::ProcessSingleBroadcastLink(): Network number confusion");
+            }
+          if (desigRtrTemp < desigRtr)
+            {
+              desigRtr = desigRtrTemp;
+            }
+        }
+    }
+  //
+  // That's all the information we need to put it all together, just like we did
+  // in the case of a single broadcast link.
+  //
+
+  GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+  NS_ABORT_MSG_IF (plr == 0, "GlobalRouter::ProcessBridgedBroadcastLink(): Can't alloc link record");
+
+  if (areTransitNetwork == false)
+    {
+      //
+      // This is a net device connected to a bridge of stub networks
+      //
+      NS_LOG_LOGIC("Router-LSA Stub Network");
+      plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+
+      // 
+      // According to OSPF, the Link ID is the IP network number of 
+      // the attached network.
+      //
+      plr->SetLinkId (addrLocal.CombineMask(maskLocal));
+
+      //
+      // and the Link Data is the network mask; converted to Ipv4Address
+      //
+      Ipv4Address maskLocalAddr;
+      maskLocalAddr.Set(maskLocal.Get ());
+      plr->SetLinkData (maskLocalAddr);
+      plr->SetMetric (metricLocal);
+      pLSA->AddLinkRecord(plr);
+      plr = 0;
+    }
+  else
+    {
+      //
+      // We have multiple routers on a bridged broadcast interface, so this is
+      // a transit network.
+      //
+      NS_LOG_LOGIC ("Router-LSA Transit Network");
+      plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
+
+      // 
+      // By definition, the router with the lowest IP address is the
+      // designated router for the network.  OSPF says that the Link ID
+      // gets the IP interface address of the designated router in this 
+      // case.
+      //
+      if (desigRtr == addrLocal) 
+        {
+          c.Add (nd);
+          NS_LOG_LOGIC ("Node " << node->GetId () << " elected a designated router");
+        }
+      plr->SetLinkId (desigRtr);
+      
+      //
+      // OSPF says that the Link Data is this router's own IP address.
+      //
+      plr->SetLinkData (addrLocal);
+      plr->SetMetric (metricLocal);
+      pLSA->AddLinkRecord (plr);
+      plr = 0;
+    }
+#endif
+}
+
+  void
+GlobalRouter::ProcessPointToPointLink (Ptr<NetDevice> ndLocal, GlobalRoutingLSA *pLSA)
+{
+  NS_LOG_FUNCTION (ndLocal << pLSA);
+
+  //
+  // We have some preliminaries to do to get enough information to proceed.
+  // This information we need comes from the internet stack, so notice that
+  // there is an implied assumption that global routing is only going to 
+  // work with devices attached to the internet stack (have an ipv4 interface
+  // associated to them.
+  //
+  Ptr<Node> nodeLocal = ndLocal->GetNode ();
+
+  uint32_t ifIndexLocal;
+  bool rc = FindIfIndexForDevice(nodeLocal, ndLocal, ifIndexLocal);
+  NS_ABORT_MSG_IF (rc == false, "GlobalRouter::ProcessPointToPointLink (): No interface index associated with device");
+
+  Ptr<Ipv4> ipv4Local = nodeLocal->GetObject<Ipv4> ();
+  NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::ProcessPointToPointLink (): GetObject for <Ipv4> interface failed");
+
+  Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+  Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+  NS_LOG_LOGIC ("Working with local address " << addrLocal);
+  uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal);
+
+  //
+  // Now, we're going to walk over to the remote net device on the other end of 
+  // the point-to-point channel we know we have.  This is where our adjacent 
+  // router (to use OSPF lingo) is running.  
+  //
+  Ptr<Channel> ch = ndLocal->GetChannel();
+
+  //
+  // Get the net device on the other side of the point-to-point channel.
+  //
+  Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
 
-          GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
-          pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA);
-          pLSA->SetLinkStateId (addrLocal);
-          pLSA->SetAdvertisingRouter (m_routerId);
-          pLSA->SetNetworkLSANetworkMask (maskLocal);
-          pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
-// Build list of AttachedRouters
-          Ptr<Channel> ch = ndLocal->GetChannel();
-          uint32_t nDevices = ch->GetNDevices();
-          NS_ASSERT (nDevices);
-          for (uint32_t i = 0; i < nDevices; i++)
+  //
+  // The adjacent net device is aggregated to a node.  We need to ask that net 
+  // device for its node, then ask that node for its Ipv4 interface.  Note a
+  // requirement that nodes on either side of a point-to-point link must have 
+  // internet stacks; and an assumption that point-to-point links are incompatible 
+  // with bridging.
+  //
+  Ptr<Node> nodeRemote = ndRemote->GetNode();
+  Ptr<Ipv4> ipv4Remote = nodeRemote->GetObject<Ipv4> ();
+  NS_ABORT_MSG_UNLESS (ipv4Remote, 
+                       "GlobalRouter::ProcessPointToPointLink(): GetObject for remote <Ipv4> failed");
+
+  //
+  // Further note the requirement that nodes on either side of a point-to-point 
+  // link must participate in global routing and therefore have a GlobalRouter
+  // interface aggregated.
+  //
+  Ptr<GlobalRouter> rtrRemote = nodeRemote->GetObject<GlobalRouter> ();
+  NS_ABORT_MSG_UNLESS(rtrRemote, 
+                      "GlobalRouter::ProcessPointToPointLinks(): GetObject for remote <GlobalRouter> failed");
+
+  //
+  // We're going to need the remote router ID, so we might as well get it now.
+  //
+  Ipv4Address rtrIdRemote = rtrRemote->GetRouterId();
+  NS_LOG_LOGIC ("Working with remote router " << rtrIdRemote);
+
+  //
+  // Now, just like we did above, we need to get the IP interface index for the 
+  // net device on the other end of the point-to-point channel.
+  //
+  uint32_t ifIndexRemote;
+  rc = FindIfIndexForDevice(nodeRemote, ndRemote, ifIndexRemote);
+  NS_ABORT_MSG_IF (rc == false, "GlobalRouter::ProcessPointToPointLinks(): No interface index associated with remote device");
+
+  //
+  // Now that we have the Ipv4 interface, we can get the (remote) address and
+  // mask we need.
+  //
+  Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote);
+  Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote);
+  NS_LOG_LOGIC ("Working with remote address " << addrRemote);
+
+  //
+  // Now we can fill out the link records for this link.  There are always two
+  // link records; the first is a point-to-point record describing the link and
+  // the second is a stub network record with the network number.
+  //
+  GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+  NS_ABORT_MSG_IF (plr == 0, "GlobalRouter::ProcessPointToPointLink(): Can't alloc link record");
+  plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint);
+  plr->SetLinkId (rtrIdRemote);
+  plr->SetLinkData (addrLocal);
+  plr->SetMetric (metricLocal);
+  pLSA->AddLinkRecord (plr);
+  plr = 0;
+
+  plr = new GlobalRoutingLinkRecord;
+  NS_ABORT_MSG_IF (plr == 0, "GlobalRouter::ProcessPointToPointLink(): Can't alloc link record");
+  plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+  plr->SetLinkId (addrRemote);
+  plr->SetLinkData (Ipv4Address(maskRemote.Get()));  // Frown
+  plr->SetMetric (metricLocal);
+  pLSA->AddLinkRecord (plr);
+  plr = 0;
+}
+
+  void
+GlobalRouter::BuildNetworkLSAs (NetDeviceContainer c)
+{
+  NS_LOG_FUNCTION (&c);
+
+  uint32_t nDesignatedRouters = c.GetN ();
+      
+  for (uint32_t i = 0; i < nDesignatedRouters; ++i)
+    {
+      //
+      // Build one NetworkLSA for each net device talking to a network that we are the 
+      // designated router for.  These devices are in the provided container.
+      //
+      Ptr<NetDevice> ndLocal = c.Get (i);
+      Ptr<Node> node = ndLocal->GetNode ();
+
+      uint32_t ifIndexLocal;
+      bool rc = FindIfIndexForDevice(node, ndLocal, ifIndexLocal);
+      NS_ABORT_MSG_IF (rc == false, "GlobalRouter::BuildNetworkLSAs (): No interface index associated with device");
+
+      Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4> ();
+      NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::ProcessPointToPointLink (): GetObject for <Ipv4> interface failed");
+
+      Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+      Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+      GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+      NS_ABORT_MSG_IF (pLSA == 0, "GlobalRouter::BuildNetworkLSAs(): Can't alloc link record");
+
+      pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA);
+      pLSA->SetLinkStateId (addrLocal);
+      pLSA->SetAdvertisingRouter (m_routerId);
+      pLSA->SetNetworkLSANetworkMask (maskLocal);
+      pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+
+      //
+      // Build a list of AttachedRouters by walking the devices in the channel
+      // and, if we find a node with a GlobalRouter interface and an IPv4 
+      // interface associated with that device, we call it an attached router.  
+      //
+      Ptr<Channel> ch = ndLocal->GetChannel();
+      uint32_t nDevices = ch->GetNDevices();
+      NS_ASSERT (nDevices);
+      
+      for (uint32_t i = 0; i < nDevices; i++)
+        {
+          Ptr<NetDevice> tempNd = ch->GetDevice (i);
+          NS_ASSERT (tempNd);
+          Ptr<Node> tempNode = tempNd->GetNode ();
+
+          //
+          // Does the node in question have a GlobalRouter interface?  If not it can
+          // hardly be considered an attached router.
+          //
+          Ptr<GlobalRouter> rtr = tempNode->GetObject<GlobalRouter> ();
+          if (rtr == 0)
+            { 
+              continue;
+            }
+
+          //
+          // Does the attached node have an ipv4 interface for the device we're probing?
+          // If not, it can't play router.
+          //
+          uint32_t tempIfIndex;
+          if (FindIfIndexForDevice (tempNode, tempNd, tempIfIndex))
             {
-              Ptr<NetDevice> tempNd = ch->GetDevice (i);
-              NS_ASSERT (tempNd);
-              Ptr<Node> tempNode = tempNd->GetNode ();
-              uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
               Ptr<Ipv4> tempIpv4 = tempNode->GetObject<Ipv4> ();
               NS_ASSERT (tempIpv4);
               Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
               pLSA->AddAttachedRouter (tempAddr);
             }
-          m_LSAs.push_back (pLSA);
-          NS_LOG_LOGIC (*pLSA);
         }
+      m_LSAs.push_back (pLSA);
+      pLSA = 0;
     }
-
-  return m_LSAs.size ();
 }
 
+//
+// Given a local net device, we need to walk the channel to which the net device is
+// attached and look for nodes with GlobalRouter interfaces on them (one of them 
+// will be us).  Of these, the router with the lowest IP address on the net device 
+// connecting to the channel becomes the designated router for the link.
+//
   Ipv4Address
-GlobalRouter::FindDesignatedRouterForLink (Ptr<Node> node, 
-  Ptr<NetDevice> ndLocal) const
+GlobalRouter::FindDesignatedRouterForLink (Ptr<NetDevice> ndLocal, bool allowRecursion) const
 {
-  uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
-  Ptr<Ipv4> ipv4Local = GetObject<Ipv4> ();
-  NS_ASSERT (ipv4Local);
-  Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
-  Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+  NS_LOG_FUNCTION (ndLocal << allowRecursion);
 
   Ptr<Channel> ch = ndLocal->GetChannel();
   uint32_t nDevices = ch->GetNDevices();
   NS_ASSERT (nDevices);
-  Ipv4Address lowest = addrLocal;
-  // iterate all NetDevices and return the lowest numbered IP address 
+
+  NS_LOG_LOGIC ("Looking for designated router off of net device " << ndLocal << " on node " << 
+                ndLocal->GetNode ()->GetId ());
+
+  Ipv4Address desigRtr ("255.255.255.255");
+
+  //
+  // Look through all of the devices on the channel to which the net device
+  // in question is attached.
+  //
   for (uint32_t i = 0; i < nDevices; i++)
     {
-      Ptr<NetDevice> tempNd = ch->GetDevice (i);
-      NS_ASSERT (tempNd);
-      Ptr<Node> tempNode = tempNd->GetNode ();
-      uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
-      Ptr<Ipv4> tempIpv4 = tempNode->GetObject<Ipv4> ();
-      NS_ASSERT (tempIpv4);
-      Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
-      if (tempAddr < addrLocal)
+      Ptr<NetDevice> ndOther = ch->GetDevice (i);
+      NS_ASSERT (ndOther);
+
+      Ptr<Node> nodeOther = ndOther->GetNode ();
+
+      NS_LOG_LOGIC ("Examine channel device " << i << " on node " << nodeOther->GetId ());
+
+      //
+      // For all other net devices, we need to check and see if a router
+      // is present.  If the net device on the other side is a bridged
+      // device, we need to consider all of the other devices on the 
+      // bridge as well (all of the bridge ports.
+      //
+      NS_LOG_LOGIC ("checking to see if the device is bridged");
+      Ptr<BridgeNetDevice> bnd = NetDeviceIsBridged (ndOther);
+      if (bnd)
         {
-          addrLocal = tempAddr;
+          NS_LOG_LOGIC ("Device is bridged by BridgeNetDevice " << bnd);
+
+          //
+          // It is possible that the bridge net device is sitting under a
+          // router, so we have to check for the presence of that router
+          // before we run off and follow all the links
+          //
+          // We require a designated router to have a GlobalRouter interface and
+          // an internet stack that includes the Ipv4 interface.  If it doesn't
+          // it can't play router.
+          //
+          NS_LOG_LOGIC ("Checking for router on bridge net device " << bnd);
+          Ptr<GlobalRouter> rtr = nodeOther->GetObject<GlobalRouter> ();
+          Ptr<Ipv4> ipv4 = nodeOther->GetObject<Ipv4> ();
+          if (rtr && ipv4)
+            {
+              uint32_t ifIndexOther;
+              if (FindIfIndexForDevice(nodeOther, bnd, ifIndexOther))
+                {
+                  NS_LOG_LOGIC ("Found router on bridge net device " << bnd);
+                  Ipv4Address addrOther = ipv4->GetAddress (ifIndexOther);
+                  desigRtr = addrOther < desigRtr ? addrOther : desigRtr;
+                  NS_LOG_LOGIC ("designated router now " << desigRtr);
+                }
+            }
+
+          NS_LOG_LOGIC ("Looking through bridge ports of bridge net device " << bnd);
+          for (uint32_t j = 0; j < bnd->GetNBridgePorts (); ++j)
+            {
+              Ptr<NetDevice> ndBridged = bnd->GetBridgePort (j);
+              NS_LOG_LOGIC ("Examining bridge port " << j << " device " << ndBridged);
+              if (ndBridged == ndOther)
+                {
+                  NS_LOG_LOGIC ("That bridge port is me, don't walk backward");
+                  continue;
+                }
+
+              if (allowRecursion)
+                {
+                  NS_LOG_LOGIC ("Recursively looking for routers down bridge port " << ndBridged);
+                  Ipv4Address addrOther = FindDesignatedRouterForLink (ndBridged, false);
+                  desigRtr = addrOther < desigRtr ? addrOther : desigRtr;
+                  NS_LOG_LOGIC ("designated router now " << desigRtr);
+                }
+            }
+        }
+      else
+        {
+          NS_LOG_LOGIC ("This device is not bridged");
+          Ptr<Node> nodeOther = ndOther->GetNode ();
+          NS_ASSERT (nodeOther);
+
+          //
+          // We require a designated router to have a GlobalRouter interface and
+          // an internet stack that includes the Ipv4 interface.  If it doesn't
+          //
+          Ptr<GlobalRouter> rtr = nodeOther->GetObject<GlobalRouter> ();
+          Ptr<Ipv4> ipv4 = nodeOther->GetObject<Ipv4> ();
+          if (rtr && ipv4)
+            {
+              uint32_t ifIndexOther;
+              if (FindIfIndexForDevice(nodeOther, ndOther, ifIndexOther))
+                {
+                  NS_LOG_LOGIC ("Found router on net device " << ndOther);
+                  Ipv4Address addrOther = ipv4->GetAddress (ifIndexOther);
+                  desigRtr = addrOther < desigRtr ? addrOther : desigRtr;
+                  NS_LOG_LOGIC ("designated router now " << desigRtr);
+                }
+            }
         }
     }
-  return addrLocal;
+  return desigRtr;
+}
+
+//
+// Given a node and an attached net device, take a look off in the channel to 
+// which the net device is attached and look for a node on the other side
+// that has a GlobalRouter interface aggregated.  Life gets more complicated
+// when there is a bridged net device on the other side.
+//
+  bool
+GlobalRouter::AnotherRouterOnLink (Ptr<NetDevice> nd, bool allowRecursion) const
+{
+  NS_LOG_FUNCTION (nd << allowRecursion);
+
+  Ptr<Channel> ch = nd->GetChannel();
+  uint32_t nDevices = ch->GetNDevices();
+  NS_ASSERT (nDevices);
+
+  NS_LOG_LOGIC ("Looking for routers off of net device " << nd << " on node " << nd->GetNode ()->GetId ());
+
+  //
+  // Look through all of the devices on the channel to which the net device
+  // in question is attached.
+  //
+  for (uint32_t i = 0; i < nDevices; i++)
+    {
+      Ptr<NetDevice> ndOther = ch->GetDevice (i);
+      NS_ASSERT (ndOther);
+
+      NS_LOG_LOGIC ("Examine channel device " << i << " on node " << ndOther->GetNode ()->GetId ());
+
+      // 
+      // Ignore the net device itself.
+      //
+      if (ndOther == nd)
+        {
+          NS_LOG_LOGIC ("Myself, skip");
+          continue;
+        }
+
+      //
+      // For all other net devices, we need to check and see if a router
+      // is present.  If the net device on the other side is a bridged
+      // device, we need to consider all of the other devices on the 
+      // bridge.
+      //
+      NS_LOG_LOGIC ("checking to see if device is bridged");
+      Ptr<BridgeNetDevice> bnd = NetDeviceIsBridged (ndOther);
+      if (bnd)
+        {
+          NS_LOG_LOGIC ("Device is bridged by net device " << bnd);
+          NS_LOG_LOGIC ("Looking through bridge ports of bridge net device " << bnd);
+          for (uint32_t j = 0; j < bnd->GetNBridgePorts (); ++j)
+            {
+              Ptr<NetDevice> ndBridged = bnd->GetBridgePort (j);
+              NS_LOG_LOGIC ("Examining bridge port " << j << " device " << ndBridged);
+              if (ndBridged == ndOther)
+                {
+                  NS_LOG_LOGIC ("That bridge port is me, skip");
+                  continue;
+                }
+
+              if (allowRecursion)
+                {
+                  NS_LOG_LOGIC ("Recursively looking for routers on bridge port " << ndBridged);
+                  if (AnotherRouterOnLink (ndBridged, false))
+                    {
+                      NS_LOG_LOGIC ("Found routers on bridge port, return true");
+                      return true;
+                    }
+                }
+            }
+          NS_LOG_LOGIC ("No routers on bridged net device, return false");
+          return false;
+        }
+
+      NS_LOG_LOGIC ("This device is not bridged");
+      Ptr<Node> nodeTemp = ndOther->GetNode ();
+      NS_ASSERT (nodeTemp);
+
+      Ptr<GlobalRouter> rtr = nodeTemp->GetObject<GlobalRouter> ();
+      if (rtr)
+        {
+          NS_LOG_LOGIC ("Found GlobalRouter interface, return true");
+          return true;
+        }
+      else 
+        {
+          NS_LOG_LOGIC ("No GlobalRouter interface on device, continue search");
+        }
+    }
+  NS_LOG_LOGIC ("No routers found, return false");
+  return false;
 }
 
   uint32_t 
@@ -820,11 +1367,10 @@
 // other end.  This only makes sense with a point-to-point channel.
 //
   Ptr<NetDevice>
-GlobalRouter::GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const
+GlobalRouter::GetAdjacent (Ptr<NetDevice> nd, Ptr<Channel> ch) const
 {
   NS_LOG_FUNCTION_NOARGS ();
-  NS_ASSERT_MSG(ch->GetNDevices() == 2, 
-    "GlobalRouter::GetAdjacent (): Channel with other than two devices");
+  NS_ASSERT_MSG(ch->GetNDevices() == 2, "GlobalRouter::GetAdjacent (): Channel with other than two devices");
 //
 // This is a point to point channel with two endpoints.  Get both of them.
 //
@@ -852,24 +1398,79 @@
 }
 
 //
-// Given a node and a net device, find the IPV4 interface index that 
-// corresponds to that net device.
+// Given a node and a net device, find an IPV4 interface index that corresponds
+// to that net device.  This function may fail for various reasons.  If a node
+// does not have an internet stack (for example if it is a bridge) we won't have
+// an IPv4 at all.  If the node does have a stack, but the net device in question
+// is bridged, there will not be an interface associated directly with the device.
 //
-  uint32_t
-GlobalRouter::FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const
+  bool
+GlobalRouter::FindIfIndexForDevice (Ptr<Node> node, Ptr<NetDevice> nd, uint32_t &index) const
 {
   NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_LOGIC("For node " << node->GetId () << " for net device " << nd );
+
   Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
-  NS_ASSERT_MSG(ipv4, "QI for <Ipv4> interface failed");
+  if (ipv4 == 0)
+    {
+      NS_LOG_LOGIC ("No Ipv4 interface on node " << node->GetId ());
+      return false;
+    }
+
   for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i )
     {
       if (ipv4->GetNetDevice(i) == nd) 
         {
-          return i;
+          NS_LOG_LOGIC ("Device " << nd << " has associated ipv4 index " << i);
+          index = i;
+          return true;
         }
     }
 
-  NS_ASSERT_MSG(0, "Cannot find interface for device");
+  NS_LOG_LOGIC ("Device " << nd << " has no associated ipv4 index");
+  return false;
+}
+
+//
+// Decide whether or not a given net device is being bridged by a BridgeNetDevice.
+//
+  Ptr<BridgeNetDevice>
+GlobalRouter::NetDeviceIsBridged (Ptr<NetDevice> nd) const
+{
+  NS_LOG_FUNCTION (nd);
+
+  Ptr<Node> node = nd->GetNode ();
+  uint32_t nDevices = node->GetNDevices();
+
+  //
+  // There is no bit on a net device that says it is being bridged, so we have
+  // to look for bridges on the node to which the device is attached.  If we
+  // find a bridge, we need to look through its bridge ports (the devices it
+  // bridges) to see if we find the device in question.
+  //
+  for (uint32_t i = 0; i < nDevices; ++i)
+    {
+      Ptr<NetDevice> ndTest = node->GetDevice(i);
+      NS_LOG_LOGIC ("Examine device " << i << " " << ndTest);
+
+      if (ndTest->IsBridge ())
+        {
+          NS_LOG_LOGIC ("device " << i << " is a bridge net device");
+          Ptr<BridgeNetDevice> bnd = ndTest->GetObject<BridgeNetDevice> ();
+          NS_ABORT_MSG_UNLESS (bnd, "GlobalRouter::DiscoverLSAs (): GetObject for <BridgeNetDevice> failed");
+
+          for (uint32_t j = 0; j < bnd->GetNBridgePorts (); ++j)
+            {
+              NS_LOG_LOGIC ("Examine bridge port " << j << " " << bnd->GetBridgePort (j));
+              if (bnd->GetBridgePort (j) == nd)
+                {
+                  NS_LOG_LOGIC ("Net device " << nd << " is bridged by " << bnd);
+                  return bnd;
+                }
+            }
+        }
+    }
+  NS_LOG_LOGIC ("Net device " << nd << " is not bridged");
   return 0;
 }
 
--- a/src/routing/global-routing/global-router-interface.h	Fri Nov 28 08:55:24 2008 +0100
+++ b/src/routing/global-routing/global-router-interface.h	Fri Nov 28 08:56:47 2008 +0100
@@ -29,10 +29,14 @@
 #include "ns3/node.h"
 #include "ns3/channel.h"
 #include "ns3/ipv4-address.h"
+#include "ns3/net-device-container.h"
+#include "ns3/bridge-net-device.h"
 #include "ns3/global-route-manager.h"
 
 namespace ns3 {
 
+class GlobalRouter;
+
 /**
  * @brief A single link record for a link state advertisement.
  *
@@ -43,6 +47,7 @@
 class GlobalRoutingLinkRecord
 {
 public:
+  friend class GlobalRoutingLSA;
 /**
  * @enum LinkType
  * @brief Enumeration of the possible types of Global Routing Link Records.
@@ -639,9 +644,17 @@
   void ClearLSAs (void);
 
   Ptr<NetDevice> GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const;
-  uint32_t FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const;
-  Ipv4Address FindDesignatedRouterForLink (Ptr<Node> node,   
-    Ptr<NetDevice> ndLocal) const;
+  bool FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd, uint32_t &index) const;
+  Ipv4Address FindDesignatedRouterForLink (Ptr<NetDevice> ndLocal, bool allowRecursion) const;
+  bool AnotherRouterOnLink (Ptr<NetDevice> nd, bool allowRecursion) const;
+  void ProcessBroadcastLink (Ptr<NetDevice> nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c);
+  void ProcessSingleBroadcastLink (Ptr<NetDevice> nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c);
+  void ProcessBridgedBroadcastLink (Ptr<NetDevice> nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c);
+
+  void ProcessPointToPointLink (Ptr<NetDevice> ndLocal, GlobalRoutingLSA *pLSA);
+  void BuildNetworkLSAs (NetDeviceContainer c);
+  Ptr<BridgeNetDevice> NetDeviceIsBridged (Ptr<NetDevice> nd) const;
+
 
   typedef std::list<GlobalRoutingLSA*> ListOfLSAs_t;
   ListOfLSAs_t m_LSAs;
--- a/wscript	Fri Nov 28 08:55:24 2008 +0100
+++ b/wscript	Fri Nov 28 08:56:47 2008 +0100
@@ -447,16 +447,13 @@
 
     if Params.g_options.run:
         # Check that the requested program name is valid
-        try:
-            wutils.find_program(Params.g_options.run, env)
-        except ValueError, ex:
-            Params.fatal(str(ex))
-        
+        program_name, dummy_program_argv = wutils.get_run_program(Params.g_options.run, get_command_template())
+
         # When --run'ing a program, tell WAF to only build that program,
         # nothing more; this greatly speeds up compilation when all you
         # want to do is run a test program.
         if not Params.g_options.compile_targets:
-            Params.g_options.compile_targets = Params.g_options.run
+            Params.g_options.compile_targets = program_name
 
 
 
--- a/wutils.py	Fri Nov 28 08:55:24 2008 +0100
+++ b/wutils.py	Fri Nov 28 08:56:47 2008 +0100
@@ -94,13 +94,12 @@
         Params.fatal("Command %s exited with code %i" % (argv, retval))
     return retval
 
-def run_program(program_string, command_template=None):
+def get_run_program(program_string, command_template=None):
     """
-    if command_template is not None, then program_string == program
-    name and argv is given by command_template with %s replaced by the
-    full path to the program.  Else, program_string is interpreted as
-    a shell command with first name being the program name.
+    Return the program name and argv of the process that would be executed by
+    run_program(program_string, command_template).
     """
+    #print "get_run_program_argv(program_string=%r, command_template=%r)" % (program_string, command_template)
     env = Params.g_build.env_of_name('default')
 
     if command_template in (None, '%s'):
@@ -132,7 +131,16 @@
             Params.fatal("%s does not appear to be a program" % (program_name,))
 
         execvec = shlex.split(command_template % (program_node.abspath(env),))
+    return program_name, execvec
 
+def run_program(program_string, command_template=None):
+    """
+    if command_template is not None, then program_string == program
+    name and argv is given by command_template with %s replaced by the
+    full path to the program.  Else, program_string is interpreted as
+    a shell command with first name being the program name.
+    """
+    dummy_program_name, execvec = get_run_program(program_string, command_template)
     former_cwd = os.getcwd()
     if (Params.g_options.cwd_launch):
         os.chdir(Params.g_options.cwd_launch)