A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
dhcp6-duid.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 NITK Surathkal
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Kavya Bhat <kavyabhat@gmail.com>
7 *
8 */
9
10#include "dhcp6-duid.h"
11
12#include "ns3/address.h"
13#include "ns3/assert.h"
14#include "ns3/ipv6-l3-protocol.h"
15#include "ns3/log.h"
16#include "ns3/loopback-net-device.h"
17#include "ns3/ptr.h"
18#include "ns3/simulator.h"
19
20#include <algorithm>
21#include <iomanip>
22
23namespace ns3
24{
25
26NS_LOG_COMPONENT_DEFINE("Dhcp6Duid");
27
28bool
30{
31 return m_blob.empty();
32}
33
34uint8_t
36{
37 return m_blob.size();
38}
39
40std::vector<uint8_t>
42{
43 return m_blob;
44}
45
48{
49 return m_duidType;
50}
51
52void
54{
55 NS_LOG_FUNCTION(this << node);
56
58 Address duidAddress = FindSuitableNetDeviceAddress(node);
59
60 uint8_t idLen = duidAddress.GetLength();
61 NS_ASSERT_MSG(idLen == 6 || idLen == 8, "Duid: Invalid identifier length.");
62
63 m_blob.resize(idLen + Offset::LL);
64
65 // Ethernet (48 bit) - HardwareType 1
66 // EUI-64 (64 bit) - HardwareType 27
67 m_blob[0] = 0;
68 m_blob[1] = idLen == 6 ? 1 : 27;
69
70 duidAddress.CopyTo(&m_blob[Offset::LL]);
71}
72
73void
75{
76 NS_LOG_FUNCTION(this << node);
77
79 Address duidAddress = FindSuitableNetDeviceAddress(node);
80
81 uint8_t idLen = duidAddress.GetLength();
82 NS_ASSERT_MSG(idLen == 6 || idLen == 8, "Duid: Invalid identifier length.");
83
84 m_blob.resize(idLen + Offset::LLT);
85
86 // Ethernet (48 bit) - HardwareType 1
87 // EUI-64 (64 bit) - HardwareType 27
88 m_blob[0] = 0;
89 m_blob[1] = idLen == 6 ? 1 : 27;
90
91 // This should be (according to RFC 8415)
92 // seconds since midnight (UTC), January 1, 2000, modulo 2 ^ 32
93 // We do not have an (easy) way to measure the difference.
94
95 uint32_t time = std::floor(std::fmod(Simulator::Now().GetSeconds(), std::pow(2, 32)));
96 HtoN(time, m_blob.begin() + Offset::LL);
97
98 duidAddress.CopyTo(&m_blob[Offset::LLT]);
99}
100
101void
102Duid::InitializeEN(uint32_t enNumber, const std::vector<uint8_t>& identifier)
103{
104 NS_LOG_FUNCTION(this << enNumber << identifier);
105
107
108 // The DUID is going to be embedded in an option, which
109 // have a DUID length expressed 16-bit
110 // this leaves 65535 - 2 - 4 bytes for the identifier.
111 NS_ASSERT_MSG(identifier.size() < 65535 - 6,
112 "Duid: Invalid identifier length (max length is 65529 bytes).");
113
114 m_blob.resize(identifier.size() + Offset::EN);
115
116 HtoN(enNumber, m_blob.begin());
117
118 std::move(identifier.cbegin(), identifier.cend(), &m_blob[Offset::EN]);
119}
120
121void
122Duid::InitializeUUID(const std::vector<uint8_t>& uuid)
123{
124 NS_LOG_FUNCTION(this << uuid);
125
127
128 NS_ASSERT_MSG(uuid.size() == 16, "Duid: Invalid identifier length (UUID must be 128 bits).");
129
130 m_blob.resize(uuid.size());
131
132 std::move(uuid.cbegin(), uuid.cend(), m_blob.begin());
133}
134
135void
136Duid::Initialize(Type duidType, Ptr<Node> node, uint32_t enIdentifierLength)
137{
138 NS_LOG_FUNCTION(this << std::to_underlying(duidType) << node << enIdentifierLength);
139
140 switch (duidType)
141 {
142 case Duid::Type::LLT: {
143 InitializeLLT(node);
144 break;
145 }
146 case Duid::Type::EN: {
147 // We use enterprise-number 0xf00dcafe (totally arbitrary)
148 // The list of numbers is at
149 // https://www.iana.org/assignments/enterprise-numbers/
150 std::vector<uint8_t> identifier(enIdentifierLength);
151 HtoN(node->GetId(), identifier.begin());
152 InitializeEN(0xf00dcafe, identifier);
153 break;
154 }
155 case Duid::Type::LL: {
156 InitializeLL(node);
157 break;
158 }
159 case Duid::Type::UUID: {
160 std::vector<uint8_t> identifier(16);
161 HtoN(node->GetId(), identifier.begin());
162 InitializeUUID(identifier);
163 break;
164 }
165 }
166}
167
170{
171 NS_LOG_FUNCTION(this << node);
172
173 Ptr<Ipv6L3Protocol> ipv6 = node->GetObject<Ipv6L3Protocol>();
174 NS_ASSERT_MSG(ipv6, "DHCPv6: No IPv6 stack found.");
175 uint32_t nInterfaces = ipv6->GetNInterfaces();
176
177 uint32_t maxAddressLength = 0;
178 Address duidAddress;
179
180 // We select NetDevices with the longest MAC address length,
181 // and among them, the one with the smallest index.
182 for (uint32_t i = 0; i < nInterfaces; i++)
183 {
184 Ptr<NetDevice> device = ipv6->GetNetDevice(i);
185
186 // Discard the loopback device.
188 {
189 continue;
190 }
191
192 // Check if the NetDevice is up.
193 if (device->IsLinkUp())
194 {
195 NS_LOG_DEBUG("Interface " << device->GetIfIndex() << " up on node " << node->GetId());
196 Address address = device->GetAddress();
197 if (address.GetLength() > maxAddressLength)
198 {
199 maxAddressLength = address.GetLength();
200 duidAddress = address;
201 }
202 }
203 }
204
205 NS_ASSERT_MSG(!duidAddress.IsInvalid(), "Duid: No suitable NetDevice found for DUID.");
206
207 NS_LOG_DEBUG("DUID of node " << node->GetId() << " is " << duidAddress);
208
209 return duidAddress;
210}
211
214{
215 // The DUID type is 2 bytes.
216 return 2 + m_blob.size();
217}
218
219void
221{
222 Buffer::Iterator i = start;
223 i.WriteHtonU16(static_cast<std::underlying_type_t<Duid::Type>>(m_duidType));
224
225 i.Write(&m_blob[0], m_blob.size());
226}
227
230{
231 Buffer::Iterator i = start;
232
233 m_duidType = static_cast<Duid::Type>(i.ReadNtohU16());
234 len -= 2;
235
236 m_blob.resize(len);
237 i.Read(&m_blob[0], m_blob.size());
238
239 return GetSerializedSize();
240}
241
242void
243Duid::HtoN(uint32_t source, std::vector<uint8_t>::iterator dest)
244{
245 dest[0] = (source >> 24);
246 dest[1] = (source >> 16) & 0xFF;
247 dest[2] = (source >> 8) & 0xFF;
248 dest[3] = source & 0xFF;
249}
250
251size_t
252Duid::DuidHash::operator()(const Duid& x) const noexcept
253{
254 uint8_t duidLen = x.GetLength();
255 std::vector<uint8_t> buffer = x.GetIdentifier();
256
257 std::string s(buffer.begin(), buffer.begin() + duidLen);
258 return std::hash<std::string>{}(s);
259}
260
261// Comparison operators are defined because gcc-13.3 raises an error in optimized builds.
262// Other than that, the comparisons are semantically identical to the default ones.
263bool
264Duid::operator==(const Duid& other) const
265{
266 return std::is_eq(*this <=> other);
267};
268
269std::strong_ordering
270operator<=>(const Duid& a, const Duid& b)
271{
272 if (a.m_duidType == b.m_duidType)
273 {
274 return a.m_blob <=> b.m_blob;
275 }
276
277 return a.m_duidType <=> b.m_duidType;
278}
279
280std::ostream&
281operator<<(std::ostream& os, const Duid& duid)
282{
283 auto fold16 = [](std::vector<uint8_t>::const_iterator a) -> uint16_t {
284 auto f = static_cast<uint16_t>(a[0]) << 8;
285 f += static_cast<uint16_t>(a[1]);
286 return f;
287 };
288
289 auto fold32 = [](std::vector<uint8_t>::const_iterator a) -> uint32_t {
290 auto f = static_cast<uint32_t>(a[0]) << 24;
291 f += static_cast<uint32_t>(a[1]) << 16;
292 f += static_cast<uint32_t>(a[2]) << 8;
293 f += static_cast<uint32_t>(a[3]);
294 return f;
295 };
296
297 auto format = [](std::vector<uint8_t>::const_iterator start,
298 std::vector<uint8_t>::const_iterator end) -> std::string {
299 std::ostringstream str;
300 str << std::hex;
301 std::for_each(start, end, [&](int i) { str << std::setfill('0') << std::setw(2) << i; });
302 return str.str();
303 };
304
305 switch (duid.m_duidType)
306 {
307 case Duid::Type::LLT: {
308 os << "DUID-LLT";
309 os << " HWtype: " << fold16(duid.m_blob.cbegin());
310 os << " Time: " << fold32(duid.m_blob.cbegin() + 2);
311 auto identifierStart = duid.m_blob.cbegin() + Duid::Offset::LLT;
312 os << " Identifier: 0x" << format(identifierStart, duid.m_blob.cend());
313 break;
314 }
315 case Duid::Type::EN: {
316 os << "DUID-EN";
317 os << " EnNumber: 0x"
318 << format(duid.m_blob.cbegin(), duid.m_blob.cbegin() + Duid::Offset::EN);
319 auto identifierStart = duid.m_blob.cbegin() + Duid::Offset::EN;
320 os << " Identifier: 0x" << format(identifierStart, duid.m_blob.cend());
321 break;
322 }
323 case Duid::Type::LL: {
324 os << "DUID-LL";
325 os << " HWtype: " << fold16(duid.m_blob.cbegin());
326 auto identifierStart = duid.m_blob.cbegin() + Duid::Offset::LL;
327 os << " Identifier: 0x" << format(identifierStart, duid.m_blob.cend());
328 break;
329 }
330 case Duid::Type::UUID: {
331 os << "DUID-UUID";
332 auto identifierStart = duid.m_blob.cbegin();
333 os << " UUID: 0x" << format(identifierStart, duid.m_blob.cend());
334 break;
335 }
336 }
337 return os;
338}
339
340} // namespace ns3
cairo_uint64_t x
_cairo_uint_96by64_32x64_divrem:
a polymophic address class
Definition address.h:114
bool IsInvalid() const
Definition address.cc:55
uint8_t GetLength() const
Get the length of the underlying address.
Definition address.cc:62
uint32_t CopyTo(uint8_t buffer[MAX_SIZE]) const
Copy the address bytes into a buffer.
Definition address.cc:70
iterator in a Buffer instance
Definition buffer.h:89
void Write(const uint8_t *buffer, uint32_t size)
Definition buffer.cc:937
void Read(uint8_t *buffer, uint32_t size)
Definition buffer.cc:1114
void WriteHtonU16(uint16_t data)
Definition buffer.h:916
uint16_t ReadNtohU16()
Definition buffer.h:955
size_t operator()(const Duid &x) const noexcept
Returns the hash of a DUID.
Implements the unique identifier for DHCPv6.
Definition dhcp6-duid.h:27
uint32_t Deserialize(Buffer::Iterator start, uint32_t len)
Deserialize the DUID.
uint8_t GetLength() const
Get the length of the DUID.
Definition dhcp6-duid.cc:35
void InitializeLL(Ptr< Node > node)
Initialize the DUID-LL for a client or server.
Definition dhcp6-duid.cc:53
Type m_duidType
DUID type.
Definition dhcp6-duid.h:219
bool operator==(const Duid &other) const
Comparison operator.
void Serialize(Buffer::Iterator start) const
Serialize the DUID.
void HtoN(uint32_t source, std::vector< uint8_t >::iterator dest)
Utility function to convert a 32-bit number to an array with its bytes in network order.
bool IsInvalid() const
Check if the DUID is invalid.
Definition dhcp6-duid.cc:29
void InitializeEN(uint32_t enNumber, const std::vector< uint8_t > &identifier)
Initialize the DUID-EN for a client or server.
void InitializeUUID(const std::vector< uint8_t > &uuid)
Initialize the DUID-EN for a client or server.
void Initialize(Type duidType, Ptr< Node > node, uint32_t enIdentifierLength)
Initialize a DUID.
std::vector< uint8_t > GetIdentifier() const
Return the identifier of the node.
Definition dhcp6-duid.cc:41
uint32_t GetSerializedSize() const
Get the DUID serialized size.
Type GetDuidType() const
Get the DUID type.
Definition dhcp6-duid.cc:47
std::vector< uint8_t > m_blob
DUID data, content depending on the DUID type.
Definition dhcp6-duid.h:221
void InitializeLLT(Ptr< Node > node)
Initialize the DUID-LLT for a client or server.
Definition dhcp6-duid.cc:74
Address FindSuitableNetDeviceAddress(Ptr< Node > node)
Find a suitable NetDevice address to create a DUID-LL or DUID-LLT.
Type
DUID type.
Definition dhcp6-duid.h:31
IPv6 layer implementation.
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
std::strong_ordering operator<=>(const Duid &a, const Duid &b)