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/icmpv6-l4-protocol.h"
16#include "ns3/ipv6-interface.h"
17#include "ns3/ipv6-l3-protocol.h"
18#include "ns3/ipv6-packet-info-tag.h"
19#include "ns3/ipv6.h"
20#include "ns3/log.h"
21#include "ns3/loopback-net-device.h"
22#include "ns3/simulator.h"
23#include "ns3/socket.h"
24
25#include <algorithm>
26
27namespace ns3
28{
29
30NS_LOG_COMPONENT_DEFINE("Dhcp6Server");
31
32TypeId
34{
35 static TypeId tid =
36 TypeId("ns3::Dhcp6Server")
38 .AddConstructor<Dhcp6Server>()
39 .SetGroupName("InternetApps")
40 .AddAttribute("RenewTime",
41 "Time after which client should renew. 1000 seconds by default in Linux. "
42 "This is equivalent to REN_MAX_RT (RFC 8415, Section 7.6).",
43 TimeValue(Seconds(1000)),
46 .AddAttribute("RebindTime",
47 "Time after which client should rebind. "
48 "2000 seconds by default in Linux. "
49 "This is equivalent to REB_MAX_RT (RFC 8415, Section 7.6).",
50 TimeValue(Seconds(2000)),
53 .AddAttribute("PreferredLifetime",
54 "The preferred lifetime of the leased address. "
55 "3000 seconds by default in Linux.",
56 TimeValue(Seconds(3000)),
59 .AddAttribute("ValidLifetime",
60 "Time after which client should release the address. "
61 "4000 seconds by default in Linux.",
62 TimeValue(Seconds(4000)),
65
66 return tid;
67}
68
73
74void
76{
77 NS_LOG_FUNCTION(this);
78 if (m_recvSocket)
79 {
81 m_recvSocket = nullptr;
82 }
83
84 for (auto& itr : m_subnets)
85 {
86 itr.m_leasedAddresses.clear();
87 itr.m_expiredAddresses.clear();
88 itr.m_declinedAddresses.clear();
89 }
90 m_subnets.clear();
92
93 for (auto& itr : m_sendSockets)
94 {
95 // Close sockets.
96 if (!itr.second)
97 {
98 continue;
99 }
100 itr.second->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
102 itr.second->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
103 itr.second->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
104 itr.second->Close();
105 }
106 m_sendSockets.clear();
107 m_iaBindings.clear();
109}
110
111void
113{
114 Duid clientDuid = header.GetClientIdentifier().GetDuid();
115 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
116
117 // Add each IA in the header to the IA bindings.
118 if (headerOptions.find(Options::OptionType::OPTION_IA_NA) != headerOptions.end())
119 {
120 std::vector<IaOptions> iaOpt = header.GetIanaOptions();
121 for (const auto& itr : iaOpt)
122 {
123 uint32_t iaid = itr.GetIaid();
124 m_iaBindings.insert(
125 {clientDuid, std::make_pair(Options::OptionType::OPTION_IA_NA, iaid)});
126 NS_LOG_DEBUG("DHCPv6 server: Client registering IAID " << iaid);
127 }
128 }
129}
130
131void
133{
134 NS_LOG_FUNCTION(this << iDev << header << client);
135
136 // Options included according to RFC 8415 Section 18.3.9
137
138 Ptr<Packet> packet = Create<Packet>();
139 Dhcp6Header advertiseHeader;
140 advertiseHeader.ResetOptions();
142 advertiseHeader.SetTransactId(header.GetTransactId());
143
144 // Add Client Identifier Option, copied from the received header.
145 Duid clientDuid = header.GetClientIdentifier().GetDuid();
146 advertiseHeader.AddClientIdentifier(clientDuid);
147
148 // Add Server Identifier Option.
149 advertiseHeader.AddServerIdentifier(m_serverDuid);
150
151 // Find all requested IAIDs for this client.
152 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
153 std::vector<uint32_t> requestedIa(ianaOptionsList.size());
154 for (std::size_t i = 0; i < ianaOptionsList.size(); i++)
155 {
156 requestedIa[i] = ianaOptionsList[i].GetIaid();
157 }
158
159 // Add IA_NA option.
160 // Available address pools and IA information is sent in this option.
161 for (auto& subnet : m_subnets)
162 {
163 Ipv6Address pool = subnet.GetAddressPool();
164 Ipv6Prefix prefix = subnet.GetPrefix();
165 Ipv6Address minAddress = subnet.GetMinAddress();
166 Ipv6Address maxAddress = subnet.GetMaxAddress();
167
168 /*
169 * Find the next available address. Checks the expired address map.
170 * If there are no expired addresses, it advertises a new address.
171 */
172
173 uint8_t offeredAddrBuf[16];
174
175 bool foundAddress = false;
176 if (!subnet.m_expiredAddresses.empty())
177 {
178 Ipv6Address nextAddress;
179
180 for (auto itr = subnet.m_expiredAddresses.begin();
181 itr != subnet.m_expiredAddresses.end();)
182 {
183 if (itr->second.first == clientDuid)
184 {
185 nextAddress = itr->second.second;
186 nextAddress.GetBytes(offeredAddrBuf);
187 itr = subnet.m_expiredAddresses.erase(itr);
188 foundAddress = true;
189 break;
190 }
191 itr++;
192 }
193
194 /*
195 Prevent Expired Addresses from building up.
196 We set a maximum limit of 30 expired addresses, after which the
197 oldest expired address is removed and offered to a client.
198 */
199 if (!foundAddress && subnet.m_expiredAddresses.size() > 30)
200 {
201 auto firstExpiredAddress = subnet.m_expiredAddresses.begin();
202 nextAddress = firstExpiredAddress->second.second;
203 nextAddress.GetBytes(offeredAddrBuf);
204 subnet.m_expiredAddresses.erase(firstExpiredAddress);
205 foundAddress = true;
206 }
207 }
208
209 if (!foundAddress)
210 {
211 // Allocate a new address.
212 uint8_t minAddrBuf[16];
213 minAddress.GetBytes(minAddrBuf);
214
215 // Get the latest leased address.
216 uint8_t lastLeasedAddrBuf[16];
217
218 if (!subnet.m_leasedAddresses.empty())
219 {
220 // Obtain the highest address that has been offered.
221 subnet.m_maxOfferedAddress.GetBytes(lastLeasedAddrBuf);
222 memcpy(offeredAddrBuf, lastLeasedAddrBuf, 16);
223
224 // Increment the address by adding 1. Bitwise addition is used.
225 bool addedOne = false;
226 for (uint8_t i = 15; !addedOne && i >= 0; i--)
227 {
228 for (int j = 0; j < 8; j++)
229 {
230 uint8_t bit = (offeredAddrBuf[i] & (1 << j)) >> j;
231 if (bit == 0)
232 {
233 offeredAddrBuf[i] = offeredAddrBuf[i] | (1 << j);
234 addedOne = true;
235 break;
236 }
237 offeredAddrBuf[i] = offeredAddrBuf[i] & ~(1 << j);
238 }
239 }
240 }
241 else
242 {
243 memcpy(offeredAddrBuf, minAddrBuf, 16);
244 }
245
246 Ipv6Address offer(offeredAddrBuf);
247 subnet.m_maxOfferedAddress = offer;
248
249 /*
250 Optimistic assumption that the address will be leased to this client.
251 This is to prevent multiple clients from receiving the same address.
252 */
253 subnet.m_leasedAddresses.insert(
254 {clientDuid, std::make_pair(offer, Seconds(m_prefLifetime.GetSeconds()))});
255 }
256
257 Ipv6Address offeredAddr(offeredAddrBuf);
258 NS_LOG_INFO("Offered address: " << offeredAddr);
259 NS_LOG_DEBUG("Offered address: " << offeredAddr);
260
261 for (const auto& iaid : requestedIa)
262 {
263 // Add the IA_NA option and IA Address option.
264 advertiseHeader.AddIanaOption(iaid, m_renew.GetSeconds(), m_rebind.GetSeconds());
265 advertiseHeader.AddAddress(iaid,
266 offeredAddr,
269 }
270 }
271
272 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
273 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
274 {
275 std::vector<Options::OptionType> requestedOptions =
277 advertiseHeader.HandleOptionRequest(requestedOptions);
278 }
279
280 packet->AddHeader(advertiseHeader);
281
282 // Find the socket corresponding to the NetDevice.
283 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
284 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
285 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
286
287 // Send the advertise message.
288 if (sendSocket->SendTo(packet, 0, client) >= 0)
289 {
290 NS_LOG_INFO("DHCPv6 Advertise sent.");
291 }
292 else
293 {
294 NS_LOG_INFO("Error while sending DHCPv6 Advertise.");
295 }
296}
297
298void
300{
301 NS_LOG_FUNCTION(this << iDev << header << client);
302
303 // Options included according to RFC 8415 Section 18.3.10
304
305 Ptr<Packet> packet = Create<Packet>();
306 Dhcp6Header replyHeader;
307 replyHeader.ResetOptions();
309 replyHeader.SetTransactId(header.GetTransactId());
310
311 // Add Client Identifier Option, copied from the received header.
312 Duid clientDuid = header.GetClientIdentifier().GetDuid();
313 replyHeader.AddClientIdentifier(clientDuid);
314
315 // Add Server Identifier Option.
317
318 // Add IA_NA option.
319 // Retrieve requested IA Option from client header.
320 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
321
322 for (auto& iaOpt : ianaOptionsList)
323 {
324 // Iterate through the offered addresses.
325 // Current approach: Try to accept all offers.
326 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
327 for (auto& addrItr : iaAddrOptList)
328 {
329 Ipv6Address requestedAddr = addrItr.GetIaAddress();
330
331 for (auto& subnet : m_subnets)
332 {
333 Ipv6Address pool = subnet.GetAddressPool();
334 Ipv6Prefix prefix = subnet.GetPrefix();
335 Ipv6Address minAddress = subnet.GetMinAddress();
336 Ipv6Address maxAddress = subnet.GetMaxAddress();
337
338 // Check if the requested address has been declined earlier.
339 // In this case, it cannot be leased.
340 if (subnet.m_declinedAddresses.find(requestedAddr) !=
341 subnet.m_declinedAddresses.end())
342 {
343 NS_LOG_INFO("Requested address" << requestedAddr << "is declined.");
344 return;
345 }
346
347 // Check whether this subnet matches the requested address.
348 if (prefix.IsMatch(requestedAddr, pool))
349 {
350 uint8_t minBuf[16];
351 uint8_t maxBuf[16];
352 uint8_t requestedBuf[16];
353 minAddress.GetBytes(minBuf);
354 maxAddress.GetBytes(maxBuf);
355 requestedAddr.GetBytes(requestedBuf);
356
357 if (memcmp(requestedBuf, minBuf, 16) < 0 ||
358 memcmp(requestedBuf, maxBuf, 16) > 0)
359 {
360 NS_LOG_INFO("Requested address is not in the range of the subnet.");
361 return;
362 }
363
364 // Add the IA_NA option and IA Address option.
365 replyHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
366 replyHeader.AddAddress(iaOpt.GetIaid(),
367 requestedAddr,
370
371 NS_LOG_DEBUG("Adding address " << requestedAddr << " to lease");
372 // Update the lease time of the newly leased addresses.
373 // Find all the leases for this client.
374 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
375
376 // Create a new multimap to store the updated lifetimes.
377 std::multimap<Duid, std::pair<Ipv6Address, Time>> updatedLifetimes;
378 for (auto it = range.first; it != range.second; it++)
379 {
380 Ipv6Address clientLease = it->second.first;
381 std::pair<Ipv6Address, Time> clientLeaseTime = {
382 clientLease,
384
385 // Add the DUID + Ipv6Address / LeaseTime to the map.
386 updatedLifetimes.insert({clientDuid, clientLeaseTime});
387 }
388
389 // Remove all the old leases for this client.
390 // This is done to prevent multiple entries for the same lease.
391 subnet.m_leasedAddresses.erase(range.first->first);
392
393 // Add the updated leases to the subnet.
394 for (auto& itr : updatedLifetimes)
395 {
396 subnet.m_leasedAddresses.insert({itr.first, itr.second});
397 }
398 break;
399 }
400 }
401 }
402 }
403
404 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
405
406 // Check if the client has requested any options.
407 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
408 {
409 std::vector<Options::OptionType> requestedOptions =
411 replyHeader.HandleOptionRequest(requestedOptions);
412 }
413
414 packet->AddHeader(replyHeader);
415
416 // Find the socket corresponding to the NetDevice.
417 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
418 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
419 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
420
421 // Send the Reply message.
422 if (sendSocket->SendTo(packet, 0, client) >= 0)
423 {
424 NS_LOG_INFO("DHCPv6 Reply sent.");
425 }
426 else
427 {
428 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
429 }
430}
431
432void
434{
435 NS_LOG_FUNCTION(this << iDev << header << client);
436
437 // Options included according to RFC 8415 Section 18.3.4, 18.3.5
438
439 Ptr<Packet> packet = Create<Packet>();
440 Dhcp6Header replyHeader;
441 replyHeader.ResetOptions();
443 replyHeader.SetTransactId(header.GetTransactId());
444
445 // Add Client Identifier Option, copied from the received header.
446 Duid clientDuid = header.GetClientIdentifier().GetDuid();
447 replyHeader.AddClientIdentifier(clientDuid);
448
449 // Add Server Identifier Option.
451
452 // Add IA_NA option.
453 // Retrieve IA_NAs from client header.
454 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
455 for (auto& iaOpt : ianaOptionsList)
456 {
457 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
458
459 // Add the IA_NA option.
460 replyHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
461
462 for (const auto& addrItr : iaAddrOptList)
463 {
464 // Find the lease address which is to be renewed or rebound.
465 Ipv6Address clientLease = addrItr.GetIaAddress();
466
467 // Update the lifetime for the address.
468 // Iterate through the subnet list to find the subnet that the
469 // address belongs to.
470 for (auto& subnet : m_subnets)
471 {
472 Ipv6Prefix prefix = subnet.GetPrefix();
473 Ipv6Address pool = subnet.GetAddressPool();
474
475 // Check if the prefix of the lease matches that of the pool.
476 if (prefix.IsMatch(clientLease, pool))
477 {
478 // Find all the leases for this client.
479 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
480 for (auto itr = range.first; itr != range.second; itr++)
481 {
482 // Check if the IPv6 address matches the client lease.
483 if (itr->second.first == clientLease)
484 {
485 NS_LOG_DEBUG("Renewing address: " << itr->second.first);
486
487 std::pair<Ipv6Address, Time> clientLeaseTime = {
488 clientLease,
490
491 // Remove the old lease information.
492 subnet.m_leasedAddresses.erase(itr);
493
494 // Add the new lease information (with updated time)
495 subnet.m_leasedAddresses.insert({clientDuid, clientLeaseTime});
496
497 // Add the IA Address option.
498 replyHeader.AddAddress(iaOpt.GetIaid(),
499 clientLease,
502 break;
503 }
504 }
505 }
506 }
507 }
508 }
509
510 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
511 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
512 {
513 std::vector<Options::OptionType> requestedOptions =
515 replyHeader.HandleOptionRequest(requestedOptions);
516 }
517
518 packet->AddHeader(replyHeader);
519
520 // Find the socket corresponding to the NetDevice.
521 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
522 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
523 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
524
525 // Send the Reply message.
526 if (sendSocket->SendTo(packet, 0, client) >= 0)
527 {
528 NS_LOG_INFO("DHCPv6 Reply sent.");
529 }
530 else
531 {
532 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
533 }
534}
535
536void
538{
539 // Invoked in case a Decline or Release message is received.
540 NS_LOG_FUNCTION(this << iDev << header << client);
541
542 // Options included in accordance with RFC 8415, Section 18.3.7, 18.3.8
543
544 Ptr<Packet> packet = Create<Packet>();
545 Dhcp6Header replyHeader;
546 replyHeader.ResetOptions();
548 replyHeader.SetTransactId(header.GetTransactId());
549
550 // Add Client Identifier Option, copied from the received header.
551 Duid clientDuid = header.GetClientIdentifier().GetDuid();
552 replyHeader.AddClientIdentifier(clientDuid);
553
554 // Add Server Identifier Option.
556
557 // Add Status code option.
558 replyHeader.AddStatusCode(Options::StatusCodeValues::Success, "Address declined.");
559
560 // Add the declined or expired address to the subnet information.
561 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
562 for (const auto& iaOpt : ianaOptionsList)
563 {
564 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
565
566 for (const auto& addrItr : iaAddrOptList)
567 {
568 Ipv6Address address = addrItr.GetIaAddress();
570 {
571 // Find the subnet that this address belongs to.
572 for (auto& subnet : m_subnets)
573 {
574 // Find the client that the address currently belongs to.
575
576 for (auto itr = subnet.m_leasedAddresses.begin();
577 itr != subnet.m_leasedAddresses.end();)
578 {
579 Ipv6Address leaseAddr = itr->second.first;
580 if (leaseAddr == address)
581 {
582 itr = subnet.m_leasedAddresses.erase(itr);
583 subnet.m_declinedAddresses[address] = clientDuid;
584 continue;
585 }
586 itr++;
587 }
588 }
589 }
591 {
592 // Find the subnet that this address belongs to.
593 for (auto& subnet : m_subnets)
594 {
595 // Find the client that the address currently belongs to.
596
597 for (auto itr = subnet.m_leasedAddresses.begin();
598 itr != subnet.m_leasedAddresses.end();)
599 {
600 Duid duid = itr->first;
601 Ipv6Address leaseAddr = itr->second.first;
602 Time expiredTime = itr->second.second;
603 if (leaseAddr == address)
604 {
605 itr = subnet.m_leasedAddresses.erase(itr);
606 std::pair<Duid, Ipv6Address> expiredLease = {duid, leaseAddr};
607 subnet.m_expiredAddresses.insert({expiredTime, expiredLease});
608 continue;
609 }
610 itr++;
611 }
612 }
613 }
614 }
615 }
616
617 packet->AddHeader(replyHeader);
618
619 // Find the socket corresponding to the NetDevice.
620 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
621 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
622 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
623
624 // Send the Reply message.
625 if (sendSocket->SendTo(packet, 0, client) >= 0)
626 {
627 NS_LOG_INFO("DHCPv6 Reply sent.");
628 }
629 else
630 {
631 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
632 }
633}
634
635void
637{
638 for (auto itr = netDevices.Begin(); itr != netDevices.End(); itr++)
639 {
640 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
641 int32_t ifIndex = ipv6->GetInterfaceForDevice(*itr);
642 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
643 m_sendSockets[ifIndex] = nullptr;
644 }
645}
646
647void
649{
650 NS_LOG_FUNCTION(this << socket);
651
652 Dhcp6Header header;
653 Address from;
654 Ptr<Packet> packet = m_recvSocket->RecvFrom(from);
655
657
658 Ipv6PacketInfoTag interfaceInfo;
659 NS_ASSERT_MSG(packet->RemovePacketTag(interfaceInfo),
660 "No incoming interface on DHCPv6 message.");
661
662 uint32_t incomingIf = interfaceInfo.GetRecvIf();
663 Ptr<NetDevice> iDev = GetNode()->GetDevice(incomingIf);
664
665 if (packet->RemoveHeader(header) == 0)
666 {
667 return;
668 }
669
670 // Initialize the DUID before responding to the client.
671 Ptr<Node> node = GetNode();
673
675 {
676 ProcessSolicit(iDev, header, senderAddr);
677 SendAdvertise(iDev, header, senderAddr);
678 }
680 {
681 SendReply(iDev, header, senderAddr);
682 }
685 {
686 RenewRebindLeases(iDev, header, senderAddr);
687 }
690 {
691 UpdateBindings(iDev, header, senderAddr);
692 }
693}
694
695void
697 Ipv6Prefix prefix,
698 Ipv6Address minAddress,
699 Ipv6Address maxAddress)
700{
701 NS_LOG_FUNCTION(this << addressPool << prefix << minAddress << maxAddress);
702
703 NS_LOG_DEBUG("DHCPv6 server: Adding subnet " << addressPool << " to lease information.");
704 LeaseInfo newSubnet(addressPool, prefix, minAddress, maxAddress);
705 m_subnets.emplace_back(newSubnet);
706}
707
708void
710{
711 Ptr<Node> node = GetNode();
712 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
713 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
714
715 for (auto itr = m_sendSockets.begin(); itr != m_sendSockets.end(); itr++)
716 {
717 uint32_t ifIndex = itr->first;
718 Ptr<NetDevice> device = GetNode()->GetDevice(ifIndex);
719 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
720
721 if (ifIndex == recvInterface)
722 {
723 Ipv6Address linkLocal =
724 ipv6l3->GetInterface(ifIndex)->GetLinkLocalAddress().GetAddress();
725
726 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
727
728 Ptr<Socket> socket = Socket::CreateSocket(node, tid);
729 socket->Bind(Inet6SocketAddress(linkLocal, Dhcp6Header::SERVER_PORT));
730 socket->BindToNetDevice(device);
731 socket->SetRecvPktInfo(true);
732 socket->SetRecvCallback(MakeCallback(&Dhcp6Server::NetHandler, this));
733
734 m_sendSockets[ifIndex] = socket;
735 }
736 }
737}
738
739void
741{
742 NS_LOG_INFO("Starting DHCPv6 server.");
743
744 if (m_recvSocket)
745 {
746 NS_LOG_INFO("DHCPv6 daemon is not meant to be started repeatedly.");
747 return;
748 }
749
750 Ptr<Node> node = GetNode();
751 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
752 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
753
754 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
756
757 Inet6SocketAddress local =
759 m_recvSocket->Bind(local);
762
763 for (auto itr = m_sendSockets.begin(); itr != m_sendSockets.end(); itr++)
764 {
765 int32_t ifIndex = itr->first;
766 Ptr<NetDevice> iDev = GetNode()->GetDevice(ifIndex);
767 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
768
769 NS_LOG_DEBUG("DHCPv6 server: Node " << node->GetId() << " listening on interface "
770 << ifIndex);
771
772 NS_ASSERT_MSG(ifIndex >= 0,
773 "Dhcp6Server::StartApplication: device is not connected to IPv6.");
774
776 ipv6->GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber(), ifIndex));
777
778 icmpv6->SetDhcpv6Callback(MakeCallback(&Dhcp6Server::ReceiveMflag, this));
779 }
780
782}
783
784void
789
790void
792{
793 NS_LOG_DEBUG("Cleaning up leases.");
794 for (auto& subnet : m_subnets)
795 {
796 for (auto itr = subnet.m_leasedAddresses.begin(); itr != subnet.m_leasedAddresses.end();)
797 {
798 Duid duid = itr->first;
799 Ipv6Address address = itr->second.first;
800 Time leaseTime = itr->second.second;
801
802 if (Simulator::Now() >= leaseTime)
803 {
804 NS_LOG_DEBUG("DHCPv6 server: Removing expired lease for " << address);
805 std::pair<Duid, Ipv6Address> expiredLease = {duid, address};
806 subnet.m_expiredAddresses.insert({leaseTime, expiredLease});
807 itr = subnet.m_leasedAddresses.erase(itr);
808 continue;
809 }
810 itr++;
811 }
812 }
813
815}
816
818 Ipv6Prefix prefix,
819 Ipv6Address minAddress,
820 Ipv6Address maxAddress)
821{
822 m_addressPool = addressPool;
823 m_prefix = prefix;
824 m_minAddress = minAddress;
825 m_maxAddress = maxAddress;
826 m_numAddresses = 0;
827}
828
831{
832 return m_addressPool;
833}
834
837{
838 return m_prefix;
839}
840
843{
844 return m_minAddress;
845}
846
849{
850 return m_maxAddress;
851}
852
855{
856 return m_numAddresses;
857}
858} // namespace ns3
a polymophic address class
Definition address.h:90
The base class for all ns3 applications.
Definition application.h:51
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
Server DUID.
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.
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.
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
void Initialize(Ptr< Node > node)
Initialize the DUID for a client or server.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
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.
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
If the Address match the type.
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:511
Smart pointer class similar to boost::intrusive_ptr.
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:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
void SetRecvPktInfo(bool flag)
Enable/Disable receive packet information to socket.
Definition socket.cc:343
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
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
virtual int Close()=0
Close a socket.
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:872
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#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 > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:264
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580