Pretty-print IPv6 addresses and routing tables
authorTommaso Pecorella <tommaso.pecorella@unifi.it>
Tue, 10 Dec 2013 19:54:12 +0100
changeset 10494 69f1d28a831e
parent 10493 ccb3c64e55e8
child 10495 e877c029ed3e
Pretty-print IPv6 addresses and routing tables
CHANGES.html
RELEASE_NOTES
src/internet/model/ipv6-interface-address.cc
src/internet/model/ipv6-routing-table-entry.cc
src/internet/model/ipv6-static-routing.cc
src/network/utils/ipv6-address.cc
src/network/utils/ipv6-address.h
--- a/CHANGES.html	Tue Dec 10 19:56:16 2013 +0100
+++ b/CHANGES.html	Tue Dec 10 19:54:12 2013 +0100
@@ -97,6 +97,7 @@
 <ul>
   <li> For the TapBridge device, in UseLocal mode there is a MAC learning function. TapBridge has been waiting for the first packet received from tap interface to set the address of the bridged device to the source address of the first packet. This has caused problems with WiFi.  The new behavior is that after connection to the tap interface, ns-3 learns the MAC address of that interface with a system call and immediately sets the address of the bridged device to the learned one.  See <a href="https://www.nsnam.org/bugzilla/show_bug.cgi?id=1777">bug 1777</a> for more details.</li>
   <li> TapBridge device now correctly implements IsLinkUp() method.</li>
+  <li> IPv6 addresses and routing tables are printed like in Linux "route -A inet6" command.</li>
 </ul>
 
 <hr>
--- a/RELEASE_NOTES	Tue Dec 10 19:56:16 2013 +0100
+++ b/RELEASE_NOTES	Tue Dec 10 19:54:12 2013 +0100
@@ -21,6 +21,9 @@
 
 New user-visible features
 -------------------------
+- IPv6 addresses and routing tables are printed in a more conventional way,
+  closely matching the Linux "route -A inet6" command.
+  
 - new SixLowPanNetDevice model, headers and associated helpers.  The 
   SixLowPanNetDevice is able to act as a shim between IPv6 and a NetDevice, 
   compressing IPv6 headers according to RFCs 4944 and 6262.
--- a/src/internet/model/ipv6-interface-address.cc	Tue Dec 10 19:56:16 2013 +0100
+++ b/src/internet/model/ipv6-interface-address.cc	Tue Dec 10 19:54:12 2013 +0100
@@ -140,8 +140,22 @@
 
 std::ostream& operator<< (std::ostream& os, const Ipv6InterfaceAddress &addr)
 {
-  os << "address=" << addr.GetAddress () << "; prefix=" <<
-  addr.GetPrefix () << "; scope=" << addr.GetScope ();
+  os << "address: " << addr.GetAddress () << addr.GetPrefix () << "; scope: ";
+  switch (addr.GetScope ())
+  {
+    case Ipv6InterfaceAddress::HOST:
+      os << "HOST";
+      break;
+    case Ipv6InterfaceAddress::LINKLOCAL:
+      os << "LINK-LOCAL";
+      break;
+    case Ipv6InterfaceAddress::GLOBAL:
+      os << "GLOBAL";
+      break;
+    default:
+      os << "UNKNOWN";
+      break;
+  }
   return os;
 }
 
--- a/src/internet/model/ipv6-routing-table-entry.cc	Tue Dec 10 19:56:16 2013 +0100
+++ b/src/internet/model/ipv6-routing-table-entry.cc	Tue Dec 10 19:54:12 2013 +0100
@@ -208,36 +208,36 @@
   if (route.IsDefault ())
     {
       NS_ASSERT (route.IsGateway ());
-      os << "default out =" << route.GetInterface () << ", next hop =" << route.GetGateway ();
+      os << "default out: " << route.GetInterface () << ", next hop: " << route.GetGateway ();
     }
   else if (route.IsHost ())
     {
       if (route.IsGateway ())
         {
-          os << "host ="<< route.GetDest () <<
-          ", out =" << route.GetInterface () <<
-          ", next hop =" << route.GetGateway ();
+          os << "host: "<< route.GetDest () <<
+          ", out: " << route.GetInterface () <<
+          ", next hop: " << route.GetGateway ();
         }
       else
         {
-          os << "host =" << route.GetDest () <<
-          ", out =" << route.GetInterface ();
+          os << "host: " << route.GetDest () <<
+          ", out: " << route.GetInterface ();
         }
     }
   else if (route.IsNetwork ())
     {
       if (route.IsGateway ())
         {
-          os << "network =" << route.GetDestNetwork () <<
-          ", mask =" << route.GetDestNetworkPrefix () <<
-          ",out =" << route.GetInterface () <<
-          ", next hop =" << route.GetGateway ();
+          os << "network: " << route.GetDestNetwork () <<
+          "/ " << int(route.GetDestNetworkPrefix ().GetPrefixLength ()) <<
+          ", out: " << route.GetInterface () <<
+          ", next hop: " << route.GetGateway ();
         }
       else
         {
-          os << "network =" << route.GetDestNetwork () <<
-          ", mask =" << route.GetDestNetworkPrefix () <<
-          ",out =" << route.GetInterface ();
+          os << "network: " << route.GetDestNetwork () <<
+          "/" << int(route.GetDestNetworkPrefix ().GetPrefixLength ()) <<
+          ", out: " << route.GetInterface ();
         }
     }
   else
