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"
21#include "ns3/loopback-net-device.h"
22#include "ns3/simulator.h"
23#include "ns3/socket.h"
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).",
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).",
53 .AddAttribute(
"PreferredLifetime",
54 "The preferred lifetime of the leased address. "
55 "3000 seconds by default in Linux.",
59 .AddAttribute(
"ValidLifetime",
60 "Time after which client should release the address. "
61 "4000 seconds by default in Linux.",
86 itr.m_leasedAddresses.clear();
87 itr.m_expiredAddresses.clear();
88 itr.m_declinedAddresses.clear();
115 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
121 for (
const auto& itr : iaOpt)
126 NS_LOG_DEBUG(
"DHCPv6 server: Client registering IAID " << iaid);
153 std::vector<uint32_t> requestedIa(ianaOptionsList.size());
154 for (std::size_t i = 0; i < ianaOptionsList.size(); i++)
156 requestedIa[i] = ianaOptionsList[i].GetIaid();
168 uint8_t offeredAddrBuf[16];
170 bool foundAddress =
false;
171 if (!subnet.m_expiredAddresses.empty())
175 for (
auto itr = subnet.m_expiredAddresses.begin();
176 itr != subnet.m_expiredAddresses.end();)
178 if (itr->second.first == clientDuid)
180 nextAddress = itr->second.second;
181 nextAddress.
GetBytes(offeredAddrBuf);
182 itr = subnet.m_expiredAddresses.erase(itr);
194 if (!foundAddress && subnet.m_expiredAddresses.size() > 30)
196 auto firstExpiredAddress = subnet.m_expiredAddresses.begin();
197 nextAddress = firstExpiredAddress->second.second;
198 nextAddress.
GetBytes(offeredAddrBuf);
199 subnet.m_expiredAddresses.erase(firstExpiredAddress);
207 uint8_t minAddrBuf[16];
212 uint8_t lastLeasedAddrBuf[16];
214 if (!subnet.m_leasedAddresses.empty())
217 subnet.m_maxOfferedAddress.GetBytes(lastLeasedAddrBuf);
218 memcpy(offeredAddrBuf, lastLeasedAddrBuf, 16);
221 bool addedOne =
false;
222 for (uint8_t i = 15; !addedOne && i >= 0; i--)
224 for (
int j = 0; j < 8; j++)
226 uint8_t bit = (offeredAddrBuf[i] & (1 << j)) >> j;
229 offeredAddrBuf[i] = offeredAddrBuf[i] | (1 << j);
233 offeredAddrBuf[i] = offeredAddrBuf[i] & ~(1 << j);
239 memcpy(offeredAddrBuf, minAddrBuf, 16);
243 subnet.m_maxOfferedAddress = offer;
249 subnet.m_leasedAddresses.insert(
257 for (
const auto& iaid : requestedIa)
268 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
271 std::vector<Options::OptionType> requestedOptions =
276 packet->AddHeader(advertiseHeader);
280 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
284 if (sendSocket->SendTo(packet, 0, client) >= 0)
290 NS_LOG_INFO(
"Error while sending DHCPv6 Advertise.");
318 for (
auto& iaOpt : ianaOptionsList)
322 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
323 for (
auto& addrItr : iaAddrOptList)
325 Ipv6Address requestedAddr = addrItr.GetIaAddress();
336 if (subnet.m_declinedAddresses.find(requestedAddr) !=
337 subnet.m_declinedAddresses.end())
339 NS_LOG_INFO(
"Requested address" << requestedAddr <<
"is declined.");
344 if (prefix.
IsMatch(requestedAddr, pool))
348 uint8_t requestedBuf[16];
351 requestedAddr.
GetBytes(requestedBuf);
353 if (memcmp(requestedBuf, minBuf, 16) < 0 ||
354 memcmp(requestedBuf, maxBuf, 16) > 0)
356 NS_LOG_INFO(
"Requested address is not in the range of the subnet.");
361 replyHeader.
AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
367 NS_LOG_DEBUG(
"Adding address " << requestedAddr <<
" to lease");
370 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
373 std::multimap<Duid, std::pair<Ipv6Address, Time>> updatedLifetimes;
374 for (
auto it = range.first; it != range.second; it++)
377 std::pair<Ipv6Address, Time> clientLeaseTime = {
382 updatedLifetimes.insert({clientDuid, clientLeaseTime});
387 subnet.m_leasedAddresses.erase(range.first->first);
390 for (
auto& itr : updatedLifetimes)
392 subnet.m_leasedAddresses.insert({itr.first, itr.second});
400 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
405 std::vector<Options::OptionType> requestedOptions =
410 packet->AddHeader(replyHeader);
414 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
418 if (sendSocket->SendTo(packet, 0, client) >= 0)
451 for (
auto& iaOpt : ianaOptionsList)
453 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
456 replyHeader.
AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
458 for (
const auto& addrItr : iaAddrOptList)
472 if (prefix.
IsMatch(clientLease, pool))
475 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
476 for (
auto itr = range.first; itr != range.second; itr++)
479 if (itr->second.first == clientLease)
481 NS_LOG_DEBUG(
"Renewing address: " << itr->second.first);
483 std::pair<Ipv6Address, Time> clientLeaseTime = {
488 subnet.m_leasedAddresses.erase(itr);
491 subnet.m_leasedAddresses.insert({clientDuid, clientLeaseTime});
506 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
509 std::vector<Options::OptionType> requestedOptions =
514 packet->AddHeader(replyHeader);
518 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
522 if (sendSocket->SendTo(packet, 0, client) >= 0)
558 for (
const auto& iaOpt : ianaOptionsList)
560 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
562 for (
const auto& addrItr : iaAddrOptList)
572 for (
auto itr = subnet.m_leasedAddresses.begin();
573 itr != subnet.m_leasedAddresses.end();)
576 if (leaseAddr == address)
578 itr = subnet.m_leasedAddresses.erase(itr);
579 subnet.m_declinedAddresses[address] = clientDuid;
593 for (
auto itr = subnet.m_leasedAddresses.begin();
594 itr != subnet.m_leasedAddresses.end();)
596 Duid duid = itr->first;
598 Time expiredTime = itr->second.second;
599 if (leaseAddr == address)
601 itr = subnet.m_leasedAddresses.erase(itr);
602 std::pair<Duid, Ipv6Address> expiredLease = {duid, leaseAddr};
603 subnet.m_expiredAddresses.insert({expiredTime, expiredLease});
613 packet->AddHeader(replyHeader);
617 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
621 if (sendSocket->SendTo(packet, 0, client) >= 0)
634 for (
auto itr = netDevices.
Begin(); itr != netDevices.
End(); itr++)
637 int32_t ifIndex = ipv6->GetInterfaceForDevice(*itr);
656 "No incoming interface on DHCPv6 message.");
661 if (packet->RemoveHeader(header) == 0)
697 NS_LOG_FUNCTION(
this << addressPool << prefix << minAddress << maxAddress);
699 NS_LOG_DEBUG(
"DHCPv6 server: Adding subnet " << addressPool <<
" to lease information.");
700 LeaseInfo newSubnet(addressPool, prefix, minAddress, maxAddress);
717 if (ifIndex == recvInterface)
720 ipv6l3->GetInterface(ifIndex)->GetLinkLocalAddress().GetAddress();
726 socket->BindToNetDevice(device);
727 socket->SetRecvPktInfo(
true);
742 NS_LOG_INFO(
"DHCPv6 daemon is not meant to be started repeatedly.");
765 NS_LOG_DEBUG(
"DHCPv6 server: Node " << node->GetId() <<
" listening on interface "
769 "Dhcp6Server::StartApplication: device is not connected to IPv6.");
792 for (
auto itr = subnet.m_leasedAddresses.begin(); itr != subnet.m_leasedAddresses.end();)
794 Duid duid = itr->first;
796 Time leaseTime = itr->second.second;
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);
a polymophic address class
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
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.
static uint16_t GetStaticProtocolNumber()
Get ICMPv6 protocol number.
Duid GetDuid() const
Get the DUID object.
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.
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.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
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.
static Time Now()
Return the current simulation virtual time.
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...
Simulation virtual time values and global simulation resolution.
AttributeValue implementation for Time.
a unique identifier for an interface.
static TypeId LookupByName(std::string name)
Get a TypeId by name.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Callback< R, Args... > MakeNullCallback()
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#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.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Seconds(double value)
Construct a Time in the indicated unit.
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...
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.