14#include "ns3/address-utils.h"
16#include "ns3/icmpv6-l4-protocol.h"
17#include "ns3/ipv6-interface.h"
18#include "ns3/ipv6-l3-protocol.h"
19#include "ns3/ipv6-packet-info-tag.h"
22#include "ns3/loopback-net-device.h"
23#include "ns3/mac48-address.h"
24#include "ns3/net-device-container.h"
25#include "ns3/object.h"
26#include "ns3/pointer.h"
28#include "ns3/random-variable-stream.h"
29#include "ns3/simulator.h"
30#include "ns3/socket.h"
31#include "ns3/string.h"
32#include "ns3/trace-source-accessor.h"
33#include "ns3/traced-value.h"
34#include "ns3/trickle-timer.h"
49 .AddConstructor<Dhcp6Client>()
50 .SetGroupName(
"InternetApps")
51 .AddAttribute(
"Transactions",
52 "A value to be used as the transaction ID.",
53 StringValue(
"ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"),
56 .AddAttribute(
"SolicitJitter",
57 "The jitter in ms that a node waits before sending any solicitation. By "
58 "default, the model will wait for a duration in ms defined by a uniform "
59 "random-variable between 0 and SolicitJitter. This is equivalent to"
60 "SOL_MAX_DELAY (RFC 8415, Section 7.6).",
61 StringValue(
"ns3::UniformRandomVariable[Min=0.0|Max=1000.0]"),
64 .AddAttribute(
"IaidValue",
65 "The identifier for a new IA created by a client.",
66 StringValue(
"ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"),
69 .AddAttribute(
"SolicitInterval",
70 "Time after which the client resends the Solicit."
71 "Equivalent to SOL_MAX_RT (RFC 8415, Section 7.6)",
75 .AddAttribute(
"DuidType",
76 "Configure the type of DUID used by the client.",
87 .AddAttribute(
"DuidEnIdentifierLength",
88 "Length of the identifier of the DUID-EN.",
92 .AddTraceSource(
"NewLease",
93 "The client has obtained a lease",
95 "ns3::Ipv6Address::TracedCallback");
111 itr.second->Cleanup();
112 itr.second =
nullptr;
135 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
139 if (clientTransactId != receivedTransactId)
163 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
177 (
Simulator::Now() - dhcpInterface->m_msgStartTime).GetMilliSeconds() / 10;
178 uint16_t elapsed = actualElapsedTime > 65535 ? 65535 : actualElapsedTime;
185 for (
const auto& iaOpt : ianaOptionsList)
189 for (
const auto& iaAddrOpt : iaOpt.m_iaAddressOption)
191 requestHeader.
AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
193 iaAddrOpt.GetIaAddress(),
194 iaAddrOpt.GetPreferredLifetime(),
195 iaAddrOpt.GetValidLifetime());
197 NS_LOG_DEBUG(
"Requesting " << iaAddrOpt.GetIaAddress());
204 packet->AddHeader(requestHeader);
210 if (dhcpInterface->m_socket->SendTo(
219 NS_LOG_INFO(
"DHCPv6 client: Error while sending Request.");
259 if (addr == offeredAddress)
271 m_client->m_newLease(offeredAddress);
278 NS_LOG_DEBUG(
"Address to be declined " << offeredAddress);
284 if (addr == offeredAddress)
347 packet->AddHeader(declineHeader);
357 NS_LOG_INFO(
"DHCPv6 client: Error while sending Decline");
370 releaseEvent.Cancel();
412 NS_LOG_DEBUG(
"Received status " << (uint16_t)statusCode <<
" from DHCPv6 server");
415 NS_LOG_INFO(
"DHCPv6 client: Server bindings updated successfully.");
419 NS_LOG_INFO(
"DHCPv6 client: Server bindings update failed.");
429 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
436 dhcpInterface->m_declinedAddresses.clear();
440 std::vector<uint32_t> iaidList;
442 for (
const auto& iaOpt : ianaOptionsList)
446 for (
const auto& iaAddrOpt : iaOpt.m_iaAddressOption)
448 Ipv6Address offeredAddress = iaAddrOpt.GetIaAddress();
452 ipv6->AddAddress(ifIndex, addr);
453 ipv6->SetUp(ifIndex);
456 dhcpInterface->m_prefLifetime =
Seconds(iaAddrOpt.GetPreferredLifetime());
457 dhcpInterface->m_validLifetime =
Seconds(iaAddrOpt.GetValidLifetime());
460 m_iaidMap[offeredAddress] = iaOpt.GetIaid();
463 dhcpInterface->m_releaseEvent.emplace_back(
469 dhcpInterface->m_offeredAddresses.push_back(offeredAddress);
472 earliestRenew = std::min(earliestRenew,
Seconds(iaOpt.GetT1()));
473 earliestRebind = std::min(earliestRebind,
Seconds(iaOpt.GetT2()));
474 iaidList.emplace_back(iaOpt.GetIaid());
479 dhcpInterface->m_renewTime = earliestRenew;
480 dhcpInterface->m_renewEvent.Cancel();
481 dhcpInterface->m_renewEvent =
485 dhcpInterface->m_rebindTime = earliestRebind;
486 dhcpInterface->m_rebindEvent.Cancel();
487 dhcpInterface->m_rebindEvent =
490 int32_t interfaceId = ipv6->GetInterfaceForDevice(iDev);
496 if (!dhcpInterface->m_acceptedAddressCb.has_value())
498 dhcpInterface->m_acceptedAddressCb =
500 icmpv6->TraceConnectWithoutContext(
"DadSuccess",
501 dhcpInterface->m_acceptedAddressCb.value());
504 if (!dhcpInterface->m_declinedAddressCb.has_value())
506 dhcpInterface->m_declinedAddressCb =
508 icmpv6->TraceConnectWithoutContext(
"DadFailure",
509 dhcpInterface->m_declinedAddressCb.value());
537 for (
const auto& iaidRenew :
m_interfaces[dhcpInterfaceIndex]->m_iaids)
540 m_interfaces[dhcpInterfaceIndex]->m_renewTime.GetSeconds(),
541 m_interfaces[dhcpInterfaceIndex]->m_rebindTime.GetSeconds());
549 if (iaid == iaidRenew)
553 m_interfaces[dhcpInterfaceIndex]->m_prefLifetime.GetSeconds(),
554 m_interfaces[dhcpInterfaceIndex]->m_validLifetime.GetSeconds());
558 NS_LOG_DEBUG(
"Renewing addresses in IAID " << iaidRenew);
564 packet->AddHeader(header);
565 if ((
m_interfaces[dhcpInterfaceIndex]->m_socket->SendTo(
575 NS_LOG_INFO(
"DHCPv6 client: Error while sending Renew");
602 for (
const auto& iaid :
m_interfaces[dhcpInterfaceIndex]->m_iaids)
605 m_interfaces[dhcpInterfaceIndex]->m_renewTime.GetSeconds(),
606 m_interfaces[dhcpInterfaceIndex]->m_rebindTime.GetSeconds());
614 packet->AddHeader(header);
615 if ((
m_interfaces[dhcpInterfaceIndex]->m_socket->SendTo(
625 NS_LOG_INFO(
"DHCPv6 client: Error while sending Rebind");
647 bool removed = ipv6->RemoveAddress(ifIndex, address);
654 header.SetTransactId(dhcpInterface->m_transactId);
661 header.AddServerIdentifier(dhcpInterface->m_serverDuid);
664 header.AddElapsedTime(0);
668 header.AddIanaOption(iaid,
669 dhcpInterface->m_renewTime.GetSeconds(),
670 dhcpInterface->m_rebindTime.GetSeconds());
671 header.AddAddress(iaid,
673 dhcpInterface->m_prefLifetime.GetSeconds(),
674 dhcpInterface->m_validLifetime.GetSeconds());
678 packet->AddHeader(header);
679 if ((dhcpInterface->m_socket->SendTo(packet,
688 NS_LOG_INFO(
"DHCPv6 client: Error while sending Release");
708 "No incoming interface on DHCPv6 message.");
713 uint32_t iIf = ipv6->GetInterfaceForDevice(iDev);
716 if (packet->RemoveHeader(header) == 0 || !dhcpInterface)
724 dhcpInterface->m_solicitTimer.Stop();
736 dhcpInterface->m_renewEvent.Cancel();
737 dhcpInterface->m_rebindEvent.Cancel();
738 for (
auto itr : dhcpInterface->m_releaseEvent)
766 dhcpInterface->Cleanup();
783 NS_ASSERT_MSG(node,
"Dhcp6Client::StartApplication: cannot get the node from the device.");
786 NS_ASSERT_MSG(ipv6,
"Dhcp6Client::StartApplication: node does not have IPv6.");
788 NS_LOG_DEBUG(
"Starting DHCPv6 application on node " << node->GetId());
791 uint32_t nInterfaces = ipv6->GetNInterfaces();
794 for (
uint32_t ifIndex = 1; ifIndex < nInterfaces; ifIndex++)
817 dhcpInterface->m_client =
this;
818 dhcpInterface->m_interfaceIndex = recvInterface;
819 dhcpInterface->m_socket =
nullptr;
824 std::vector<uint32_t> existingIaNaIds;
828 if (std::find(existingIaNaIds.begin(), existingIaNaIds.end(), iaid) ==
829 existingIaNaIds.end())
831 dhcpInterface->m_iaids.push_back(iaid);
832 existingIaNaIds.emplace_back(iaid);
839 ipv6Interface->TraceConnectWithoutContext(
852 if (interface == recvInterface &&
m_interfaces[interface])
857 ipv6l3->GetInterface(interface)->GetLinkLocalAddress().GetAddress();
862 socket->BindToNetDevice(device);
863 socket->SetRecvPktInfo(
true);
877 dhcpInterface->m_solicitTimer.Enable();
888 int32_t ifIndex = ipv6->GetInterfaceForDevice(device);
922 for (
auto iaid : dhcpInterface->m_iaids)
925 dhcpInterface->m_renewTime.GetSeconds(),
926 dhcpInterface->m_rebindTime.GetSeconds());
929 packet->AddHeader(header);
931 if ((dhcpInterface->m_socket->SendTo(packet,
940 NS_LOG_INFO(
"DHCPv6 client: Error while sending Solicit");
958 itr.second->Cleanup();
a polymophic address class
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
State m_state
The DHCPv6 state of the client interface.
void DeclineOffer()
Send a Decline message to the DHCPv6 server.
Ptr< Dhcp6Client > m_client
The Dhcp6Client on which the interface is present.
Time m_msgStartTime
Time when message exchange starts.
uint8_t m_nAcceptedAddresses
Number of addresses accepted by client.
Time m_prefLifetime
Preferred lifetime of the address.
std::vector< Ipv6Address > m_declinedAddresses
List of addresses to be declined by the client.
std::optional< Callback< void, const Ipv6Address & > > m_declinedAddressCb
Callback for the declined addresses - needed for cleanup.
Time m_rebindTime
REB_MAX_RT, Time after which client should send a Rebind message.
~InterfaceConfig()
Destructor.
Duid m_serverDuid
The server DUID.
Ptr< Socket > m_socket
The socket that has been opened for this interface.
void AcceptedAddress(const Ipv6Address &offeredAddress)
Accept the DHCPv6 offer.
std::vector< Ipv6Address > m_offeredAddresses
List of addresses offered to the client.
std::vector< uint32_t > m_iaids
The IAIDs associated with this DHCPv6 client interface.
EventId m_rebindEvent
Event ID for the rebind event.
uint32_t m_transactId
Transaction ID of the client-initiated message.
EventId m_renewEvent
Event ID for the Renew event.
InterfaceConfig()
The default constructor.
std::optional< Callback< void, const Ipv6Address & > > m_acceptedAddressCb
Callback for the accepted addresses - needed for cleanup.
void DeclinedAddress(const Ipv6Address &offeredAddress)
Add a declined address to the list maintained by the client.
TrickleTimer m_solicitTimer
TrickleTimer to schedule Solicit messages.
void Cleanup()
Cleanup the internal callbacks and timers.
Time m_renewTime
REN_MAX_RT, Time after which lease should be renewed.
std::vector< EventId > m_releaseEvent
Store all the Event IDs for the addresses being Released.
uint32_t m_interfaceIndex
The IPv6 interface index of this configuration.
Time m_validLifetime
Valid lifetime of the address.
void CheckLeaseStatus(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress server) const
Check lease status after sending a Decline or Release message.
Duid GetSelfDuid() const
Get the DUID.
std::unordered_map< uint32_t, Ptr< InterfaceConfig > > m_interfaces
Map each interface to its corresponding configuration details.
void ReceiveMflag(uint32_t recvInterface)
Callback for when an M flag is received.
void LinkStateHandler(bool isUp, int32_t ifIndex)
Handle changes in the link state.
std::unordered_map< Ipv6Address, uint32_t > m_iaidMap
Track the IPv6 Address - IAID association.
Ptr< RandomVariableStream > m_solicitJitter
Random jitter before sending the first Solicit.
void SendRelease(Ipv6Address address)
Send a Release message to the DHCPv6 server.
static TypeId GetTypeId()
Get the type ID.
TracedCallback< const Ipv6Address & > m_newLease
Trace the new lease.
bool ValidateAdvertise(Dhcp6Header header, Ptr< NetDevice > iDev)
Verify the incoming advertise message.
void Boot(Ptr< NetDevice > device)
Used to send the Solicit message and start the DHCPv6 client.
@ WAIT_REPLY_AFTER_DECLINE
@ WAIT_REPLY_AFTER_RELEASE
Duid::Type m_duidType
DUID type.
void ProcessReply(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress server)
Send a request to the DHCPv6 server.
Ptr< RandomVariableStream > m_transactionId
Random variable to set transaction ID.
void SendRequest(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress server)
Send a request to the DHCPv6 server.
uint16_t m_DuidEnIdentifierLength
DUID-EN identifier length.
void StartApplication() override
Application specific startup code.
void StopApplication() override
Application specific shutdown code.
void NetHandler(Ptr< Socket > socket)
Handles incoming packets from the network.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this Application object.
Ptr< RandomVariableStream > m_iaidStream
Random variable used to create the IAID.
void SendRebind(uint32_t interfaceIndex)
Send a rebind message to the DHCPv6 server.
void SendRenew(uint32_t interfaceIndex)
Send a renew message to the DHCPv6 server.
Time m_solicitInterval
SOL_MAX_RT, time between solicitations.
Duid m_clientDuid
The client DUID, built on first usage in the Boot() function.
void DoDispose() override
Destructor implementation.
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.
Access to the IPv6 forwarding table, interfaces, and configuration.
IPv6 address associated with an interface.
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.
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.
StatusCodeValues
Enum to identify the status code of the operation.
Smart pointer class similar to boost::intrusive_ptr.
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...
StatusCodeValues GetStatusCode() const
Get the status code of the operation.
Hold variables of type string.
Simulation virtual time values and global simulation resolution.
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
AttributeValue implementation for Time.
A Trickle Timer following RFC 6206.
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 > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
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.
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
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.