@@ -314,10 +314,10 @@
 
 std::ostream& operator<< (std::ostream& os, Ipv6MulticastRoutingTableEntry const& route)
 {
-  os << "origin =" << route.GetOrigin () <<
-  ", group =" << route.GetGroup () <<
-  ", input interface =" << route.GetInputInterface () <<
-  ", output interfaces =";
+  os << "origin: " << route.GetOrigin () <<
+  ", group: " << route.GetGroup () <<
+  ", input interface: " << route.GetInputInterface () <<
+  ", output interfaces: ";
 
   for (uint32_t i = 0; i < route.GetNOutputInterfaces (); ++i)
     {
--- a/src/internet/model/ipv6-static-routing.cc	Tue Dec 10 19:56:16 2013 +0100
+++ b/src/internet/model/ipv6-static-routing.cc	Tue Dec 10 19:54:12 2013 +0100
@@ -25,6 +25,7 @@
 #include "ns3/simulator.h"
 #include "ns3/ipv6-route.h"
 #include "ns3/net-device.h"
+#include "ns3/names.h"
 
 #include "ipv6-static-routing.h"
 #include "ipv6-routing-table-entry.h"
@@ -80,18 +81,48 @@
 void
 Ipv6StaticRouting::PrintRoutingTable (Ptr<OutputStreamWrapper> stream) const
 {
-  NS_LOG_FUNCTION (this);
+  NS_LOG_FUNCTION (this << stream);
   std::ostream* os = stream->GetStream ();
+
+  *os << "Node: " << m_ipv6->GetObject<Node> ()->GetId ()
+      << " Time: " << Simulator::Now ().GetSeconds () << "s "
+      << "Ipv6StaticRouting table" << std::endl;
+
   if (GetNRoutes () > 0)
     {
-      *os << "Node: " << m_ipv6->GetObject<Node> ()->GetId ()
-          << " Time: " << Simulator::Now ().GetSeconds () << "s "
-          << "Ipv6StaticRouting table" << std::endl;
-
+      *os << "Destination                    Next Hop                   Flag Met Ref Use If" << std::endl;
       for (uint32_t j = 0; j < GetNRoutes (); j++)
         {
+          std::ostringstream dest, gw, mask, flags;
           Ipv6RoutingTableEntry route = GetRoute (j);
-          *os << route << std::endl;
+          dest << route.GetDest () << "/" << int(route.GetDestNetworkPrefix ().GetPrefixLength ());
+          *os << std::setiosflags (std::ios::left) << std::setw (31) << dest.str ();
+          gw << route.GetGateway ();
+          *os << std::setiosflags (std::ios::left) << std::setw (27) << gw.str ();
+          flags << "U";
+          if (route.IsHost ())
+            {
+              flags << "H";
+            }
+          else if (route.IsGateway ())
+            {
+              flags << "G";
+            }
+          *os << std::setiosflags (std::ios::left) << std::setw (5) << flags.str ();
+          *os << std::setiosflags (std::ios::left) << std::setw (4) << GetMetric (j);
+          // Ref ct not implemented
+          *os << "-" << "   ";
+          // Use not implemented
+          *os << "-" << "   ";
+          if (Names::FindName (m_ipv6->GetNetDevice (route.GetInterface ())) != "")
+            {
+              *os << Names::FindName (m_ipv6->GetNetDevice (route.GetInterface ()));
+            }
+          else
+            {
+              *os << route.GetInterface ();
+            }
+          *os << std::endl;
         }
     }
 }
@@ -724,12 +755,12 @@
   else /* default route */
     {
       /* this case is mainly used by configuring default route following RA processing,
-       * in case of multipe prefix in RA, the first will configured default route
+       * in case of multiple prefix in RA, the first will configured default route
        */
 
       /* for the moment, all default route has the same metric
        * so according to the longest prefix algorithm,
-       * the default route choosen will be the last added
+       * the default route chosen will be the last added
        */
       SetDefaultRoute (nextHop, interface, prefixToUse);
     }
--- a/src/network/utils/ipv6-address.cc	Tue Dec 10 19:56:16 2013 +0100
+++ b/src/network/utils/ipv6-address.cc	Tue Dec 10 19:54:12 2013 +0100
@@ -18,6 +18,29 @@
  * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
  */
 
+// Part of the Ipv6Address::Print function has been adapted from inet_ntop6 Linux function.
+// See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html
+// Author: Paul Vixie, 1996.
+// The inet_ntop6 function was under the copyright below, which is
+// compatible with GPLv2, see http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses.
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+
 #include <iomanip>
 #include <memory.h>
 
@@ -478,23 +501,96 @@
 void Ipv6Address::Print (std::ostream& os) const
 {
   NS_LOG_FUNCTION (this << &os);
-  os << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[0]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[1] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[2]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[3] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[4]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[5] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[6]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[7] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[8]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[9] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[10]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[11] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[12]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[13] << ":"
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[14]
-     << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[15]
-     << std::dec << std::setfill (' ');
+
+  // note: part of this function has been adapted from inet_ntop6 Linux function.
+  // See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html
+  // Author: Paul Vixie, 1996.
+
+  if (IsIpv4MappedAddress ())
+    {
+      os << "::ffff:"
+         << (unsigned int) m_address[12] << "."
+         << (unsigned int) m_address[13] << "."
+         << (unsigned int) m_address[14] << "."
+         << (unsigned int) m_address[15];
+      return;
+    }
+
+  uint16_t address[8];
+  uint8_t i;
+
+  for (i=0; i<8; i++)
+    {
+      address[i] = (uint16_t(m_address[2*i]) << 8) | uint16_t(m_address[2*i+1]);
+    }
+
+  int8_t bestBase = -1;
+  int8_t bestLen = 0;
+  int8_t curBase = -1;
+  int8_t curLen = 0;
+
+  for (i=0; i<8; i++)
+    {
+      if (address[i] == 0)
+        {
+          if (curBase == -1)
+            {
+              curBase = i;
+              curLen = 1;
+            }
+          else
+            {
+              curLen++;
+            }
+        }
+      else
+        {
+          if (curBase != -1)
+            {
+              if (bestBase == -1 || curLen > bestLen)
+                {
+                  bestBase = curBase;
+                  bestLen = curLen;
+                }
+              curBase = -1;
+            }
+        }
+    }
+  if (curBase != -1)
+    {
+      if (bestBase == -1 || curLen > bestLen)
+        {
+          bestBase = curBase;
+          bestLen = curLen;
+        }
+    }
+  if (bestBase != -1 && bestLen < 2)
+    {
+      bestBase = -1;
+    }
+
+  for (i = 0; i < 8;) {
+      // Are we inside the best run of 0x00's?
+      if (i == bestBase)
+        {
+          os << ':';
+          i += bestLen;
+          continue;
+        }
+      // Are we following an initial run of 0x00s or any real hex?
+      if (i != 0)
+        {
+          os << ':';
+        }
+      os << std::hex << (unsigned int) address[i];
+      i++;
+  }
+  // Was it a trailing run of 0x00's?
+  if (bestBase != -1 && (bestBase + bestLen) == 8)
+    {
+      os << ':';
+    }
+  os << std::dec;
 }
 
 bool Ipv6Address::IsLocalhost () const
@@ -524,7 +620,7 @@
   return false;
 }
 
-bool Ipv6Address::IsIpv4MappedAddress ()
+bool Ipv6Address::IsIpv4MappedAddress () const
 {
   NS_LOG_FUNCTION (this);
   uint8_t v4MappedPrefix[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -832,22 +928,8 @@
 void Ipv6Prefix::Print (std::ostream &os) const
 {
   NS_LOG_FUNCTION (this << &os);
-  os << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[0]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[1] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[2]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[3] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[4]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[5] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[6]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[7] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[8]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[9] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[10]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[11] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[12]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[13] << ":"
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[14]
-  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[15];
+
+  os << "/" << (unsigned int) GetPrefixLength();
 }
 
 Ipv6Prefix Ipv6Prefix::GetLoopback ()
--- a/src/network/utils/ipv6-address.h	Tue Dec 10 19:56:16 2013 +0100
+++ b/src/network/utils/ipv6-address.h	Tue Dec 10 19:54:12 2013 +0100
@@ -269,7 +269,7 @@
    * \brief If the address is an IPv4-mapped address
    * \return true if address is an IPv4-mapped address, otherwise false.
    */
-  bool IsIpv4MappedAddress();
+  bool IsIpv4MappedAddress() const;
 
   /**
    * \brief Convert to Address object