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
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 {
80 m_recvSocket->Close();
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();
91 m_leaseCleanupEvent.Cancel();
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 /*
164 * Find the next available address. Checks the expired address map.
165 * If there are no expired addresses, it advertises a new address.
166 */
167
168 uint8_t offeredAddrBuf[16];
169
170 bool foundAddress = false;
171 if (!subnet.m_expiredAddresses.empty())
172 {
173 Ipv6Address nextAddress;
174
175 for (auto itr = subnet.m_expiredAddresses.begin();
176 itr != subnet.m_expiredAddresses.end();)
177 {
178 if (itr->second.first == clientDuid)
179 {
180 nextAddress = itr->second.second;
181 nextAddress.GetBytes(offeredAddrBuf);
182 itr = subnet.m_expiredAddresses.erase(itr);
183 foundAddress = true;
184 break;
185 }
186 itr++;
187 }
188
189 /*
190 Prevent Expired Addresses from building up.
191 We set a maximum limit of 30 expired addresses, after which the
192 oldest expired address is removed and offered to a client.
193 */
194 if (!foundAddress && subnet.m_expiredAddresses.size() > 30)
195 {
196 auto firstExpiredAddress = subnet.m_expiredAddresses.begin();
197 nextAddress = firstExpiredAddress->second.second;
198 nextAddress.GetBytes(offeredAddrBuf);
199 subnet.m_expiredAddresses.erase(firstExpiredAddress);
200 foundAddress = true;
201 }
202 }
203
204 if (!foundAddress)
205 {
206 // Allocate a new address.
207 uint8_t minAddrBuf[16];
208 Ipv6Address minAddress = subnet.GetMinAddress();
209 minAddress.GetBytes(minAddrBuf);
210
211 // Get the latest leased address.
212 uint8_t lastLeasedAddrBuf[16];
213
214 if (!subnet.m_leasedAddresses.empty())
215 {
216 // Obtain the highest address that has been offered.
217 subnet.m_maxOfferedAddress.GetBytes(lastLeasedAddrBuf);
218 memcpy(offeredAddrBuf, lastLeasedAddrBuf, 16);
219
220 // Increment the address by adding 1. Bitwise addition is used.
221 bool addedOne = false;
222 for (uint8_t i = 15; !addedOne && i >= 0; i--)
223 {
224 for (int j = 0; j < 8; j++)
225 {
226 uint8_t bit = (offeredAddrBuf[i] & (1 << j)) >> j;
227 if (bit == 0)
228 {
229 offeredAddrBuf[i] = offeredAddrBuf[i] | (1 << j);
230 addedOne = true;
231 break;
232 }
233 offeredAddrBuf[i] = offeredAddrBuf[i] & ~(1 << j);
234 }
235 }
236 }
237 else
238 {
239 memcpy(offeredAddrBuf, minAddrBuf, 16);
240 }
241
242 Ipv6Address offer(offeredAddrBuf);
243 subnet.m_maxOfferedAddress = offer;
244
245 /*
246 Optimistic assumption that the address will be leased to this client.
247 This is to prevent multiple clients from receiving the same address.
248 */
249 subnet.m_leasedAddresses.insert(
250 {clientDuid, std::make_pair(offer, Seconds(m_prefLifetime.GetSeconds()))});
251 }
252
253 Ipv6Address offeredAddr(offeredAddrBuf);
254 NS_LOG_INFO("Offered address: " << offeredAddr);
255 NS_LOG_DEBUG("Offered address: " << offeredAddr);
256
257 for (const auto& iaid : requestedIa)
258 {
259 // Add the IA_NA option and IA Address option.
260 advertiseHeader.AddIanaOption(iaid, m_renew.GetSeconds(), m_rebind.GetSeconds());
261 advertiseHeader.AddAddress(iaid,
262 offeredAddr,
263 m_prefLifetime.GetSeconds(),
264 m_validLifetime.GetSeconds());
265 }
266 }
267
268 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
269 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
270 {
271 std::vector<Options::OptionType> requestedOptions =
273 advertiseHeader.HandleOptionRequest(requestedOptions);
274 }
275
276 packet->AddHeader(advertiseHeader);
277
278 // Find the socket corresponding to the NetDevice.
279 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
280 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
281 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
282
283 // Send the advertise message.
284 if (sendSocket->SendTo(packet, 0, client) >= 0)
285 {
286 NS_LOG_INFO("DHCPv6 Advertise sent.");
287 }
288 else
289 {
290 NS_LOG_INFO("Error while sending DHCPv6 Advertise.");
291 }
292}
293
294void
296{
297 NS_LOG_FUNCTION(this << iDev << header << client);
298
299 // Options included according to RFC 8415 Section 18.3.10
300
301 Ptr<Packet> packet = Create<Packet>();
302 Dhcp6Header replyHeader;
303 replyHeader.ResetOptions();
305 replyHeader.SetTransactId(header.GetTransactId());
306
307 // Add Client Identifier Option, copied from the received header.
308 Duid clientDuid = header.GetClientIdentifier().GetDuid();
309 replyHeader.AddClientIdentifier(clientDuid);
310
311 // Add Server Identifier Option.
313
314 // Add IA_NA option.
315 // Retrieve requested IA Option from client header.
316 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
317
318 for (auto& iaOpt : ianaOptionsList)
319 {
320 // Iterate through the offered addresses.
321 // Current approach: Try to accept all offers.
322 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
323 for (auto& addrItr : iaAddrOptList)
324 {
325 Ipv6Address requestedAddr = addrItr.GetIaAddress();
326
327 for (auto& subnet : m_subnets)
328 {
329 Ipv6Address pool = subnet.GetAddressPool();
330 Ipv6Prefix prefix = subnet.GetPrefix();
331 Ipv6Address minAddress = subnet.GetMinAddress();
332 Ipv6Address maxAddress = subnet.GetMaxAddress();
333
334 // Check if the requested address has been declined earlier.
335 // In this case, it cannot be leased.
336 if (subnet.m_declinedAddresses.find(requestedAddr) !=
337 subnet.m_declinedAddresses.end())
338 {
339 NS_LOG_INFO("Requested address" << requestedAddr << "is declined.");
340 return;
341 }
342
343 // Check whether this subnet matches the requested address.
344 if (prefix.IsMatch(requestedAddr, pool))
345 {
346 uint8_t minBuf[16];
347 uint8_t maxBuf[16];
348 uint8_t requestedBuf[16];
349 minAddress.GetBytes(minBuf);
350 maxAddress.GetBytes(maxBuf);
351 requestedAddr.GetBytes(requestedBuf);
352
353 if (memcmp(requestedBuf, minBuf, 16) < 0 ||
354 memcmp(requestedBuf, maxBuf, 16) > 0)
355 {
356 NS_LOG_INFO("Requested address is not in the range of the subnet.");
357 return;
358 }
359
360 // Add the IA_NA option and IA Address option.
361 replyHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
362 replyHeader.AddAddress(iaOpt.GetIaid(),
363 requestedAddr,
364 m_prefLifetime.GetSeconds(),
365 m_validLifetime.GetSeconds());
366
367 NS_LOG_DEBUG("Adding address " << requestedAddr << " to lease");
368 // Update the lease time of the newly leased addresses.
369 // Find all the leases for this client.
370 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
371
372 // Create a new multimap to store the updated lifetimes.
373 std::multimap<Duid, std::pair<Ipv6Address, Time>> updatedLifetimes;
374 for (auto it = range.first; it != range.second; it++)
375 {
376 Ipv6Address clientLease = it->second.first;
377 std::pair<Ipv6Address, Time> clientLeaseTime = {
378 clientLease,
379 Seconds(m_prefLifetime.GetSeconds())};
380
381 // Add the DUID + Ipv6Address / LeaseTime to the map.
382 updatedLifetimes.insert({clientDuid, clientLeaseTime});
383 }
384
385 // Remove all the old leases for this client.
386 // This is done to prevent multiple entries for the same lease.
387 subnet.m_leasedAddresses.erase(range.first->first);
388
389 // Add the updated leases to the subnet.
390 for (auto& itr : updatedLifetimes)
391 {
392 subnet.m_leasedAddresses.insert({itr.first, itr.second});
393 }
394 break;
395 }
396 }
397 }
398 }
399
400 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
401
402 // Check if the client has requested any options.
403 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
404 {
405 std::vector<Options::OptionType> requestedOptions =
407 replyHeader.HandleOptionRequest(requestedOptions);
408 }
409
410 packet->AddHeader(replyHeader);
411
412 // Find the socket corresponding to the NetDevice.
413 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
414 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
415 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
416
417 // Send the Reply message.
418 if (sendSocket->SendTo(packet, 0, client) >= 0)
419 {
420 NS_LOG_INFO("DHCPv6 Reply sent.");
421 }
422 else
423 {
424 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
425 }
426}
427
428void
430{
431 NS_LOG_FUNCTION(this << iDev << header << client);
432
433 // Options included according to RFC 8415 Section 18.3.4, 18.3.5
434
435 Ptr<Packet> packet = Create<Packet>();
436 Dhcp6Header replyHeader;
437 replyHeader.ResetOptions();
439 replyHeader.SetTransactId(header.GetTransactId());
440
441 // Add Client Identifier Option, copied from the received header.
442 Duid clientDuid = header.GetClientIdentifier().GetDuid();
443 replyHeader.AddClientIdentifier(clientDuid);
444
445 // Add Server Identifier Option.
447
448 // Add IA_NA option.
449 // Retrieve IA_NAs from client header.
450 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
451 for (auto& iaOpt : ianaOptionsList)
452 {
453 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
454
455 // Add the IA_NA option.
456 replyHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
457
458 for (const auto& addrItr : iaAddrOptList)
459 {
460 // Find the lease address which is to be renewed or rebound.
461 Ipv6Address clientLease = addrItr.GetIaAddress();
462
463 // Update the lifetime for the address.
464 // Iterate through the subnet list to find the subnet that the
465 // address belongs to.
466 for (auto& subnet : m_subnets)
467 {
468 Ipv6Prefix prefix = subnet.GetPrefix();
469 Ipv6Address pool = subnet.GetAddressPool();
470
471 // Check if the prefix of the lease matches that of the pool.
472 if (prefix.IsMatch(clientLease, pool))
473 {
474 // Find all the leases for this client.
475 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
476 for (auto itr = range.first; itr != range.second; itr++)
477 {
478 // Check if the IPv6 address matches the client lease.
479 if (itr->second.first == clientLease)
480 {
481 NS_LOG_DEBUG("Renewing address: " << itr->second.first);
482
483 std::pair<Ipv6Address, Time> clientLeaseTime = {
484 clientLease,
485 Seconds(m_prefLifetime.GetSeconds())};
486
487 // Remove the old lease information.
488 subnet.m_leasedAddresses.erase(itr);
489
490 // Add the new lease information (with updated time)
491 subnet.m_leasedAddresses.insert({clientDuid, clientLeaseTime});
492
493 // Add the IA Address option.
494 replyHeader.AddAddress(iaOpt.GetIaid(),
495 clientLease,
496 m_prefLifetime.GetSeconds(),
497 m_validLifetime.GetSeconds());
498 break;
499 }
500 }
501 }
502 }
503 }
504 }
505
506 std::map<Options::OptionType, bool> headerOptions = header.GetOptionList();
507 if (headerOptions.find(Options::OptionType::OPTION_ORO) != headerOptions.end())
508 {
509 std::vector<Options::OptionType> requestedOptions =
511 replyHeader.HandleOptionRequest(requestedOptions);
512 }
513
514 packet->AddHeader(replyHeader);
515
516 // Find the socket corresponding to the NetDevice.
517 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
518 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
519 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
520
521 // Send the Reply message.
522 if (sendSocket->SendTo(packet, 0, client) >= 0)
523 {
524 NS_LOG_INFO("DHCPv6 Reply sent.");
525 }
526 else
527 {
528 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
529 }
530}
531
532void
534{
535 // Invoked in case a Decline or Release message is received.
536 NS_LOG_FUNCTION(this << iDev << header << client);
537
538 // Options included in accordance with RFC 8415, Section 18.3.7, 18.3.8
539
540 Ptr<Packet> packet = Create<Packet>();
541 Dhcp6Header replyHeader;
542 replyHeader.ResetOptions();
544 replyHeader.SetTransactId(header.GetTransactId());
545
546 // Add Client Identifier Option, copied from the received header.
547 Duid clientDuid = header.GetClientIdentifier().GetDuid();
548 replyHeader.AddClientIdentifier(clientDuid);
549
550 // Add Server Identifier Option.
552
553 // Add Status code option.
554 replyHeader.AddStatusCode(Options::StatusCodeValues::Success, "Address declined.");
555
556 // Add the declined or expired address to the subnet information.
557 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
558 for (const auto& iaOpt : ianaOptionsList)
559 {
560 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
561
562 for (const auto& addrItr : iaAddrOptList)
563 {
564 Ipv6Address address = addrItr.GetIaAddress();
566 {
567 // Find the subnet that this address belongs to.
568 for (auto& subnet : m_subnets)
569 {
570 // Find the client that the address currently belongs to.
571
572 for (auto itr = subnet.m_leasedAddresses.begin();
573 itr != subnet.m_leasedAddresses.end();)
574 {
575 Ipv6Address leaseAddr = itr->second.first;
576 if (leaseAddr == address)
577 {
578 itr = subnet.m_leasedAddresses.erase(itr);
579 subnet.m_declinedAddresses[address] = clientDuid;
580 continue;
581 }
582 itr++;
583 }
584 }
585 }
587 {
588 // Find the subnet that this address belongs to.
589 for (auto& subnet : m_subnets)
590 {
591 // Find the client that the address currently belongs to.
592
593 for (auto itr = subnet.m_leasedAddresses.begin();
594 itr != subnet.m_leasedAddresses.end();)
595 {
596 Duid duid = itr->first;
597 Ipv6Address leaseAddr = itr->second.first;
598 Time expiredTime = itr->second.second;
599 if (leaseAddr == address)
600 {
601 itr = subnet.m_leasedAddresses.erase(itr);
602 std::pair<Duid, Ipv6Address> expiredLease = {duid, leaseAddr};
603 subnet.m_expiredAddresses.insert({expiredTime, expiredLease});
604 continue;
605 }
606 itr++;
607 }
608 }
609 }
610 }
611 }
612
613 packet->AddHeader(replyHeader);
614
615 // Find the socket corresponding to the NetDevice.
616 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
617 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
618 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
619
620 // Send the Reply message.
621 if (sendSocket->SendTo(packet, 0, client) >= 0)
622 {
623 NS_LOG_INFO("DHCPv6 Reply sent.");
624 }
625 else
626 {
627 NS_LOG_INFO("Error while sending DHCPv6 Reply.");
628 }
629}
630
631void
633{
634 for (auto itr = netDevices.Begin(); itr != netDevices.End(); itr++)
635 {
636 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
637 int32_t ifIndex = ipv6->GetInterfaceForDevice(*itr);
638 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
639 m_sendSockets[ifIndex] = nullptr;
640 }
641}
642
643void
645{
646 NS_LOG_FUNCTION(this << socket);
647
648 Dhcp6Header header;
649 Address from;
650 Ptr<Packet> packet = m_recvSocket->RecvFrom(from);
651
653
654 Ipv6PacketInfoTag interfaceInfo;
655 NS_ASSERT_MSG(packet->RemovePacketTag(interfaceInfo),
656 "No incoming interface on DHCPv6 message.");
657
658 uint32_t incomingIf = interfaceInfo.GetRecvIf();
659 Ptr<NetDevice> iDev = GetNode()->GetDevice(incomingIf);
660
661 if (packet->RemoveHeader(header) == 0)
662 {
663 return;
664 }
665
666 // Initialize the DUID before responding to the client.
667 Ptr<Node> node = GetNode();
668 m_serverDuid.Initialize(node);
669
671 {
672 ProcessSolicit(iDev, header, senderAddr);
673 SendAdvertise(iDev, header, senderAddr);
674 }
676 {
677 SendReply(iDev, header, senderAddr);
678 }
681 {
682 RenewRebindLeases(iDev, header, senderAddr);
683 }
686 {
687 UpdateBindings(iDev, header, senderAddr);
688 }
689}
690
691void
693 Ipv6Prefix prefix,
694 Ipv6Address minAddress,
695 Ipv6Address maxAddress)
696{
697 NS_LOG_FUNCTION(this << addressPool << prefix << minAddress << maxAddress);
698
699 NS_LOG_DEBUG("DHCPv6 server: Adding subnet " << addressPool << " to lease information.");
700 LeaseInfo newSubnet(addressPool, prefix, minAddress, maxAddress);
701 m_subnets.emplace_back(newSubnet);
702}
703
704void
706{
707 Ptr<Node> node = GetNode();
708 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
709 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
710
711 for (auto itr = m_sendSockets.begin(); itr != m_sendSockets.end(); itr++)
712 {
713 uint32_t ifIndex = itr->first;
714 Ptr<NetDevice> device = GetNode()->GetDevice(ifIndex);
715 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
716
717 if (ifIndex == recvInterface)
718 {
719 Ipv6Address linkLocal =
720 ipv6l3->GetInterface(ifIndex)->GetLinkLocalAddress().GetAddress();
721
722 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
723
724 Ptr<Socket> socket = Socket::CreateSocket(node, tid);
725 socket->Bind(Inet6SocketAddress(linkLocal, Dhcp6Header::SERVER_PORT));
726 socket->BindToNetDevice(device);
727 socket->SetRecvPktInfo(true);
728 socket->SetRecvCallback(MakeCallback(&Dhcp6Server::NetHandler, this));
729
730 m_sendSockets[ifIndex] = socket;
731 }
732 }
733}
734
735void
737{
738 NS_LOG_INFO("Starting DHCPv6 server.");
739
740 if (m_recvSocket)
741 {
742 NS_LOG_INFO("DHCPv6 daemon is not meant to be started repeatedly.");
743 return;
744 }
745
746 Ptr<Node> node = GetNode();
747 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
748 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
749
750 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
752
753 Inet6SocketAddress local =
755 m_recvSocket->Bind(local);
756 m_recvSocket->SetRecvPktInfo(true);
757 m_recvSocket->SetRecvCallback(MakeCallback(&Dhcp6Server::NetHandler, this));
758
759 for (auto itr = m_sendSockets.begin(); itr != m_sendSockets.end(); itr++)
760 {
761 int32_t ifIndex = itr->first;
762 Ptr<NetDevice> iDev = GetNode()->GetDevice(ifIndex);
763 Ptr<Socket> sendSocket = m_sendSockets[ifIndex];
764
765 NS_LOG_DEBUG("DHCPv6 server: Node " << node->GetId() << " listening on interface "
766 << ifIndex);
767
768 NS_ASSERT_MSG(ifIndex >= 0,
769 "Dhcp6Server::StartApplication: device is not connected to IPv6.");
770
772 ipv6->GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber(), ifIndex));
773
774 icmpv6->SetDhcpv6Callback(MakeCallback(&Dhcp6Server::ReceiveMflag, this));
775 }
776
778}
779
780void
785
786void
788{
789 NS_LOG_DEBUG("Cleaning up leases.");
790 for (auto& subnet : m_subnets)
791 {
792 for (auto itr = subnet.m_leasedAddresses.begin(); itr != subnet.m_leasedAddresses.end();)
793 {
794 Duid duid = itr->first;
795 Ipv6Address address = itr->second.first;
796 Time leaseTime = itr->second.second;
797
798 if (Simulator::Now() >= leaseTime)
799 {
800 NS_LOG_DEBUG("DHCPv6 server: Removing expired lease for " << address);
801 std::pair<Duid, Ipv6Address> expiredLease = {duid, address};
802 subnet.m_expiredAddresses.insert({leaseTime, expiredLease});
803 itr = subnet.m_leasedAddresses.erase(itr);
804 continue;
805 }
806 itr++;
807 }
808 }
809
811}
812
814 Ipv6Prefix prefix,
815 Ipv6Address minAddress,
816 Ipv6Address maxAddress)
817{
818 m_addressPool = addressPool;
819 m_prefix = prefix;
820 m_minAddress = minAddress;
821 m_maxAddress = maxAddress;
822 m_numAddresses = 0;
823}
824
827{
828 return m_addressPool;
829}
830
833{
834 return m_prefix;
835}
836
839{
840 return m_minAddress;
841}
842
845{
846 return m_maxAddress;
847}
848
851{
852 return m_numAddresses;
853}
854} // namespace ns3
a polymophic address class
Definition address.h:111
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
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
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:511
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:67
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
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:96
AttributeValue implementation for Time.
Definition nstime.h:1456
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:1457
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1477
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:439
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
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:585