src/internet-stack/ipv4-static-routing-impl.cc
changeset 4571 2c9c600270e0
parent 4560 2f106fd728ab
--- a/src/internet-stack/ipv4-static-routing-impl.cc	Fri Jun 19 14:12:59 2009 -0700
+++ b/src/internet-stack/ipv4-static-routing-impl.cc	Sun Jun 21 22:29:08 2009 -0700
@@ -224,11 +224,10 @@
           NS_LOG_LOGIC ("Found global host route" << *i);
           Ipv4RoutingTableEntry* route = (*i);
           rtentry = Create<Ipv4Route> ();
+          uint32_t interfaceIdx = route->GetInterface ();
           rtentry->SetDestination (route->GetDest ());
-          // XXX handle multi-address case
-          rtentry->SetSource (m_ipv4->GetAddress (route->GetInterface(), 0).GetLocal ());
+          rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
           rtentry->SetGateway (route->GetGateway ());
-          uint32_t interfaceIdx = route->GetInterface ();
           rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
           return rtentry;
         }
@@ -245,11 +244,10 @@
           NS_LOG_LOGIC ("Found global network route" << *j);
           Ipv4RoutingTableEntry* route = (*j);
           rtentry = Create<Ipv4Route> ();
+          uint32_t interfaceIdx = route->GetInterface ();
           rtentry->SetDestination (route->GetDest ());
-          // XXX handle multi-address case
-          rtentry->SetSource (m_ipv4->GetAddress (route->GetInterface(), 0).GetLocal ());
+          rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
           rtentry->SetGateway (route->GetGateway ());
-          uint32_t interfaceIdx = route->GetInterface ();
           rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
           return rtentry;
         }
@@ -260,11 +258,10 @@
       NS_LOG_LOGIC ("Found global network route" << m_defaultRoute);
       Ipv4RoutingTableEntry* route = m_defaultRoute;
       rtentry = Create<Ipv4Route> ();
+      uint32_t interfaceIdx = route->GetInterface ();
       rtentry->SetDestination (route->GetDest ());
-      // XXX handle multi-address case
-      rtentry->SetSource (m_ipv4->GetAddress (route->GetInterface(), 0).GetLocal ());
+      rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
       rtentry->SetGateway (route->GetGateway ());
-      uint32_t interfaceIdx = route->GetInterface ();
       rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
       return rtentry;
     }
@@ -469,7 +466,8 @@
   return rtentry;
 }
 
-// XXX this method not robust enough to work independent of ListRouting
+// XXX this method not robust enough to work outside of ListRouting context
+// because it will not perform local delivery
 bool 
 Ipv4StaticRoutingImpl::RouteInput  (Ptr<const Packet> p, const Ipv4Header &ipHeader, Ptr<const NetDevice> idev,
                              UnicastForwardCallback ucb, MulticastForwardCallback mcb,
@@ -641,4 +639,30 @@
     }
 }
 
+Ipv4Address
+Ipv4StaticRoutingImpl::SourceAddressSelection (uint32_t interfaceIdx, Ipv4Address dest)
+{
+  if (m_ipv4->GetNAddresses (interfaceIdx) == 1)  // common case
+    {
+      return m_ipv4->GetAddress (interfaceIdx, 0).GetLocal ();
+    }
+  // no way to determine the scope of the destination, so adopt the
+  // following rule:  pick the first available address (index 0) unless
+  // a subsequent address is on link (in which case, pick the primary
+  // address if there are multiple)
+  Ipv4Address candidate = m_ipv4->GetAddress (interfaceIdx, 0).GetLocal ();
+  for (uint32_t i = 0; i < m_ipv4->GetNAddresses (interfaceIdx); i++)
+    {
+      Ipv4InterfaceAddress test = m_ipv4->GetAddress (interfaceIdx, i);
+      if (test.GetLocal ().CombineMask (test.GetMask ()) == dest.CombineMask (test.GetMask ()))
+        {
+          if (test.IsSecondary () == false) 
+            {
+              return test.GetLocal ();
+            }
+        }
+    }
+  return candidate;
+}
+
 }//namespace ns3