A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
dhcp6-server.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-server.h"
11
12#include "dhcp6-duid.h"
13
14#include "ns3/address-utils.h"
15#include "ns3/enum.h"
16#include "ns3/icmpv6-l4-protocol.h"
17#include "ns3/integer.h"
18#include "ns3/ipv6-interface.h"
19#include "ns3/ipv6-l3-protocol.h"
20#include "ns3/ipv6-packet-info-tag.h"
21#include "ns3/ipv6.h"
22#include "ns3/log.h"
23#include "ns3/loopback-net-device.h"
24#include "ns3/simulator.h"
25#include "ns3/socket.h"
26
27#include <algorithm>
28
29namespace ns3
30{
31
32NS_LOG_COMPONENT_DEFINE("Dhcp6Server");
33
36{
37 static TypeId tid =
38 TypeId("ns3::Dhcp6Server")
40 .AddConstructor<Dhcp6Server>()
41 .SetGroupName("InternetApps")
42 .AddAttribute("RenewTime",
43 "Time after which client should renew. 1000 seconds by default in Linux. "
44 "This is equivalent to REN_MAX_RT (RFC 8415, Section 7.6).",
45 TimeValue(Seconds(1000)),
48 .AddAttribute("RebindTime",
49 "Time after which client should rebind. "
50 "2000 seconds by default in Linux. "
51 "This is equivalent to REB_MAX_RT (RFC 8415, Section 7.6).",
52 TimeValue(Seconds(2000)),
55 .AddAttribute("PreferredLifetime",
56 "The preferred lifetime of the leased address. "
57 "3000 seconds by default in Linux.",
58 TimeValue(Seconds(3000)),
61 .AddAttribute("ValidLifetime",
62 "Time after which client should release the address. "
63 "4000 seconds by default in Linux.",
64 TimeValue(Seconds(4000)),
67 .AddAttribute("DuidType",
68 "Configure the type of DUID used by the server.",
72 "LLT",
74 "EN",
76 "LL",
78 "UUID"))
79 .AddAttribute("DuidEnIdentifierLength",
80 "Length of the identifier of the DUID-EN.",
81 IntegerValue(8),
84
85 return tid;
86}
87
92
93void
95{
96 NS_LOG_FUNCTION(this);
97 if (m_recvSocket)
98 {
99 m_recvSocket->Close();
100 m_recvSocket = nullptr;
101 }
102
103 for (auto& itr : m_subnets)
104 {
105 itr.m_leasedAddresses.clear();
106 itr.m_expiredAddresses.clear();
107 itr.m_declinedAddresses.clear();
108 }
109 m_subnets.clear();
110 m_leaseCleanupEvent.Cancel();
111
112 for (auto& itr : m_sendSockets)
113 {
114 // Close sockets.
115 if (!itr.second)
116 {
117 continue;
118 }
119 itr.second->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
121 itr.second->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
122 itr.second->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
123 itr.second->Close();
124 }
125 m_sendSockets.clear();
126 m_iaBindings.clear();
128}
129
130void
132{
133 Duid clientDuid = header.GetClientIdentifier().GetDuid();
134 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
135
136 // Add each IA in the header to the IA bindings.
137 if (headerOptions.find(Options::OptionType::OPTION_IA_NA) != headerOptions.end())
138 {
139 std::vector<IaOptions> iaOpt = header.GetIanaOptions();
140 for (const auto& itr : iaOpt)
141 {
142 uint32_t iaid = itr.GetIaid();
143 m_iaBindings.insert(
144 {clientDuid, std::make_pair(Options::OptionType::OPTION_IA_NA, iaid)});
145 NS_LOG_DEBUG("DHCPv6 server: Client registering IAID " << iaid);
146 }
147 }
148}
149
150void
152{
153 NS_LOG_FUNCTION(this << iDev << header << client);
154
155 // Options included according to RFC 8415 Section 18.3.9
156
157 Ptr<Packet> packet = Create<Packet>();
158 Dhcp6Header advertiseHeader;
159 advertiseHeader.ResetOptions();
161 advertiseHeader.SetTransactId(header.GetTransactId());
162
163 // Add Client Identifier Option, copied from the received header.
164 Duid clientDuid = header.GetClientIdentifier().GetDuid();
165 advertiseHeader.AddClientIdentifier(clientDuid);
166
167 // Add Server Identifier Option.
168 advertiseHeader.AddServerIdentifier(m_serverDuid);
169
170 // Find all requested IAIDs for this client.
171 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
172 std::vector<uint32_t> requestedIa(ianaOptionsList.size());
173 for (std::size_t i = 0; i < ianaOptionsList.size(); i++)
174 {
175 requestedIa[i] = ianaOptionsList[i].GetIaid();
176 }
177
178 // Add IA_NA option.
179 // Available address pools and IA information is sent in this option.
180 for (auto& subnet : m_subnets)
181 {
182 /*
183 * Find the next available address. Checks the expired address map.
184 * If there are no expired addresses, it advertises a new address.
185 */
186
187 uint8_t offeredAddrBuf[16];
188
189 bool foundAddress = false;
190 if (!subnet.m_expiredAddresses.empty())
191 {
192 Ipv6Address nextAddress;
193
194 for (auto itr = subnet.m_expiredAddresses.begin();
195 itr != subnet.m_expiredAddresses.end();)
196 {
197 if (itr->second.first == clientDuid)
198 {
199 nextAddress = itr->second.second;
200 nextAddress.GetBytes(offeredAddrBuf);
201 itr = subnet.m_expiredAddresses.erase(itr);
202 foundAddress = true;
203 break;
204 }
205 itr++;
206 }
207
208 /*
209 Prevent Expired Addresses from building up.
210 We set a maximum limit of 30 expired addresses, after which the
211 oldest expired address is removed and offered to a client.
212 */
213 if (!foundAddress && subnet.m_expiredAddresses.size() > 30)
214 {
215 auto firstExpiredAddress = subnet.m_expiredAddresses.begin();
216 nextAddress = firstExpiredAddress->second.second;
217 nextAddress.GetBytes(offeredAddrBuf);
218 subnet.m_expiredAddresses.erase(firstExpiredAddress);
219 foundAddress = true;
220 }
221 }
222
223 if (!foundAddress)
224 {
225 // Allocate a new address.
226 uint8_t minAddrBuf[16];
227 Ipv6Address minAddress = subnet.GetMinAddress();
228 minAddress.GetBytes(minAddrBuf);
229
230 // Get the latest leased address.
231 uint8_t lastLeasedAddrBuf[16];
232
233 if (!subnet.m_leasedAddresses.empty())
234 {
235 // Obtain the highest address that has been offered.
236 subnet.m_maxOfferedAddress.GetBytes(lastLeasedAddrBuf);
237 memcpy(offeredAddrBuf, lastLeasedAddrBuf, 16);
238
239 // Increment the address by adding 1. Bitwise addition is used.
240 bool addedOne = false;
241 for (uint8_t i = 15; !addedOne && i >= 0; i--)
242 {
243 for (int j = 0; j < 8; j++)
244 {
245 uint8_t bit = (offeredAddrBuf[i] & (1 << j)) >> j;
246 if (bit == 0)
247 {
248 offeredAddrBuf[i] = offeredAddrBuf[i] | (1 << j);
249 addedOne = true;
250 break;
251 }
252 offeredAddrBuf[i] = offeredAddrBuf[i] & ~(1 << j);
253 }
254 }
255 }
256 else
257 {
258 memcpy(offeredAddrBuf, minAddrBuf, 16);
259 }
260
261 Ipv6Address offer(offeredAddrBuf);
262 subnet.m_maxOfferedAddress = offer;
263
264 /*
265 Optimistic assumption that the address will be leased to this client.
266 This is to prevent multiple clients from receiving the same address.
267 */
268 subnet.m_leasedAddresses.insert(
269 {clientDuid, std::make_pair(offer, Seconds(m_prefLifetime.GetSeconds()))});
270 }
271
272 Ipv6Address offeredAddr(offeredAddrBuf);
273 NS_LOG_INFO("Offered address: " << offeredAddr);
274 NS_LOG_DEBUG("Offered address: " << offeredAddr);
275
276 for (const auto& iaid : requestedIa)
277 {
278 // Add the IA_NA option and IA Address option.
279 advertiseHeader.AddIanaOption(iaid, m_renew.GetSeconds(), m_rebind.GetSeconds());
280 advertiseHeader.AddAddress(iaid,
281 offeredAddr,
282 m_prefLifetime.GetSeconds(),
283 m_validLifetime.GetSeconds());
284 }
285 }
286
287 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
288 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
289 {
290 std::vector<Options::OptionType> requestedOptions =
292 advertiseHeader.HandleOptionRequest(requestedOptions);
293 }
294
295 packet->AddHeader(advertiseHeader);
296
297 // Find the socket corresponding to the NetDevice.
298 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
299 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
300 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
301
302 // Send the advertise message.
303 if (sendSocket->SendTo(packet, 0, client) >= 0)
304 {
305 NS_LOG_INFO("DHCPv6 Advertise sent.");
306 }
307 else
308 {
309 NS_LOG_INFO("Error while sending DHCPv6 Advertise.");
310 }
311}
312
313void
315{
316 NS_LOG_FUNCTION(this << iDev << header << client);
317
318 // Options included according to RFC 8415 Section 18.3.10
319
320 Ptr<Packet> packet = Create<Packet>();
321 Dhcp6Header replyHeader;
322 replyHeader.ResetOptions();
324 replyHeader.SetTransactId(header.GetTransactId());
325
326 // Add Client Identifier Option, copied from the received header.
327 Duid clientDuid = header.GetClientIdentifier().GetDuid();
328 replyHeader.AddClientIdentifier(clientDuid);
329
330 // Add Server Identifier Option.
332
333 // Add IA_NA option.
334 // Retrieve requested IA Option from client header.
335 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
336
337 for (auto& iaOpt : ianaOptionsList)
338 {
339 // Iterate through the offered addresses.
340 // Current approach: Try to accept all offers.
341 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
342 for (auto& addrItr : iaAddrOptList)
343 {
344 Ipv6Address requestedAddr = addrItr.GetIaAddress();
345
346 for (auto& subnet : m_subnets)
347 {
348 Ipv6Address pool = subnet.GetAddressPool();
349 Ipv6Prefix prefix = subnet.GetPrefix();
350 Ipv6Address minAddress = subnet.GetMinAddress();
351 Ipv6Address maxAddress = subnet.GetMaxAddress();
352
353 // Check if the requested address has been declined earlier.
354 // In this case, it cannot be leased.
355 if (subnet.m_declinedAddresses.find(requestedAddr) !=
356 subnet.m_declinedAddresses.end())
357 {
358 NS_LOG_INFO("Requested address" << requestedAddr << "is declined.");
359 return;
360 }
361
362 // Check whether this subnet matches the requested address.
363 if (prefix.IsMatch(requestedAddr, pool))
364 {
365 uint8_t minBuf[16];
366 uint8_t maxBuf[16];
367 uint8_t requestedBuf[16];
368 minAddress.GetBytes(minBuf);
369 maxAddress.GetBytes(maxBuf);
370 requestedAddr.GetBytes(requestedBuf);
371
372 if (memcmp(requestedBuf, minBuf, 16) < 0 ||
373 memcmp(requestedBuf, maxBuf, 16) > 0)
374 {
375 NS_LOG_INFO("Requested address is not in the range of the subnet.");
376 return;
377 }
378
379 // Add the IA_NA option and IA Address option.
380 replyHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
381 replyHeader.AddAddress(iaOpt.GetIaid(),
382 requestedAddr,
383 m_prefLifetime.GetSeconds(),
384 m_validLifetime.GetSeconds());
385
386 NS_LOG_DEBUG("Adding address " << requestedAddr << " to lease");
387 // Update the lease time of the newly leased addresses.
388 // Find all the leases for this client.
389 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
390
391 // Create a new multimap to store the updated lifetimes.
392 std::multimap<Duid, std::pair<Ipv6Address, Time>> updatedLifetimes;
393 for (auto it = range.first; it != range.second; it++)
394 {
395 Ipv6Address clientLease = it->second.first;
396 std::pair<Ipv6Address, Time> clientLeaseTime = {
397 clientLease,
398 Seconds(m_prefLifetime.GetSeconds())};
399
400 // Add the DUID + Ipv6Address / LeaseTime to the map.
401 updatedLifetimes.insert({clientDuid, clientLeaseTime});
402 }
403
404 // Remove all the old leases for this client.
405 // This is done to prevent multiple entries for the same lease.
406 subnet.m_leasedAddresses.erase(range.first->first);
407
408 // Add the updated leases to the subnet.
409 for (auto& itr : updatedLifetimes)
410 {
411 subnet.m_leasedAddresses.insert({itr.first, itr.second});
412 }
413 break;
414 }
415 }
416 }
417 }
418
419 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
420
421 // Check if the client has requested any options.
422 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
423 {
424 std::vector<Options::OptionType> requestedOptions =
426 replyHeader.HandleOptionRequest(requestedOptions);
427 }
428
429 packet->AddHeader(replyHeader);
430
431 // Find the socket corresponding to the NetDevice.
432 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
433 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
434 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
435
436 // Send the Reply message.
437 if (sendSocket->SendTo(packet, 0, client) >= 0)
438 {
439 NS_LOG_INFO("DHCPv6 Reply sent.");
440 }
441 else
442 {
443 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
444 }
445}
446
447void
449{
450 NS_LOG_FUNCTION(this << iDev << header << client);
451
452 // Options included according to RFC 8415 Section 18.3.4, 18.3.5
453
454 Ptr<Packet> packet = Create<Packet>();
455 Dhcp6Header replyHeader;
456 replyHeader.ResetOptions();
458 replyHeader.SetTransactId(header.GetTransactId());
459
460 // Add Client Identifier Option, copied from the received header.
461 Duid clientDuid = header.GetClientIdentifier().GetDuid();
462 replyHeader.AddClientIdentifier(clientDuid);
463
464 // Add Server Identifier Option.
466
467 // Add IA_NA option.
468 // Retrieve IA_NAs from client header.
469 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
470 for (auto& iaOpt : ianaOptionsList)
471 {
472 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
473
474 // Add the IA_NA option.
475 replyHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
476
477 for (const auto& addrItr : iaAddrOptList)
478 {
479 // Find the lease address which is to be renewed or rebound.
480 Ipv6Address clientLease = addrItr.GetIaAddress();
481
482 // Update the lifetime for the address.
483 // Iterate through the subnet list to find the subnet that the
484 // address belongs to.
485 for (auto& subnet : m_subnets)
486 {
487 Ipv6Prefix prefix = subnet.GetPrefix();
488 Ipv6Address pool = subnet.GetAddressPool();
489
490 // Check if the prefix of the lease matches that of the pool.
491 if (prefix.IsMatch(clientLease, pool))
492 {
493 // Find all the leases for this client.
494 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
495 for (auto itr = range.first; itr != range.second; itr++)
496 {
497 // Check if the IPv6 address matches the client lease.
498 if (itr->second.first == clientLease)
499 {
500 NS_LOG_DEBUG("Renewing address: " << itr->second.first);
501
502 std::pair<Ipv6Address, Time> clientLeaseTime = {
503 clientLease,
504 Seconds(m_prefLifetime.GetSeconds())};
505
506 // Remove the old lease information.
507 subnet.m_leasedAddresses.erase(itr);
508
509 // Add the new lease information (with updated time)
510 subnet.m_leasedAddresses.insert({clientDuid, clientLeaseTime});
511
512 // Add the IA Address option.
513 replyHeader.AddAddress(iaOpt.GetIaid(),
514 clientLease,
515 m_prefLifetime.GetSeconds(),
516 m_validLifetime.GetSeconds());
517 break;
518 }
519 }
520 }
521 }
522 }
523 }
524
525 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
526 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
527 {
528 std::vector<Options::OptionType> requestedOptions =
530 replyHeader.HandleOptionRequest(requestedOptions);
531 }
532
533 packet->AddHeader(replyHeader);
534
535 // Find the socket corresponding to the NetDevice.
536 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
537 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
538 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
539
540 // Send the Reply message.
541 if (sendSocket->SendTo(packet, 0, client) >= 0)
542 {
543 NS_LOG_INFO("DHCPv6 Reply sent.");
544 }
545 else
546 {
547 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
548 }
549}
550
551void
553{
554 // Invoked in case a Decline or Release message is received.
555 NS_LOG_FUNCTION(this << iDev << header << client);
556
557 // Options included in accordance with RFC 8415, Section 18.3.7, 18.3.8
558
559 Ptr<Packet> packet = Create<Packet>();
560 Dhcp6Header replyHeader;
561 replyHeader.ResetOptions();
563 replyHeader.SetTransactId(header.GetTransactId());
564
565 // Add Client Identifier Option, copied from the received header.
566 Duid clientDuid = header.GetClientIdentifier().GetDuid();
567 replyHeader.AddClientIdentifier(clientDuid);
568
569 // Add Server Identifier Option.
571
572 // Add Status code option.
573 replyHeader.AddStatusCode(Options::StatusCodeValues::Success, "Address declined.");
574
575 // Add the declined or expired address to the subnet information.
576 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
577 for (const auto& iaOpt : ianaOptionsList)
578 {
579 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
580
581 for (const auto& addrItr : iaAddrOptList)
582 {
583 Ipv6Address address = addrItr.GetIaAddress();
585 {
586 // Find the subnet that this address belongs to.
587 for (auto& subnet : m_subnets)
588 {
589 // Find the client that the address currently belongs to.
590
591 for (auto itr = subnet.m_leasedAddresses.begin();
592 itr != subnet.m_leasedAddresses.end();)
593 {
594 Ipv6Address leaseAddr = itr->second.first;
595 if (leaseAddr == address)
596 {
597 itr = subnet.m_leasedAddresses.erase(itr);
598 subnet.m_declinedAddresses[address] = clientDuid;
599 continue;
600 }
601 itr++;
602 }
603 }
604 }
606 {
607 // Find the subnet that this address belongs to.
608 for (auto& subnet : m_subnets)
609 {
610 // Find the client that the address currently belongs to.
611
612 for (auto itr = subnet.m_leasedAddresses.begin();
613 itr != subnet.m_leasedAddresses.end();)
614 {
615 Duid duid = itr->first;
616 Ipv6Address leaseAddr = itr->second.first;
617 Time expiredTime = itr->second.second;
618 if (leaseAddr == address)
619 {
620 itr = subnet.m_leasedAddresses.erase(itr);
621 std::pair<Duid, Ipv6Address> expiredLease = {duid, leaseAddr};
622 subnet.m_expiredAddresses.insert({expiredTime, expiredLease});
623 continue;
624 }
625 itr++;
626 }
627 }
628 }
629 }
630 }
631
632 packet->AddHeader(replyHeader);
633
634 // Find the socket corresponding to the NetDevice.
635 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
636 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
637 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
638
639 // Send the Reply message.
640 if (sendSocket->SendTo(packet, 0, client) >= 0)
641 {
642 NS_LOG_INFO("DHCPv6 Reply sent.");
643 }
644 else
645 {
646 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
647 }
648}
649
650void
652{
653 for (auto itr = netDevices.Begin(); itr != netDevices.End(); itr++)
654 {
655 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
656 int32_t ifIndex = ipv6->GetInterfaceForDevice(*itr);
657 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
658 m_sendSockets[ifIndex] = nullptr;
659 }
660}
661
662void
664{
665 NS_LOG_FUNCTION(this << socket);
666
667 Dhcp6Header header;
668 Address from;
669 Ptr<Packet> packet = m_recvSocket->RecvFrom(from);
670
672
673 Ipv6PacketInfoTag interfaceInfo;
674 NS_ASSERT_MSG(packet->RemovePacketTag(interfaceInfo),
675 "No incoming interface on DHCPv6 message.");
676
677 uint32_t incomingIf = interfaceInfo.GetRecvIf();
678 Ptr<NetDevice> iDev = GetNode()->GetDevice(incomingIf);
679
680 if (packet->RemoveHeader(header) == 0)
681 {
682 return;
683 }
684
686 {
687 ProcessSolicit(iDev, header, senderAddr);
688 SendAdvertise(iDev, header, senderAddr);
689 }
691 {
692 SendReply(iDev, header, senderAddr);
693 }
696 {
697 RenewRebindLeases(iDev, header, senderAddr);
698 }
701 {
702 UpdateBindings(iDev, header, senderAddr);
703 }
704}
705
706void
708 Ipv6Prefix prefix,
709 Ipv6Address minAddress,
710 Ipv6Address maxAddress)
711{
712 NS_LOG_FUNCTION(this << addressPool << prefix << minAddress << maxAddress);
713
714 NS_LOG_DEBUG("DHCPv6 server: Adding subnet " << addressPool << " to lease information.");
715 LeaseInfo newSubnet(addressPool, prefix, minAddress, maxAddress);
716 m_subnets.emplace_back(newSubnet);
717}
718
719void
721{
722 Ptr<Node> node = GetNode();
723 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
724 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
725
726 for (auto itr = m_sendSockets.begin(); itr != m_sendSockets.end(); itr++)
727 {
728 uint32_t ifIndex = itr->first;
729 Ptr<NetDevice> device = GetNode()->GetDevice(ifIndex);
730 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
731
732 if (ifIndex == recvInterface)
733 {
734 Ipv6Address linkLocal =
735 ipv6l3->GetInterface(ifIndex)->GetLinkLocalAddress().GetAddress();
736
737 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
738
739 Ptr<Socket> socket = Socket::CreateSocket(node, tid);
740 socket->Bind(Inet6SocketAddress(linkLocal, Dhcp6Header::SERVER_PORT));
741 socket->BindToNetDevice(device);
742 socket->SetRecvPktInfo(true);
743 socket->SetRecvCallback(MakeCallback(&Dhcp6Server::NetHandler, this));
744
745 m_sendSockets[ifIndex] = socket;
746 }
747 }
748}
749
750void
752{
753 NS_LOG_INFO("Starting DHCPv6 server.");
754
755 if (m_recvSocket)
756 {
757 NS_LOG_INFO("DHCPv6 daemon is not meant to be started repeatedly.");
758 return;
759 }
760
761 Ptr<Node> node = GetNode();
762 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
763 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
764
765 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
767
768 Inet6SocketAddress local =
770 m_recvSocket->Bind(local);
771 m_recvSocket->SetRecvPktInfo(true);
772 m_recvSocket->SetRecvCallback(MakeCallback(&Dhcp6Server::NetHandler, this));
773
774 for (auto itr = m_sendSockets.begin(); itr != m_sendSockets.end(); itr++)
775 {
776 int32_t ifIndex = itr->first;
777 Ptr<NetDevice> iDev = GetNode()->GetDevice(ifIndex);
778 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
779
780 NS_LOG_DEBUG("DHCPv6 server: Node " << node->GetId() << " listening on interface "
781 << ifIndex);
782
783 NS_ASSERT_MSG(ifIndex >= 0,
784 "Dhcp6Server::StartApplication: device is not connected to IPv6.");
785
787 ipv6->GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber(), ifIndex));
788
789 icmpv6->SetDhcpv6Callback(MakeCallback(&Dhcp6Server::ReceiveMflag, this));
790 }
791
792 // Initialize the DUID before responding to the client.
793 if (m_serverDuid.IsInvalid())
794 {
795 Ptr<Node> node = GetNode();
796 // We use enterprise-number 0xf00dcafe (totally arbitrary)
797 // The current largest enterprise number is less than 0xffff, which means
798 // we use an unused number.
799 // The list of numbers is at
800 // https://www.iana.org/assignments/enterprise-numbers/
802 NS_LOG_INFO("DHCPv6 server DUID created: " << m_serverDuid);
803 }
804
806}
807
808void
813
814void
816{
817 NS_LOG_DEBUG("Cleaning up leases.");
818 for (auto& subnet : m_subnets)
819 {
820 for (auto itr = subnet.m_leasedAddresses.begin(); itr != subnet.m_leasedAddresses.end();)
821 {
822 Duid duid = itr->first;
823 Ipv6Address address = itr->second.first;
824 Time leaseTime = itr->second.second;
825
826 if (Simulator::Now() >= leaseTime)
827 {
828 NS_LOG_DEBUG("DHCPv6 server: Removing expired lease for " << address);
829 std::pair<Duid, Ipv6Address> expiredLease = {duid, address};
830 subnet.m_expiredAddresses.insert({leaseTime, expiredLease});
831 itr = subnet.m_leasedAddresses.erase(itr);
832 continue;
833 }
834 itr++;
835 }
836 }
837
839}
840
842 Ipv6Prefix prefix,
843 Ipv6Address minAddress,
844 Ipv6Address maxAddress)
845{
846 m_addressPool = addressPool;
847 m_prefix = prefix;
848 m_minAddress = minAddress;
849 m_maxAddress = maxAddress;
850 m_numAddresses = 0;
851}
852
855{
856 return m_addressPool;
857}
858
861{
862 return m_prefix;
863}
864
867{
868 return m_minAddress;
869}
870
873{
874 return m_maxAddress;
875}
876
879{
880 return m_numAddresses;
881}
882} // namespace ns3
a polymophic address class
Definition address.h:114
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
Implements the DHCPv6 header.
IdentifierOption GetClientIdentifier()
Get the client identifier.
void AddServerIdentifier(Duid duid)
Add the server identifier option.
void ResetOptions()
Reset all options.
std::map< Options::OptionType, bool > GetOptionList()
Get list of all options set in the header.
void AddClientIdentifier(Duid duid)
Add the client identifier option.
uint32_t GetTransactId() const
Get the transaction ID.
void AddAddress(uint32_t iaid, Ipv6Address address, uint32_t prefLifetime, uint32_t validLifetime)
Add IA address option to the IANA or IATA.
MessageType GetMessageType() const
Get the type of message.
static const uint16_t SERVER_PORT
The port number of the DHCPv6 server.
void HandleOptionRequest(std::vector< Options::OptionType > requestedOptions)
Handle all options requested by client.
void AddStatusCode(Options::StatusCodeValues statusCode, std::string statusMsg)
Add the status code option.
void AddIanaOption(uint32_t iaid, uint32_t t1, uint32_t t2)
Add IANA option.
void SetMessageType(MessageType msgType)
Set the message type.
std::vector< IaOptions > GetIanaOptions()
Get the list of IA_NA options.
RequestOptions GetOptionRequest()
Get the option request option.
void SetTransactId(uint32_t transactId)
Set the transaction ID.
void SendAdvertise(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress client)
Sends DHCPv6 Advertise after receiving DHCPv6 Solicit.
std::unordered_map< uint32_t, Ptr< Socket > > m_sendSockets
Map of NetDevice - Corresponding socket used to send packets.
void DoDispose() override
Destructor implementation.
void SendReply(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress client)
Sends Reply after receiving Request.
void StartApplication() override
Application specific startup code.
void AddSubnet(Ipv6Address pool, Ipv6Prefix prefix, Ipv6Address minAddress, Ipv6Address maxAddress)
Add a managed address pool.
std::multimap< Duid, std::pair< Options::OptionType, uint32_t > > m_iaBindings
Store IA bindings. Map of DUID + IA Type / IAID.
Duid m_serverDuid
The server DUID, built by StartApplication() on fist usage.
EventId m_leaseCleanupEvent
Event ID for lease cleanup.
void NetHandler(Ptr< Socket > socket)
Handles incoming packets from the network.
static TypeId GetTypeId()
Get the type ID.
Dhcp6Server()
Default constructor.
Ptr< Socket > m_recvSocket
Socket bound to port 547.
Time m_validLifetime
Default valid lifetime.
Time m_prefLifetime
Default preferred lifetime for an address.
Time m_renew
The default renew timer.
uint16_t m_DuidEnIdentifierLength
DUID-EN identifier length.
std::vector< LeaseInfo > m_subnets
List of managed subnets.
void SetDhcp6ServerNetDevice(NetDeviceContainer netDevices)
Set the list of net devices that the DHCPv6 server will use.
void CleanLeases()
Clean up stale lease info.
void ProcessSolicit(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress client)
Sends DHCPv6 Advertise after receiving DHCPv6 Solicit.
void StopApplication() override
Application specific shutdown code.
Duid::Type m_duidType
DUID type.
Time m_leaseCleanup
Lease cleanup time.
void ReceiveMflag(uint32_t recvInterface)
Callback for when an M flag is received.
void UpdateBindings(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress client)
Sends Reply after receiving Request.
void RenewRebindLeases(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress client)
Sends Reply after receiving Request.
Time m_rebind
The default rebind timer.
Implements the unique identifier for DHCPv6.
Definition dhcp6-duid.h:27
Hold variables of type enum.
Definition enum.h:52
static uint16_t GetStaticProtocolNumber()
Get ICMPv6 protocol number.
Duid GetDuid() const
Get the DUID object.
An Inet6 address class.
static Inet6SocketAddress ConvertFrom(const Address &addr)
Convert the address to a InetSocketAddress.
Hold a signed integer type.
Definition integer.h:34
Describes an IPv6 address.
static Ipv6Address GetAllNodesMulticast()
Get the "all nodes multicast" address.
void GetBytes(uint8_t buf[16]) const
Get the bytes corresponding to the address.
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition ipv6.h:71
IPv6 layer implementation.
This class implements a tag that carries socket ancillary data to the socket interface.
uint32_t GetRecvIf() const
Get the tag's receiving interface.
Describes an IPv6 prefix.
bool IsMatch(Ipv6Address a, Ipv6Address b) const
Check whether two addresses have the same bits in the prefix portion of their addresses.
Includes information about available subnets and corresponding leases.
Ipv6Address GetMinAddress() const
Get the minimum address in the pool.
uint32_t GetNumAddresses() const
Get the number of addresses leased.
Ipv6Address m_maxAddress
Maximum address in the pool.
Ipv6Prefix GetPrefix() const
Get the prefix of the address pool.
Ipv6Prefix m_prefix
Prefix of the address pool.
Ipv6Address GetMaxAddress() const
Get the maximum address in the pool.
Ipv6Address m_addressPool
Address pool.
Ipv6Address GetAddressPool() const
Get the address pool.
Ipv6Address m_minAddress
Minimum address in the pool.
uint32_t m_numAddresses
Number of addresses leased.
LeaseInfo(Ipv6Address addressPool, Ipv6Prefix prefix, Ipv6Address minAddress, Ipv6Address maxAddress)
Constructor.
holds a vector of ns3::NetDevice pointers
Iterator Begin() const
Get an iterator which refers to the first NetDevice in the container.
Iterator End() const
Get an iterator which indicates past-the-last NetDevice in the container.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition node.cc:138
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:518
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
std::vector< OptionType > GetRequestedOptions() const
Get the option values.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition socket.cc:61
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
AttributeValue implementation for Time.
Definition nstime.h:1375
a unique identifier for an interface.
Definition type-id.h:50
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:870
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
#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
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition enum.h:223
Ptr< const AttributeChecker > MakeIntegerChecker()
Definition integer.h:99
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition integer.h:35
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1376
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1396
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:690
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
Definition callback.h:734
#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 ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:181
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605