14#include "ns3/address-utils.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"
23#include "ns3/loopback-net-device.h"
24#include "ns3/simulator.h"
25#include "ns3/socket.h"
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).",
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).",
55 .AddAttribute(
"PreferredLifetime",
56 "The preferred lifetime of the leased address. "
57 "3000 seconds by default in Linux.",
61 .AddAttribute(
"ValidLifetime",
62 "Time after which client should release the address. "
63 "4000 seconds by default in Linux.",
67 .AddAttribute(
"DuidType",
68 "Configure the type of DUID used by the server.",
79 .AddAttribute(
"DuidEnIdentifierLength",
80 "Length of the identifier of the DUID-EN.",
105 itr.m_leasedAddresses.clear();
106 itr.m_expiredAddresses.clear();
107 itr.m_declinedAddresses.clear();
134 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
140 for (
const auto& itr : iaOpt)
145 NS_LOG_DEBUG(
"DHCPv6 server: Client registering IAID " << iaid);
172 std::vector<uint32_t> requestedIa(ianaOptionsList.size());
173 for (std::size_t i = 0; i < ianaOptionsList.size(); i++)
175 requestedIa[i] = ianaOptionsList[i].GetIaid();
187 uint8_t offeredAddrBuf[16];
189 bool foundAddress =
false;
190 if (!subnet.m_expiredAddresses.empty())
194 for (
auto itr = subnet.m_expiredAddresses.begin();
195 itr != subnet.m_expiredAddresses.end();)
197 if (itr->second.first == clientDuid)
199 nextAddress = itr->second.second;
200 nextAddress.
GetBytes(offeredAddrBuf);
201 itr = subnet.m_expiredAddresses.erase(itr);
213 if (!foundAddress && subnet.m_expiredAddresses.size() > 30)
215 auto firstExpiredAddress = subnet.m_expiredAddresses.begin();
216 nextAddress = firstExpiredAddress->second.second;
217 nextAddress.
GetBytes(offeredAddrBuf);
218 subnet.m_expiredAddresses.erase(firstExpiredAddress);
226 uint8_t minAddrBuf[16];
231 uint8_t lastLeasedAddrBuf[16];
233 if (!subnet.m_leasedAddresses.empty())
236 subnet.m_maxOfferedAddress.GetBytes(lastLeasedAddrBuf);
237 memcpy(offeredAddrBuf, lastLeasedAddrBuf, 16);
240 bool addedOne =
false;
241 for (uint8_t i = 15; !addedOne && i >= 0; i--)
243 for (
int j = 0; j < 8; j++)
245 uint8_t bit = (offeredAddrBuf[i] & (1 << j)) >> j;
248 offeredAddrBuf[i] = offeredAddrBuf[i] | (1 << j);
252 offeredAddrBuf[i] = offeredAddrBuf[i] & ~(1 << j);
258 memcpy(offeredAddrBuf, minAddrBuf, 16);
262 subnet.m_maxOfferedAddress = offer;
268 subnet.m_leasedAddresses.insert(
276 for (
const auto& iaid : requestedIa)
287 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
290 std::vector<Options::OptionType> requestedOptions =
295 packet->AddHeader(advertiseHeader);
299 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
303 if (sendSocket->SendTo(packet, 0, client) >= 0)
309 NS_LOG_INFO(
"Error while sending DHCPv6 Advertise.");
337 for (
auto& iaOpt : ianaOptionsList)
341 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
342 for (
auto& addrItr : iaAddrOptList)
344 Ipv6Address requestedAddr = addrItr.GetIaAddress();
355 if (subnet.m_declinedAddresses.find(requestedAddr) !=
356 subnet.m_declinedAddresses.end())
358 NS_LOG_INFO(
"Requested address" << requestedAddr <<
"is declined.");
363 if (prefix.
IsMatch(requestedAddr, pool))
367 uint8_t requestedBuf[16];
370 requestedAddr.
GetBytes(requestedBuf);
372 if (memcmp(requestedBuf, minBuf, 16) < 0 ||
373 memcmp(requestedBuf, maxBuf, 16) > 0)
375 NS_LOG_INFO(
"Requested address is not in the range of the subnet.");
380 replyHeader.
AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
386 NS_LOG_DEBUG(
"Adding address " << requestedAddr <<
" to lease");
389 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
392 std::multimap<Duid, std::pair<Ipv6Address, Time>> updatedLifetimes;
393 for (
auto it = range.first; it != range.second; it++)
396 std::pair<Ipv6Address, Time> clientLeaseTime = {
401 updatedLifetimes.insert({clientDuid, clientLeaseTime});
406 subnet.m_leasedAddresses.erase(range.first->first);
409 for (
auto& itr : updatedLifetimes)
411 subnet.m_leasedAddresses.insert({itr.first, itr.second});
419 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
424 std::vector<Options::OptionType> requestedOptions =
429 packet->AddHeader(replyHeader);
433 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
437 if (sendSocket->SendTo(packet, 0, client) >= 0)
470 for (
auto& iaOpt : ianaOptionsList)
472 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
475 replyHeader.
AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
477 for (
const auto& addrItr : iaAddrOptList)
491 if (prefix.
IsMatch(clientLease, pool))
494 auto range = subnet.m_leasedAddresses.equal_range(clientDuid);
495 for (
auto itr = range.first; itr != range.second; itr++)
498 if (itr->second.first == clientLease)
500 NS_LOG_DEBUG(
"Renewing address: " << itr->second.first);
502 std::pair<Ipv6Address, Time> clientLeaseTime = {
507 subnet.m_leasedAddresses.erase(itr);
510 subnet.m_leasedAddresses.insert({clientDuid, clientLeaseTime});
525 std::map<Options::OptionType, bool> headerOptions = header.
GetOptionList();
528 std::vector<Options::OptionType> requestedOptions =
533 packet->AddHeader(replyHeader);
537 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
541 if (sendSocket->SendTo(packet, 0, client) >= 0)
577 for (
const auto& iaOpt : ianaOptionsList)
579 std::vector<IaAddressOption> iaAddrOptList = iaOpt.m_iaAddressOption;
581 for (
const auto& addrItr : iaAddrOptList)
591 for (
auto itr = subnet.m_leasedAddresses.begin();
592 itr != subnet.m_leasedAddresses.end();)
595 if (leaseAddr == address)
597 itr = subnet.m_leasedAddresses.erase(itr);
598 subnet.m_declinedAddresses[address] = clientDuid;
612 for (
auto itr = subnet.m_leasedAddresses.begin();
613 itr != subnet.m_leasedAddresses.end();)
615 Duid duid = itr->first;
617 Time expiredTime = itr->second.second;
618 if (leaseAddr == address)
620 itr = subnet.m_leasedAddresses.erase(itr);
621 std::pair<Duid, Ipv6Address> expiredLease = {duid, leaseAddr};
622 subnet.m_expiredAddresses.insert({expiredTime, expiredLease});
632 packet->AddHeader(replyHeader);
636 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
640 if (sendSocket->SendTo(packet, 0, client) >= 0)
653 for (
auto itr = netDevices.
Begin(); itr != netDevices.
End(); itr++)
656 int32_t ifIndex = ipv6->GetInterfaceForDevice(*itr);
675 "No incoming interface on DHCPv6 message.");
680 if (packet->RemoveHeader(header) == 0)
712 NS_LOG_FUNCTION(
this << addressPool << prefix << minAddress << maxAddress);
714 NS_LOG_DEBUG(
"DHCPv6 server: Adding subnet " << addressPool <<
" to lease information.");
715 LeaseInfo newSubnet(addressPool, prefix, minAddress, maxAddress);
732 if (ifIndex == recvInterface)
735 ipv6l3->GetInterface(ifIndex)->GetLinkLocalAddress().GetAddress();
741 socket->BindToNetDevice(device);
742 socket->SetRecvPktInfo(
true);
757 NS_LOG_INFO(
"DHCPv6 daemon is not meant to be started repeatedly.");
780 NS_LOG_DEBUG(
"DHCPv6 server: Node " << node->GetId() <<
" listening on interface "
784 "Dhcp6Server::StartApplication: device is not connected to IPv6.");
820 for (
auto itr = subnet.m_leasedAddresses.begin(); itr != subnet.m_leasedAddresses.end();)
822 Duid duid = itr->first;
824 Time leaseTime = itr->second.second;
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);
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
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.
Hold variables of type enum.
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.
Hold a signed integer type.
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 > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeIntegerChecker()
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
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... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
#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.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.