diff --git a/src/sixlowpan/doc/sixlowpan.rst b/src/sixlowpan/doc/sixlowpan.rst index a85d501d1..46c08de16 100644 --- a/src/sixlowpan/doc/sixlowpan.rst +++ b/src/sixlowpan/doc/sixlowpan.rst @@ -6,7 +6,7 @@ ----------------------------------------------------------------- This chapter describes the implementation of |ns3| model for the -compression of IPv6 packets over IEEE 802.15.4-Based Networks +compression of IPv6 packets over IEEE 802.15.4-Based Networks as specified by :rfc:`4944` and :rfc:`6282`. Model Description @@ -17,31 +17,27 @@ The source code for the sixlowpan module lives in the directory ``src/sixlowpan` Design ====== -The model design does not follow strictly the standard from an architectural +The model design does not follow strictly the standard from an architectural standpoint, as it does extend it beyond the original scope by supporting also other kinds of networks. -Other than that, the module strictly follows :rfc:`4944` and :rfc:`6282`, with the +Other than that, the module strictly follows :rfc:`4944` and :rfc:`6282`, with the following exceptions: -* MESH and LOWPAN_BC0 dispatch types are not supported * HC2 encoding is not supported * IPHC's SAC and DAC are not supported -The MESH and LOWPAN_BC0 are not supported as they do apply only to mesh-under -architecture, which is not one of the goals of the module development. - The HC2 encoding is not supported, as it has been superseded by IPHC and NHC compression type (\ :rfc:`6282`). -IPHC SAC and DAC are not yet supported, as they do require :rfc:`6775` for full -compliance. It is planned to support them in the future. +IPHC SAC and DAC are not yet supported, as they do require :rfc:`6775` for full +compliance. It is planned to support them in the future. NetDevice ######### The whole module is developed as a transparent NetDevice, which can act as a -proxy between IPv6 and any NetDevice (the module has been successfully tested +proxy between IPv6 and any NetDevice (the module has been successfully tested with PointToPointNedevice, CsmaNetDevice and LrWpanNetDevice). For this reason, the module implements a virtual NetDevice, and all the calls are passed @@ -55,19 +51,23 @@ The attributes are: * OmitUdpChecksum (boolean, default true), used to activate UDP checksum compression in IPHC. * FragmentReassemblyListSize (integer, default 0), indicating the number of packets that can be reassembled at the same time. If the limit is reached, the oldest packet is discarded. Zero means infinite. * FragmentExpirationTimeout (Time, default 60 seconds), being the timeout to wait for further fragments before discarding a partial packet. -* CompressionThreshold (unsigned 32 bits integer, default 0), minimum compressed payload size. -* ForceEtherType (boolean, default false), and +* CompressionThreshold (unsigned 32 bits integer, default 0), minimum compressed payload size. +* ForceEtherType (boolean, default false). * EtherType (unsigned 16 bits integer, default 0xFFFF), to force a particular L2 EtherType. +* UseMeshUnder (boolean, default false), it enables mesh-under flood routing. +* MeshUnderRadius (unsigned 8 bits integer, default 10), the maximum number of hops that a packet will be forwarded. +* MeshCacheLength (unsigned 16 bits integer, default 10), the length of the cache for each source. +* MeshUnderJitter (ns3::UniformRandomVariable[Min=0.0|Max=10.0]), the jitter in ms a node uses to forward mesh-under packets - used to prevent collisions. The CompressionThreshold attribute is similar to Contiki's SICSLOWPAN_CONF_MIN_MAC_PAYLOAD option. If a compressed packet size is less than the threshold, the uncompressed version is used (plus one byte for the correct dispatch header). -This option is useful when a MAC requires a minimum frame size (e.g., ContikiMAC) and the +This option is useful when a MAC requires a minimum frame size (e.g., ContikiMAC) and the compression would violate the requirement. The last two attributes are needed to use the module with a NetDevice other than 802.15.4, as neither IANA or IEEE did reserve an EtherType for 6LoWPAN. As a consequence there might be a -conflict with the L2 multiplexer/demultiplexer which is based on EtherType. The default +conflict with the L2 multiplexer/demultiplexer which is based on EtherType. The default value is 0xFFFF, which is reserved by IEEE (see [IANA802]_ and [Ethertype]_). The default module behaviour is to not change the EtherType, however this would not work with any NetDevice actually understanding and using the EtherType. @@ -92,12 +92,34 @@ The Trace sources are: The Tx and Rx traces are called as soon as a packet is received or sent. The Drop trace is invoked when a packet (or a fragment) is discarded. +Mesh-Under routing +################## + +The module provides a very simple mesh-under routing [Shelby]_, implemented as a flooding +(a mesh-under routing protocol is a routing system implemented below IP). + +This functionality can be activated through the UseMeshUnder attribute and fine-tuned using +the MeshUnderRadius and MeshUnderJitter attributes. + +Note that flooding in a PAN generates a lot of overhead, which is often not wanted. +Moreover, when using the mesh-under facility, ALL the packets are sent without acknowledgment +because, at lower level, they are sent to a broadcast address. + +At node level, each packet is re-broadcasted if its BC0 Sequence Number is not in the cache of the +recently seen packets. The cache length (by default 10) can be changed through the MeshCacheLength +attribute. Scope and Limitations ===================== Future versions of this module will support :rfc:`6775`, however no timeframe is guaranteed. +It would be a good idea to improve the mesh-under flooding by providing the following: + +* Adaptive hop-limit calculation, +* Adaptive forwarding jitter, +* Use of direct (non mesh) transmission for packets directed to 1-hop neighbors. + Using 6LoWPAN with IPv4 (or other L3 protocols) ############################################### @@ -110,7 +132,7 @@ in advance. In the |ns3| implementation it is possible, but not advisable, to violate this requirement if the underlying NetDevice is capable of discriminating different protocols. As an example, -CsmaNetDevice can carry IPv4 and 6LoWPAN at the same time. However, this configuration has +CsmaNetDevice can carry IPv4 and 6LoWPAN at the same time. However, this configuration has not been tested. References @@ -121,6 +143,7 @@ References .. [RFC6775] :rfc:`6775`, "Neighbor Discovery Optimization for IPv6 over Low-Power Wireless Personal Area Networks (6LoWPANs)" .. [IANA802] IANA, assigned IEEE 802 numbers: http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xml .. [Ethertype] IEEE Ethertype numbers: http://standards.ieee.org/develop/regauth/ethertype/eth.txt +.. [Shelby] Z. Shelby and C. Bormann, 6LoWPAN: The Wireless Embedded Internet. Wiley, 2011. [Online]. Available: https://books.google.it/books?id=3Nm7ZCxscMQC Usage ***** @@ -133,7 +156,7 @@ Add ``sixlowpan`` to the list of modules built with |ns3|. Helper ====== -The helper is patterned after other device helpers. +The helper is patterned after other device helpers. Examples ======== @@ -156,5 +179,3 @@ Validation The model has been validated against WireShark, checking whatever the packets are correctly interpreted and validated. - - diff --git a/src/sixlowpan/examples/example-ping-lr-wpan-mesh-under.cc b/src/sixlowpan/examples/example-ping-lr-wpan-mesh-under.cc new file mode 100644 index 000000000..4758a113f --- /dev/null +++ b/src/sixlowpan/examples/example-ping-lr-wpan-mesh-under.cc @@ -0,0 +1,141 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Universita' di Firenze, Italy + * + * 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 + * + * Author: Tommaso Pecorella + */ + +#include +#include "ns3/core-module.h" +#include "ns3/internet-module.h" +#include "ns3/internet-apps-module.h" +#include "ns3/mobility-module.h" +#include "ns3/spectrum-module.h" +#include "ns3/propagation-module.h" +#include "ns3/sixlowpan-module.h" +#include "ns3/lr-wpan-module.h" +#include "ns3/csma-module.h" + +using namespace ns3; + +int main (int argc, char** argv) +{ + bool verbose = false; + + Packet::EnablePrinting (); + + CommandLine cmd; + cmd.AddValue ("verbose", "turn on log components", verbose); + cmd.Parse (argc, argv); + + if (verbose) + { + LogComponentEnable ("Ping6Application", LOG_LEVEL_ALL); + LogComponentEnable ("LrWpanMac", LOG_LEVEL_ALL); + LogComponentEnable ("LrWpanPhy", LOG_LEVEL_ALL); + LogComponentEnable ("LrWpanNetDevice", LOG_LEVEL_ALL); + LogComponentEnable ("SixLowPanNetDevice", LOG_LEVEL_ALL); + } + + uint32_t nWsnNodes = 4; + NodeContainer wsnNodes; + wsnNodes.Create (nWsnNodes); + + NodeContainer wiredNodes; + wiredNodes.Create (1); + wiredNodes.Add (wsnNodes.Get (0)); + + MobilityHelper mobility; + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (80), + "DeltaY", DoubleValue (80), + "GridWidth", UintegerValue (10), + "LayoutType", StringValue ("RowFirst")); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wsnNodes); + + LrWpanHelper lrWpanHelper; + // Add and install the LrWpanNetDevice for each node + NetDeviceContainer lrwpanDevices = lrWpanHelper.Install (wsnNodes); + + // Fake PAN association and short address assignment. + // This is needed because the lr-wpan module does not provide (yet) + // a full PAN association procedure. + lrWpanHelper.AssociateToPan (lrwpanDevices, 0); + + InternetStackHelper internetv6; + internetv6.Install (wsnNodes); + internetv6.Install (wiredNodes.Get (0)); + + SixLowPanHelper sixLowPanHelper; + NetDeviceContainer sixLowPanDevices = sixLowPanHelper.Install (lrwpanDevices); + + CsmaHelper csmaHelper; + NetDeviceContainer csmaDevices = csmaHelper.Install (wiredNodes); + + Ipv6AddressHelper ipv6; + ipv6.SetBase (Ipv6Address ("2001:cafe::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer wiredDeviceInterfaces; + wiredDeviceInterfaces = ipv6.Assign (csmaDevices); + wiredDeviceInterfaces.SetForwarding (1, true); + wiredDeviceInterfaces.SetDefaultRouteInAllNodes (1); + + ipv6.SetBase (Ipv6Address ("2001:f00d::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer wsnDeviceInterfaces; + wsnDeviceInterfaces = ipv6.Assign (sixLowPanDevices); + wsnDeviceInterfaces.SetForwarding (0, true); + wsnDeviceInterfaces.SetDefaultRouteInAllNodes (0); + + for (uint32_t i = 0; i < sixLowPanDevices.GetN (); i++) + { + Ptr dev = sixLowPanDevices.Get (i); + dev->SetAttribute ("UseMeshUnder", BooleanValue (true)); + dev->SetAttribute ("MeshUnderRadius", UintegerValue (10)); + } + + uint32_t packetSize = 10; + uint32_t maxPacketCount = 5; + Time interPacketInterval = Seconds (1.); + Ping6Helper ping6; + + ping6.SetLocal (wsnDeviceInterfaces.GetAddress (nWsnNodes - 1, 1)); + ping6.SetRemote (wiredDeviceInterfaces.GetAddress (0, 1)); + + ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + ping6.SetAttribute ("Interval", TimeValue (interPacketInterval)); + ping6.SetAttribute ("PacketSize", UintegerValue (packetSize)); + ApplicationContainer apps = ping6.Install (wsnNodes.Get (nWsnNodes - 1)); + + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + + AsciiTraceHelper ascii; + lrWpanHelper.EnableAsciiAll (ascii.CreateFileStream ("Ping-6LoW-lr-wpan-meshunder-lr-wpan.tr")); + lrWpanHelper.EnablePcapAll (std::string ("Ping-6LoW-lr-wpan-meshunder-lr-wpan"), true); + + csmaHelper.EnableAsciiAll (ascii.CreateFileStream ("Ping-6LoW-lr-wpan-meshunder-csma.tr")); + csmaHelper.EnablePcapAll (std::string ("Ping-6LoW-lr-wpan-meshunder-csma"), true); + + Simulator::Stop (Seconds (10)); + + Simulator::Run (); + Simulator::Destroy (); + +} + diff --git a/src/sixlowpan/examples/example-ping-lr-wpan.cc b/src/sixlowpan/examples/example-ping-lr-wpan.cc index 60b3f87d6..9ee16dccc 100644 --- a/src/sixlowpan/examples/example-ping-lr-wpan.cc +++ b/src/sixlowpan/examples/example-ping-lr-wpan.cc @@ -23,12 +23,9 @@ #include "ns3/core-module.h" #include "ns3/internet-module.h" #include "ns3/internet-apps-module.h" -#include "ns3/ipv6-static-routing-helper.h" #include "ns3/mobility-module.h" #include "ns3/spectrum-module.h" -#include "ns3/propagation-loss-model.h" -#include "ns3/log.h" -#include "ns3/ipv6-routing-table-entry.h" +#include "ns3/propagation-module.h" #include "ns3/sixlowpan-module.h" #include "ns3/lr-wpan-module.h" @@ -38,16 +35,20 @@ using namespace ns3; int main (int argc, char** argv) { + bool verbose = false; + CommandLine cmd; + cmd.AddValue ("verbose", "turn on log components", verbose); cmd.Parse (argc, argv); -#if 0 - LogComponentEnable ("Ping6Application", LOG_LEVEL_ALL); - LogComponentEnable ("LrWpanMac",LOG_LEVEL_ALL); - LogComponentEnable ("LrWpanPhy",LOG_LEVEL_ALL); - LogComponentEnable ("LrWpanNetDevice", LOG_LEVEL_ALL); - LogComponentEnable ("SixLowPanNetDevice", LOG_LEVEL_ALL); -#endif + if (verbose) + { + LogComponentEnable ("Ping6Application", LOG_LEVEL_ALL); + LogComponentEnable ("LrWpanMac", LOG_LEVEL_ALL); + LogComponentEnable ("LrWpanPhy", LOG_LEVEL_ALL); + LogComponentEnable ("LrWpanNetDevice", LOG_LEVEL_ALL); + LogComponentEnable ("SixLowPanNetDevice", LOG_LEVEL_ALL); + } NodeContainer nodes; nodes.Create(2); @@ -69,6 +70,8 @@ int main (int argc, char** argv) NetDeviceContainer lrwpanDevices = lrWpanHelper.Install(nodes); // Fake PAN association and short address assignment. + // This is needed because the lr-wpan module does not provide (yet) + // a full PAN association procedure. lrWpanHelper.AssociateToPan (lrwpanDevices, 0); InternetStackHelper internetv6; diff --git a/src/sixlowpan/examples/example-sixlowpan.cc b/src/sixlowpan/examples/example-sixlowpan.cc index dbcbe5c10..6569a19ab 100644 --- a/src/sixlowpan/examples/example-sixlowpan.cc +++ b/src/sixlowpan/examples/example-sixlowpan.cc @@ -43,9 +43,6 @@ #include "ns3/internet-module.h" #include "ns3/csma-module.h" #include "ns3/internet-apps-module.h" -#include "ns3/ipv6-static-routing-helper.h" - -#include "ns3/ipv6-routing-table-entry.h" #include "ns3/sixlowpan-module.h" using namespace ns3; diff --git a/src/sixlowpan/examples/wscript b/src/sixlowpan/examples/wscript index 4697f9e1e..3a13a607c 100644 --- a/src/sixlowpan/examples/wscript +++ b/src/sixlowpan/examples/wscript @@ -11,3 +11,7 @@ def build(bld): obj = bld.create_ns3_program('example-ping-lr-wpan', ['network', 'sixlowpan', 'internet', 'lr-wpan', 'internet-apps']) obj.source = 'example-ping-lr-wpan.cc' + + obj = bld.create_ns3_program('example-ping-lr-wpan-mesh-under', + ['network', 'sixlowpan', 'internet', 'lr-wpan', 'internet-apps', 'csma']) + obj.source = 'example-ping-lr-wpan-mesh-under.cc' diff --git a/src/sixlowpan/model/sixlowpan-header.cc b/src/sixlowpan/model/sixlowpan-header.cc index 5c6bb6c76..e62c993bb 100644 --- a/src/sixlowpan/model/sixlowpan-header.cc +++ b/src/sixlowpan/model/sixlowpan-header.cc @@ -23,6 +23,9 @@ #include "ns3/log.h" #include "ns3/abort.h" #include "ns3/ipv6-header.h" +#include "ns3/mac64-address.h" +#include "ns3/mac16-address.h" +#include "ns3/ipv6-header.h" #include "sixlowpan-header.h" @@ -128,7 +131,7 @@ void SixLowPanHc1::Print (std::ostream & os) const encoding <<= 1; encoding |= m_hc2HeaderPresent; - os << "encoding " << static_cast (encoding) << ", hopLimit " << static_cast (m_hopLimit); + os << "encoding " << +encoding << ", hopLimit " << +m_hopLimit; } uint32_t SixLowPanHc1::GetSerializedSize () const @@ -545,7 +548,7 @@ NS_OBJECT_ENSURE_REGISTERED (SixLowPanFrag1); SixLowPanFrag1::SixLowPanFrag1 () : m_datagramSize (0), - m_datagramTag (0) + m_datagramTag (0) { } @@ -632,8 +635,8 @@ NS_OBJECT_ENSURE_REGISTERED (SixLowPanFragN); SixLowPanFragN::SixLowPanFragN () : m_datagramSize (0), - m_datagramTag (0), - m_datagramOffset (0) + m_datagramTag (0), + m_datagramOffset (0) { } /* @@ -655,7 +658,7 @@ TypeId SixLowPanFragN::GetInstanceTypeId (void) const void SixLowPanFragN::Print (std::ostream & os) const { - os << "datagram size " << m_datagramSize << " tag " << m_datagramTag << " offset " << static_cast (m_datagramOffset); + os << "datagram size " << m_datagramSize << " tag " << m_datagramTag << " offset " << +m_datagramOffset; } uint32_t SixLowPanFragN::GetSerializedSize () const @@ -815,7 +818,7 @@ TypeId SixLowPanIphc::GetInstanceTypeId (void) const void SixLowPanIphc::Print (std::ostream & os) const { - os << "Compression kind: " << static_cast (m_baseFormat); + os << "Compression kind: " << +m_baseFormat; } uint32_t SixLowPanIphc::GetSerializedSize () const @@ -1508,7 +1511,7 @@ TypeId SixLowPanNhcExtension::GetInstanceTypeId (void) const void SixLowPanNhcExtension::Print (std::ostream & os) const { - os << "Compression kind: " << static_cast (m_nhcExtensionHeader) << " Size: " << GetSerializedSize (); + os << "Compression kind: " << +m_nhcExtensionHeader << " Size: " << GetSerializedSize (); } uint32_t SixLowPanNhcExtension::GetSerializedSize () const @@ -1637,7 +1640,7 @@ TypeId SixLowPanUdpNhcExtension::GetInstanceTypeId (void) const void SixLowPanUdpNhcExtension::Print (std::ostream & os) const { - os << "Compression kind: " << static_cast (m_baseFormat); + os << "Compression kind: " << +m_baseFormat; } uint32_t SixLowPanUdpNhcExtension::GetSerializedSize () const @@ -1805,6 +1808,317 @@ std::ostream & operator << (std::ostream & os, const SixLowPanUdpNhcExtension & return os; } +/* + * SixLowPanBc0 + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanBc0); + +SixLowPanBc0::SixLowPanBc0 () +{ + m_seqNumber = 66; +} + +TypeId SixLowPanBc0::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanBc0") + .SetParent
() + .SetGroupName ("SixLowPan") + .AddConstructor (); + return tid; +} + +TypeId SixLowPanBc0::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanBc0::Print (std::ostream & os) const +{ + os << "Sequence number: " << +m_seqNumber; +} + +uint32_t SixLowPanBc0::GetSerializedSize () const +{ + return 2; +} + +void SixLowPanBc0::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (0x50); + i.WriteU8 (m_seqNumber); + +} + +uint32_t SixLowPanBc0::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + uint8_t dispatch = i.ReadU8 (); + + if (dispatch != 0x50) + { + return 0; + } + + m_seqNumber = i.ReadU8 (); + + return GetSerializedSize (); +} + +void SixLowPanBc0::SetSequenceNumber (uint8_t seqNumber) +{ + m_seqNumber = seqNumber; +} + +uint8_t SixLowPanBc0::GetSequenceNumber (void) const +{ + return m_seqNumber; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanBc0 & h) +{ + h.Print (os); + return os; +} + +/* + * SixLowPanMesh + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanMesh); + +SixLowPanMesh::SixLowPanMesh () +{ + m_hopsLeft = 0; + m_src = Address (); + m_dst = Address (); + m_v = false; + m_f = false; +} + +TypeId SixLowPanMesh::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanMesh") + .SetParent
() + .SetGroupName ("SixLowPan") + .AddConstructor (); + return tid; +} + +TypeId SixLowPanMesh::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanMesh::Print (std::ostream & os) const +{ + os << "Hops left: " << +m_hopsLeft << ", src: "; + if (Mac64Address::IsMatchingType (m_src)) + { + os << Mac64Address::ConvertFrom (m_src); + } + else + { + os << Mac16Address::ConvertFrom (m_src); + } + os << ", dst: "; + if (Mac64Address::IsMatchingType (m_dst)) + { + os << Mac64Address::ConvertFrom (m_dst); + } + else + { + os << Mac16Address::ConvertFrom (m_dst); + } +} + +uint32_t SixLowPanMesh::GetSerializedSize () const +{ + uint32_t serializedSize = 1; + + if (m_hopsLeft >= 0xF) + { + serializedSize++; + } + + if (m_v) + { + serializedSize += 2; + } + else + { + serializedSize += 8; + } + + if (m_f) + { + serializedSize += 2; + } + else + { + serializedSize += 8; + } + + return serializedSize; +} + +void SixLowPanMesh::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + uint8_t dispatch = 0x80; + + if (m_v) + { + dispatch |= 0x20; + } + if (m_f) + { + dispatch |= 0x10; + } + + if (m_hopsLeft < 0xF) + { + dispatch |= m_hopsLeft; + i.WriteU8 (dispatch); + } + else + { + dispatch |= 0xF; + i.WriteU8 (dispatch); + i.WriteU8 (m_hopsLeft); + } + + uint8_t buffer[8]; + + m_src.CopyTo (buffer); + if (m_v) + { + i.Write (buffer, 2); + } + else + { + i.Write (buffer, 8); + } + + m_dst.CopyTo (buffer); + if (m_f) + { + i.Write (buffer, 2); + } + else + { + i.Write (buffer, 8); + } +} + +uint32_t SixLowPanMesh::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + uint8_t temp = i.ReadU8 (); + + if ((temp & 0xC0) != 0x80) + { + return 0; + } + + m_v = temp & 0x20; + m_f = temp & 0x10; + m_hopsLeft = temp & 0xF; + + if (m_hopsLeft == 0xF) + { + m_hopsLeft = i.ReadU8 (); + } + + uint8_t buffer[8]; + uint8_t addrSize; + + if (m_v) + { + addrSize = 2; + } + else + { + addrSize = 8; + } + i.Read (buffer, addrSize); + m_src.CopyFrom (buffer, addrSize); + + if (m_f) + { + addrSize = 2; + } + else + { + addrSize = 8; + } + i.Read (buffer, addrSize); + m_dst.CopyFrom (buffer, addrSize); + + return GetSerializedSize (); +} + +void SixLowPanMesh::SetOriginator (Address originator) +{ + if (Mac64Address::IsMatchingType (originator)) + { + m_v = false; + } + else if (Mac16Address::IsMatchingType (originator)) + { + m_v = true; + } + else + { + NS_ABORT_MSG ("SixLowPanMesh::SetOriginator - incompatible address"); + } + + m_src = originator; +} + +Address SixLowPanMesh::GetOriginator (void) const +{ + return m_src; +} + +void SixLowPanMesh::SetFinalDst (Address finalDst) +{ + if (Mac64Address::IsMatchingType (finalDst)) + { + m_f = false; + } + else if (Mac16Address::IsMatchingType (finalDst)) + { + m_f = true; + } + else + { + NS_ABORT_MSG ("SixLowPanMesh::SetFinalDst - incompatible address"); + } + + m_dst = finalDst; +} + +Address SixLowPanMesh::GetFinalDst (void) const +{ + return m_dst; +} + +void SixLowPanMesh::SetHopsLeft (uint8_t hopsLeft) +{ + m_hopsLeft = hopsLeft; +} + +uint8_t SixLowPanMesh::GetHopsLeft (void) const +{ + return m_hopsLeft; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanMesh & h) +{ + h.Print (os); + return os; +} } diff --git a/src/sixlowpan/model/sixlowpan-header.h b/src/sixlowpan/model/sixlowpan-header.h index 4adfd46a8..78f4023f0 100644 --- a/src/sixlowpan/model/sixlowpan-header.h +++ b/src/sixlowpan/model/sixlowpan-header.h @@ -1236,6 +1236,168 @@ private: */ std::ostream & operator<< (std::ostream & os, SixLowPanUdpNhcExtension const &header); +/** + * \ingroup sixlowpan + * \brief 6LoWPAN BC0 header - see \RFC{4944}. + */ +class SixLowPanBc0 : public Header +{ +public: + SixLowPanBc0 (void); + + /** + * \brief Get the type ID. + * \return The object TypeId. + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return Instance type ID. + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return Size. + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param [in] start Buffer iterator. + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param [in] start Buffer iterator. + * \return Size of the packet. + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Set the "Sequence Number" field. + * \param [in] seqNumber The sequence number value. + */ + void SetSequenceNumber (uint8_t seqNumber); + + /** + * \brief Get the "Sequence Number" field. + * \return The sequence number value. + */ + uint8_t GetSequenceNumber (void) const; + +private: + uint8_t m_seqNumber; //!< Sequence number. +}; + +/** + * \brief Stream insertion operator. + * + * \param [in] os The reference to the output stream. + * \param [in] header The BC0 Extension Header. + * \returns The reference to the output stream. + */ +std::ostream & operator<< (std::ostream & os, SixLowPanBc0 const &header); + +/** + * \ingroup sixlowpan + * \brief 6LoWPAN Mesh header - see \RFC{4944}. + */ +class SixLowPanMesh : public Header +{ +public: + SixLowPanMesh (void); + + /** + * \brief Get the type ID. + * \return The object TypeId. + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return Instance type ID. + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return Size. + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param [in] start Buffer iterator. + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param [in] start Buffer iterator. + * \return Size of the packet. + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Set the "Hops Left" field. + * \param [in] hopsLeft The number of hops left. + */ + void SetHopsLeft (uint8_t hopsLeft); + + /** + * \brief Get the "Hops Left" field. + * \return The number of hops left. + */ + uint8_t GetHopsLeft (void) const; + + /** + * \brief Set the "Originator" address. + * \param [in] originator The Originator address (Mac64Address or Mac16Address). + */ + void SetOriginator (Address originator); + + /** + * \brief Get the "Originator" address. + * \return The Originator address (Mac64Address or Mac16Address). + */ + Address GetOriginator (void) const; + + /** + * \brief Set the "Final Destination" address. + * \param [in] finalDst The Final Destination address (Mac64Address or Mac16Address). + */ + void SetFinalDst (Address finalDst); + + /** + * \brief Get the "Final Destination" address. + * \return The Final Destination address (Mac64Address or Mac16Address). + */ + Address GetFinalDst (void) const; + +private: + uint8_t m_hopsLeft; //!< Hops left. + bool m_v; //!< True if Originator address is 16 bit + bool m_f; //!< True if Destination address is 16 bit + Address m_src; //!< Originator (source) address. + Address m_dst; //!< Destination (final) address. +}; + +/** + * \brief Stream insertion operator. + * + * \param [in] os The reference to the output stream. + * \param [in] header The Mesh Extension Header. + * \returns The reference to the output stream. + */ +std::ostream & operator<< (std::ostream & os, SixLowPanMesh const &header); + } #endif /* SIXLOWPANHEADER_H_ */ diff --git a/src/sixlowpan/model/sixlowpan-net-device.cc b/src/sixlowpan/model/sixlowpan-net-device.cc index 4ef8bf282..aff27bba3 100644 --- a/src/sixlowpan/model/sixlowpan-net-device.cc +++ b/src/sixlowpan/model/sixlowpan-net-device.cc @@ -19,6 +19,8 @@ * Michele Muccio */ +#include + #include "ns3/node.h" #include "ns3/channel.h" #include "ns3/packet.h" @@ -33,7 +35,8 @@ #include "ns3/ipv6-extension-header.h" #include "ns3/udp-header.h" #include "ns3/udp-l4-protocol.h" -#include "ns3/random-variable-stream.h" +#include "ns3/string.h" +#include "ns3/pointer.h" #include "sixlowpan-net-device.h" #include "sixlowpan-header.h" @@ -82,6 +85,26 @@ TypeId SixLowPanNetDevice::GetTypeId (void) UintegerValue (0xFFFF), MakeUintegerAccessor (&SixLowPanNetDevice::m_etherType), MakeUintegerChecker ()) + .AddAttribute ("UseMeshUnder", + "Use a mesh-under routing protocol.", + BooleanValue (false), + MakeBooleanAccessor (&SixLowPanNetDevice::m_meshUnder), + MakeBooleanChecker ()) + .AddAttribute ("MeshUnderRadius", + "Hops Left to use in mesh-under.", + UintegerValue (10), + MakeUintegerAccessor (&SixLowPanNetDevice::m_meshUnderHopsLeft), + MakeUintegerChecker ()) + .AddAttribute ("MeshCacheLength", + "Length of the cache for each source.", + UintegerValue (10), + MakeUintegerAccessor (&SixLowPanNetDevice::m_meshCacheLength), + MakeUintegerChecker ()) + .AddAttribute ("MeshUnderJitter", + "The jitter in ms a node uses to forward mesh-under packets - used to prevent collisions", + StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=10.0]"), + MakePointerAccessor (&SixLowPanNetDevice::m_meshUnderJitter), + MakePointerChecker ()) .AddTraceSource ("Tx", "Send - packet (including 6LoWPAN header), " "SixLoWPanNetDevice Ptr, interface index.", @@ -103,12 +126,13 @@ TypeId SixLowPanNetDevice::GetTypeId (void) SixLowPanNetDevice::SixLowPanNetDevice () : m_node (0), - m_netDevice (0), - m_ifIndex (0) + m_netDevice (0), + m_ifIndex (0) { NS_LOG_FUNCTION (this); m_netDevice = 0; m_rng = CreateObject (); + m_bc0Serial = 0; } Ptr SixLowPanNetDevice::GetNetDevice () const @@ -138,7 +162,8 @@ int64_t SixLowPanNetDevice::AssignStreams (int64_t stream) { NS_LOG_FUNCTION (this << stream); m_rng->SetStream (stream); - return 1; + m_meshUnderJitter->SetStream (stream + 1); + return 2; } void SixLowPanNetDevice::DoDispose () @@ -188,14 +213,102 @@ void SixLowPanNetDevice::ReceiveFromDevice (Ptr incomingPort, NS_LOG_DEBUG ( "Packet length: " << copyPkt->GetSize () ); NS_LOG_DEBUG ( "Dispatches: " << int(dispatchRawVal) << " - " << int(dispatchVal) ); + SixLowPanMesh meshHdr; + SixLowPanBc0 bc0Hdr; + bool hasMesh = false; + bool hasBc0 = false; + + if ( dispatchVal == SixLowPanDispatch::LOWPAN_MESH ) + { + hasMesh = true; + copyPkt->RemoveHeader (meshHdr); + copyPkt->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetDispatchType (dispatchRawVal); + } + if ( dispatchVal == SixLowPanDispatch::LOWPAN_BC0 ) + { + hasBc0 = true; + copyPkt->RemoveHeader (bc0Hdr); + copyPkt->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetDispatchType (dispatchRawVal); + } + + if (hasMesh) + { + if (!hasBc0) + { + NS_LOG_LOGIC ("Dropped packet - we only support mesh if it is paired with a BC0"); + m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); + return; + } + + if (find (m_seenPkts[meshHdr.GetOriginator ()].begin (), + m_seenPkts[meshHdr.GetOriginator ()].end (), + bc0Hdr.GetSequenceNumber ()) != m_seenPkts[meshHdr.GetOriginator ()].end ()) + { + NS_LOG_LOGIC ("We have already seen this, no further processing."); + return; + } + + m_seenPkts[meshHdr.GetOriginator ()].push_back (bc0Hdr.GetSequenceNumber ()); + if (m_seenPkts[meshHdr.GetOriginator ()].size () > m_meshCacheLength) + { + m_seenPkts[meshHdr.GetOriginator ()].pop_front (); + } + + NS_ABORT_MSG_IF (!Mac16Address::IsMatchingType (meshHdr.GetFinalDst ()), "SixLowPan mesh-under flooding can not currently handle extended address final destinations: " << meshHdr.GetFinalDst ()); + NS_ABORT_MSG_IF (!Mac48Address::IsMatchingType (m_netDevice->GetAddress ()), "SixLowPan mesh-under flooding can not currently handle devices using extended addresses: " << m_netDevice->GetAddress ()); + + Mac16Address finalDst = Mac16Address::ConvertFrom (meshHdr.GetFinalDst ()); + + // See if the packet is for others than me. In case forward it. + if (meshHdr.GetFinalDst () != Get16MacFrom48Mac (m_netDevice->GetAddress ()) + || finalDst.IsBroadcast () + || finalDst.IsMulticast () + ) + { + uint8_t hopsLeft = meshHdr.GetHopsLeft (); + + if (hopsLeft == 0) + { + NS_LOG_LOGIC ("Not forwarding packet -- hop limit reached"); + } + else if (meshHdr.GetOriginator () == Get16MacFrom48Mac (m_netDevice->GetAddress ())) + { + NS_LOG_LOGIC ("Not forwarding packet -- I am the originator"); + } + else + { + meshHdr.SetHopsLeft (hopsLeft - 1); + Ptr sendPkt = copyPkt->Copy (); + sendPkt->AddHeader (bc0Hdr); + sendPkt->AddHeader (meshHdr); + Simulator::Schedule (Time (MilliSeconds (m_meshUnderJitter->GetValue ())), &NetDevice::Send, m_netDevice, sendPkt, m_netDevice->GetBroadcast (), protocol); + } + + if (!finalDst.IsBroadcast () && !finalDst.IsMulticast ()) + { + return; + } + } + } + + Address realDst = dst; + Address realSrc = src; + if (hasMesh) + { + realSrc = meshHdr.GetOriginator (); + realDst = meshHdr.GetFinalDst (); + } + if ( dispatchVal == SixLowPanDispatch::LOWPAN_FRAG1 ) { - isPktDecompressed = ProcessFragment (copyPkt, src, dst, true); + isPktDecompressed = ProcessFragment (copyPkt, realSrc, realDst, true); fragmented = true; } else if ( dispatchVal == SixLowPanDispatch::LOWPAN_FRAGN ) { - isPktDecompressed = ProcessFragment (copyPkt, src, dst, false); + isPktDecompressed = ProcessFragment (copyPkt, realSrc, realDst, false); fragmented = true; } if ( fragmented ) @@ -213,28 +326,20 @@ void SixLowPanNetDevice::ReceiveFromDevice (Ptr incomingPort, switch ( dispatchVal ) { - case SixLowPanDispatch::LOWPAN_MESH: - NS_LOG_DEBUG ("Unsupported 6LoWPAN encoding: MESH, dropping."); - m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); - break; - case SixLowPanDispatch::LOWPAN_BC0: - NS_LOG_DEBUG ("Unsupported 6LoWPAN encoding: BC0, dropping."); - m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); - break; case SixLowPanDispatch::LOWPAN_IPv6: NS_LOG_DEBUG ( "Packet without compression. Length: " << copyPkt->GetSize () ); { SixLowPanIpv6 uncompressedHdr; - copyPkt->RemoveHeader(uncompressedHdr); + copyPkt->RemoveHeader (uncompressedHdr); isPktDecompressed = true; } break; case SixLowPanDispatch::LOWPAN_HC1: - DecompressLowPanHc1 (copyPkt, src, dst); + DecompressLowPanHc1 (copyPkt, realSrc, realDst); isPktDecompressed = true; break; case SixLowPanDispatch::LOWPAN_IPHC: - DecompressLowPanIphc (copyPkt, src, dst); + DecompressLowPanIphc (copyPkt, realSrc, realDst); isPktDecompressed = true; break; default: @@ -253,10 +358,10 @@ void SixLowPanNetDevice::ReceiveFromDevice (Ptr incomingPort, if (!m_promiscRxCallback.IsNull ()) { - m_promiscRxCallback (this, copyPkt, Ipv6L3Protocol::PROT_NUMBER, src, dst, packetType); + m_promiscRxCallback (this, copyPkt, Ipv6L3Protocol::PROT_NUMBER, realSrc, realDst, packetType); } - m_rxCallback (this, copyPkt, Ipv6L3Protocol::PROT_NUMBER, src); + m_rxCallback (this, copyPkt, Ipv6L3Protocol::PROT_NUMBER, realSrc); return; } @@ -429,6 +534,10 @@ bool SixLowPanNetDevice::DoSend (Ptr packet, uint32_t origPacketSize = packet->GetSize (); bool ret = false; + Address destination = dest; + + bool useMesh = m_meshUnder; + if (m_forceEtherType) { protocolNumber = m_etherType; @@ -437,23 +546,59 @@ bool SixLowPanNetDevice::DoSend (Ptr packet, if (m_useIphc) { NS_LOG_LOGIC ("Compressing packet using IPHC"); - origHdrSize += CompressLowPanIphc (packet, m_netDevice->GetAddress (), dest); + origHdrSize += CompressLowPanIphc (packet, m_netDevice->GetAddress (), destination); } else { NS_LOG_LOGIC ("Compressing packet using HC1"); - origHdrSize += CompressLowPanHc1 (packet, m_netDevice->GetAddress (), dest); + origHdrSize += CompressLowPanHc1 (packet, m_netDevice->GetAddress (), destination); } - if (packet->GetSize () < m_compressionThreshold) + uint16_t pktSize = packet->GetSize (); + + SixLowPanMesh meshHdr; + SixLowPanBc0 bc0Hdr; + if (useMesh) + { + Address source = src; + if (!doSendFrom) + { + source = m_netDevice->GetAddress (); + } + + if (Mac48Address::IsMatchingType (source)) + { + // We got a Mac48 pseudo-MAC. We need its original Mac16 here. + source = Get16MacFrom48Mac (source); + } + if (Mac48Address::IsMatchingType (destination)) + { + // We got a Mac48 pseudo-MAC. We need its original Mac16 here. + destination = Get16MacFrom48Mac (destination); + } + + meshHdr.SetOriginator (source); + meshHdr.SetFinalDst (destination); + meshHdr.SetHopsLeft (m_meshUnderHopsLeft); + destination = m_netDevice->GetBroadcast (); + pktSize += meshHdr.GetSerializedSize () + bc0Hdr.GetSerializedSize (); + } + + if (pktSize < m_compressionThreshold) { NS_LOG_LOGIC ("Compressed packet too short, using uncompressed one"); packet = origPacket; SixLowPanIpv6 ipv6UncompressedHdr; packet->AddHeader (ipv6UncompressedHdr); + pktSize = packet->GetSize (); + if (useMesh) + { + pktSize += meshHdr.GetSerializedSize () + bc0Hdr.GetSerializedSize (); + } } - if ( packet->GetSize () > m_netDevice->GetMtu () ) + + if (pktSize > m_netDevice->GetMtu ()) { NS_LOG_LOGIC ("Fragmentation: Packet size " << packet->GetSize () << " - Mtu " << m_netDevice->GetMtu () ); // fragment @@ -465,13 +610,20 @@ bool SixLowPanNetDevice::DoSend (Ptr packet, { NS_LOG_DEBUG ( "SixLowPanNetDevice::Send (Fragment) " << **it ); m_txTrace (*it, m_node->GetObject (), GetIfIndex ()); + + if (useMesh) + { + bc0Hdr.SetSequenceNumber (m_bc0Serial++); + (*it)->AddHeader (bc0Hdr); + (*it)->AddHeader (meshHdr); + } if (doSendFrom) { - success &= m_netDevice->SendFrom (*it, src, dest, protocolNumber); + success &= m_netDevice->SendFrom (*it, src, destination, protocolNumber); } else { - success &= m_netDevice->Send (*it, dest, protocolNumber); + success &= m_netDevice->Send (*it, destination, protocolNumber); } } ret = success; @@ -479,15 +631,23 @@ bool SixLowPanNetDevice::DoSend (Ptr packet, else { m_txTrace (packet, m_node->GetObject (), GetIfIndex ()); + + if (useMesh) + { + bc0Hdr.SetSequenceNumber (m_bc0Serial++); + packet->AddHeader (bc0Hdr); + packet->AddHeader (meshHdr); + } + if (doSendFrom) { NS_LOG_DEBUG ( "SixLowPanNetDevice::SendFrom " << m_node->GetId () << " " << *packet ); - ret = m_netDevice->SendFrom (packet, src, dest, protocolNumber); + ret = m_netDevice->SendFrom (packet, src, destination, protocolNumber); } else { NS_LOG_DEBUG ( "SixLowPanNetDevice::Send " << m_node->GetId () << " " << *packet ); - ret = m_netDevice->Send (packet, dest, protocolNumber); + ret = m_netDevice->Send (packet, destination, protocolNumber); } } @@ -1405,7 +1565,7 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr packet, Address const &src, uint32_t blobSize; uint8_t blobData[260]; - blobSize = encoding.CopyBlob (blobData + 2, 260-2); + blobSize = encoding.CopyBlob (blobData + 2, 260 - 2); uint8_t paddingSize = 0; uint8_t actualEncodedHeaderType = encoding.GetEid (); @@ -1836,9 +1996,9 @@ bool SixLowPanNetDevice::ProcessFragment (Ptr& packet, Address const &sr case SixLowPanDispatch::LOWPAN_IPv6: { SixLowPanIpv6 uncompressedHdr; - p->RemoveHeader(uncompressedHdr); + p->RemoveHeader (uncompressedHdr); } - break; + break; case SixLowPanDispatch::LOWPAN_HC1: DecompressLowPanHc1 (p, src, dst); break; @@ -2053,7 +2213,7 @@ std::list< Ptr > SixLowPanNetDevice::Fragments::GetFraments () const { std::list< Ptr > fragments; std::list, uint16_t> >::const_iterator iter; - for ( iter = m_fragments.begin (); iter != m_fragments.end (); iter ++) + for ( iter = m_fragments.begin (); iter != m_fragments.end (); iter++) { fragments.push_back (iter->first); } @@ -2078,6 +2238,19 @@ void SixLowPanNetDevice::HandleFragmentsTimeout (FragmentKey key, uint32_t iif) m_fragmentsTimers.erase (key); } +Address SixLowPanNetDevice::Get16MacFrom48Mac (Address addr) +{ + NS_ASSERT_MSG (Mac48Address::IsMatchingType (addr), "Need a Mac48Address" << addr); + + uint8_t buf[6]; + addr.CopyTo (buf); + + Mac16Address shortAddr; + shortAddr.CopyFrom (buf + 4); + + return shortAddr; +} + } // namespace ns3 diff --git a/src/sixlowpan/model/sixlowpan-net-device.h b/src/sixlowpan/model/sixlowpan-net-device.h index e60545fd6..3a40f2c92 100644 --- a/src/sixlowpan/model/sixlowpan-net-device.h +++ b/src/sixlowpan/model/sixlowpan-net-device.h @@ -28,6 +28,7 @@ #include "ns3/traced-callback.h" #include "ns3/nstime.h" #include "ns3/net-device.h" +#include "ns3/random-variable-stream.h" namespace ns3 { @@ -153,9 +154,9 @@ public: * is deprecated and will be changed to \c Ptr * in a future release. */ - typedef void (* RxTxTracedCallback) - (Ptr packet, Ptr sixNetDevice, - uint32_t ifindex); + typedef void (* RxTxTracedCallback)(Ptr packet, + Ptr sixNetDevice, + uint32_t ifindex); /** * TracedCallback signature for @@ -168,11 +169,11 @@ public: * is deprecated and will be changed to \c Ptr * in a future release. */ - typedef void (* DropTracedCallback) - (DropReason reason, Ptr packet, - Ptr sixNetDevice, - uint32_t ifindex); - + typedef void (* DropTracedCallback)(DropReason reason, + Ptr packet, + Ptr sixNetDevice, + uint32_t ifindex); + protected: virtual void DoDispose (void); @@ -457,6 +458,13 @@ private: */ void DropOldestFragmentSet (); + /** + * Get a Mac16 from its Mac48 pseudo-MAC + * \param addr the PseudoMac adddress + * \return the Mac16Address + */ + Address Get16MacFrom48Mac (Address addr); + /** * Container for fragment key -> fragments. */ @@ -486,6 +494,13 @@ private: bool m_useIphc; //!< Use IPHC or HC1. + bool m_meshUnder; //!< Use a mesh-under routing. + uint8_t m_bc0Serial; //!< Serial number used in BC0 header. + uint8_t m_meshUnderHopsLeft; //!< Start value for mesh-under hops left. + uint16_t m_meshCacheLength; //!< length of the cache for each source. + Ptr m_meshUnderJitter; //!< Random variable for the mesh-under packet retransmission. + std::map
> m_seenPkts; //!< Seen packets, memorized by OriginatorAdddress, SequenceNumber. + Ptr m_node; //!< Smart pointer to the Node. Ptr m_netDevice; //!< Smart pointer to the underlying NetDevice. uint32_t m_ifIndex; //!< Interface index.