From 949955818641371df834c6ece4f18191dc04101d Mon Sep 17 00:00:00 2001 From: Tommaso Pecorella Date: Tue, 10 Dec 2013 19:54:12 +0100 Subject: [PATCH] Pretty-print IPv6 addresses and routing tables --- CHANGES.html | 1 + RELEASE_NOTES | 3 + src/internet/model/ipv6-interface-address.cc | 18 ++- .../model/ipv6-routing-table-entry.cc | 34 ++-- src/internet/model/ipv6-static-routing.cc | 47 +++++- src/network/utils/ipv6-address.cc | 150 ++++++++++++++---- src/network/utils/ipv6-address.h | 2 +- 7 files changed, 193 insertions(+), 62 deletions(-) diff --git a/CHANGES.html b/CHANGES.html index 24b1361f3..712367908 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -97,6 +97,7 @@ us a note on ns-developers mailing list.


diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e19a42eea..23953ee4d 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -21,6 +21,9 @@ Supported platforms 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. diff --git a/src/internet/model/ipv6-interface-address.cc b/src/internet/model/ipv6-interface-address.cc index 29911e4d1..3f806e1ba 100644 --- a/src/internet/model/ipv6-interface-address.cc +++ b/src/internet/model/ipv6-interface-address.cc @@ -140,8 +140,22 @@ Ipv6InterfaceAddress::Scope_e Ipv6InterfaceAddress::GetScope () const 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; } diff --git a/src/internet/model/ipv6-routing-table-entry.cc b/src/internet/model/ipv6-routing-table-entry.cc index b297db4ce..f79f1b4f2 100644 --- a/src/internet/model/ipv6-routing-table-entry.cc +++ b/src/internet/model/ipv6-routing-table-entry.cc @@ -208,36 +208,36 @@ std::ostream& operator<< (std::ostream& os, Ipv6RoutingTableEntry const& route) 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 @@ Ipv6MulticastRoutingTableEntry Ipv6MulticastRoutingTableEntry::CreateMulticastRo 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) { diff --git a/src/internet/model/ipv6-static-routing.cc b/src/internet/model/ipv6-static-routing.cc index 5906a1768..861d96a08 100644 --- a/src/internet/model/ipv6-static-routing.cc +++ b/src/internet/model/ipv6-static-routing.cc @@ -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::SetIpv6 (Ptr ipv6) void Ipv6StaticRouting::PrintRoutingTable (Ptr stream) const { - NS_LOG_FUNCTION (this); + NS_LOG_FUNCTION (this << stream); std::ostream* os = stream->GetStream (); + + *os << "Node: " << m_ipv6->GetObject ()->GetId () + << " Time: " << Simulator::Now ().GetSeconds () << "s " + << "Ipv6StaticRouting table" << std::endl; + if (GetNRoutes () > 0) { - *os << "Node: " << m_ipv6->GetObject ()->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 @@ void Ipv6StaticRouting::NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Ad 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); } diff --git a/src/network/utils/ipv6-address.cc b/src/network/utils/ipv6-address.cc index 64392a7c1..7c5508201 100644 --- a/src/network/utils/ipv6-address.cc +++ b/src/network/utils/ipv6-address.cc @@ -18,6 +18,29 @@ * Author: Sebastien Vincent */ +// 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 #include @@ -478,23 +501,96 @@ Ipv6Address Ipv6Address::MakeSolicitedAddress (Ipv6Address addr) 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 @@ bool Ipv6Address::IsLinkLocalMulticast () const 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 @@ bool Ipv6Prefix::IsMatch (Ipv6Address a, Ipv6Address b) const 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 () diff --git a/src/network/utils/ipv6-address.h b/src/network/utils/ipv6-address.h index 44b914ae4..d9e262703 100644 --- a/src/network/utils/ipv6-address.h +++ b/src/network/utils/ipv6-address.h @@ -269,7 +269,7 @@ public: * \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