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/mac48-address.h"
23#include "ns3/net-device-container.h"
24#include "ns3/object.h"
25#include "ns3/pointer.h"
27#include "ns3/random-variable-stream.h"
28#include "ns3/simulator.h"
29#include "ns3/socket.h"
30#include "ns3/string.h"
31#include "ns3/trace-source-accessor.h"
32#include "ns3/traced-value.h"
33#include "ns3/trickle-timer.h"
48 .AddConstructor<Dhcp6Client>()
49 .SetGroupName(
"InternetApps")
50 .AddAttribute(
"Transactions",
51 "A value to be used as the transaction ID.",
52 StringValue(
"ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"),
55 .AddAttribute(
"SolicitJitter",
56 "The jitter in ms that a node waits before sending any solicitation. By "
57 "default, the model will wait for a duration in ms defined by a uniform "
58 "random-variable between 0 and SolicitJitter. This is equivalent to"
59 "SOL_MAX_DELAY (RFC 8415, Section 7.6).",
60 StringValue(
"ns3::UniformRandomVariable[Min=0.0|Max=1000.0]"),
63 .AddAttribute(
"IaidValue",
64 "The identifier for a new IA created by a client.",
65 StringValue(
"ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"),
68 .AddAttribute(
"SolicitInterval",
69 "Time after which the client resends the Solicit."
70 "Equivalent to SOL_MAX_RT (RFC 8415, Section 7.6)",
74 .AddTraceSource(
"NewLease",
75 "The client has obtained a lease",
77 "ns3::Ipv6Address::TracedCallback");
93 itr.second->Cleanup();
117 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
121 if (clientTransactId != receivedTransactId)
145 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
159 (
Simulator::Now() - dhcpInterface->m_msgStartTime).GetMilliSeconds() / 10;
160 uint16_t elapsed = actualElapsedTime > 65535 ? 65535 : actualElapsedTime;
167 for (
const auto& iaOpt : ianaOptionsList)
171 for (
const auto& iaAddrOpt : iaOpt.m_iaAddressOption)
173 requestHeader.
AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
175 iaAddrOpt.GetIaAddress(),
176 iaAddrOpt.GetPreferredLifetime(),
177 iaAddrOpt.GetValidLifetime());
179 NS_LOG_DEBUG(
"Requesting " << iaAddrOpt.GetIaAddress());
186 packet->AddHeader(requestHeader);
192 if (dhcpInterface->m_socket->SendTo(
201 NS_LOG_INFO(
"DHCPv6 client: Error while sending Request.");
216 std::cout <<
"InterfaceConfig::~InterfaceConfig" << std::endl;
222 m_solicitTimer.Stop();
223 m_declinedAddresses.clear();
225 m_renewEvent.Cancel();
226 m_rebindEvent.Cancel();
228 for (
auto& itr : m_releaseEvent)
241 for (
auto& addr : m_offeredAddresses)
243 if (addr == offeredAddress)
252 m_nAcceptedAddresses += 1;
255 m_client->m_newLease(offeredAddress);
256 std::cerr <<
"* got a new lease " << offeredAddress << std::endl;
263 NS_LOG_DEBUG(
"Address to be declined " << offeredAddress);
267 for (
auto& addr : m_offeredAddresses)
269 if (addr == offeredAddress)
278 m_declinedAddresses.emplace_back(offeredAddress);
279 if (m_declinedAddresses.size() + m_nAcceptedAddresses == m_offeredAddresses.size())
289 if (m_declinedAddresses.empty())
295 m_renewEvent.Cancel();
296 m_rebindEvent.Cancel();
297 for (
auto itr : m_releaseEvent)
306 for (
const auto& offer : m_declinedAddresses)
308 uint32_t iaid = m_client->m_iaidMap[offer];
311 declineHeader.
AddIanaOption(iaid, m_renewTime.GetSeconds(), m_rebindTime.GetSeconds());
314 m_prefLifetime.GetSeconds(),
315 m_validLifetime.GetSeconds());
319 m_transactId =
static_cast<uint32_t>(m_client->m_transactionId->GetValue());
332 packet->AddHeader(declineHeader);
333 if ((m_socket->SendTo(packet,
342 NS_LOG_INFO(
"DHCPv6 client: Error while sending Decline");
351 m_solicitTimer.Stop();
353 for (
auto& releaseEvent : m_releaseEvent)
355 releaseEvent.Cancel();
358 m_renewEvent.Cancel();
359 m_rebindEvent.Cancel();
367 for (
uint32_t i = 0; i < ipv6->GetNAddresses(m_interfaceIndex); i++)
369 for (
const auto& addr : m_offeredAddresses)
371 if (ipv6->GetAddress(m_interfaceIndex, i) == addr)
373 ipv6->RemoveAddress(m_interfaceIndex, i);
378 m_offeredAddresses.clear();
383 icmpv6->TraceDisconnectWithoutContext(
"DadSuccess", m_acceptedAddressCb.value());
385 icmpv6->TraceDisconnectWithoutContext(
"DadFailure", m_declinedAddressCb.value());
397 NS_LOG_DEBUG(
"Received status " << (uint16_t)statusCode <<
" from DHCPv6 server");
400 NS_LOG_INFO(
"DHCPv6 client: Server bindings updated successfully.");
404 NS_LOG_INFO(
"DHCPv6 client: Server bindings update failed.");
414 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
421 dhcpInterface->m_declinedAddresses.clear();
425 std::vector<uint32_t> iaidList;
427 for (
const auto& iaOpt : ianaOptionsList)
431 for (
const auto& iaAddrOpt : iaOpt.m_iaAddressOption)
433 Ipv6Address offeredAddress = iaAddrOpt.GetIaAddress();
437 ipv6->AddAddress(ifIndex, addr);
438 ipv6->SetUp(ifIndex);
441 dhcpInterface->m_prefLifetime =
Seconds(iaAddrOpt.GetPreferredLifetime());
442 dhcpInterface->m_validLifetime =
Seconds(iaAddrOpt.GetValidLifetime());
445 m_iaidMap[offeredAddress] = iaOpt.GetIaid();
448 dhcpInterface->m_releaseEvent.emplace_back(
454 dhcpInterface->m_offeredAddresses.push_back(offeredAddress);
457 earliestRenew = std::min(earliestRenew,
Seconds(iaOpt.GetT1()));
458 earliestRebind = std::min(earliestRebind,
Seconds(iaOpt.GetT2()));
459 iaidList.emplace_back(iaOpt.GetIaid());
464 dhcpInterface->m_renewTime = earliestRenew;
465 dhcpInterface->m_renewEvent.Cancel();
466 dhcpInterface->m_renewEvent =
470 dhcpInterface->m_rebindTime = earliestRebind;
471 dhcpInterface->m_rebindEvent.Cancel();
472 dhcpInterface->m_rebindEvent =
475 int32_t interfaceId = ipv6->GetInterfaceForDevice(iDev);
481 if (!dhcpInterface->m_acceptedAddressCb.has_value())
483 dhcpInterface->m_acceptedAddressCb =
485 icmpv6->TraceConnectWithoutContext(
"DadSuccess",
486 dhcpInterface->m_acceptedAddressCb.value());
489 if (!dhcpInterface->m_declinedAddressCb.has_value())
491 dhcpInterface->m_declinedAddressCb =
493 icmpv6->TraceConnectWithoutContext(
"DadFailure",
494 dhcpInterface->m_declinedAddressCb.value());
522 for (
const auto& iaidRenew :
m_interfaces[dhcpInterfaceIndex]->m_iaids)
525 m_interfaces[dhcpInterfaceIndex]->m_renewTime.GetSeconds(),
526 m_interfaces[dhcpInterfaceIndex]->m_rebindTime.GetSeconds());
534 if (iaid == iaidRenew)
538 m_interfaces[dhcpInterfaceIndex]->m_prefLifetime.GetSeconds(),
539 m_interfaces[dhcpInterfaceIndex]->m_validLifetime.GetSeconds());
543 NS_LOG_DEBUG(
"Renewing addresses in IAID " << iaidRenew);
549 packet->AddHeader(header);
550 if ((
m_interfaces[dhcpInterfaceIndex]->m_socket->SendTo(
560 NS_LOG_INFO(
"DHCPv6 client: Error while sending Renew");
587 for (
const auto& iaid :
m_interfaces[dhcpInterfaceIndex]->m_iaids)
590 m_interfaces[dhcpInterfaceIndex]->m_renewTime.GetSeconds(),
591 m_interfaces[dhcpInterfaceIndex]->m_rebindTime.GetSeconds());
599 packet->AddHeader(header);
600 if ((
m_interfaces[dhcpInterfaceIndex]->m_socket->SendTo(
610 NS_LOG_INFO(
"DHCPv6 client: Error while sending Rebind");
632 bool removed = ipv6->RemoveAddress(ifIndex, address);
639 header.SetTransactId(dhcpInterface->m_transactId);
646 header.AddServerIdentifier(dhcpInterface->m_serverDuid);
649 header.AddElapsedTime(0);
653 header.AddIanaOption(iaid,
654 dhcpInterface->m_renewTime.GetSeconds(),
655 dhcpInterface->m_rebindTime.GetSeconds());
656 header.AddAddress(iaid,
658 dhcpInterface->m_prefLifetime.GetSeconds(),
659 dhcpInterface->m_validLifetime.GetSeconds());
663 packet->AddHeader(header);
664 if ((dhcpInterface->m_socket->SendTo(packet,
673 NS_LOG_INFO(
"DHCPv6 client: Error while sending Release");
693 "No incoming interface on DHCPv6 message.");
698 uint32_t iIf = ipv6->GetInterfaceForDevice(iDev);
701 if (packet->RemoveHeader(header) == 0 || !dhcpInterface)
709 dhcpInterface->m_solicitTimer.Stop();
721 dhcpInterface->m_renewEvent.Cancel();
722 dhcpInterface->m_rebindEvent.Cancel();
723 for (
auto itr : dhcpInterface->m_releaseEvent)
751 dhcpInterface->Cleanup();
768 NS_ASSERT_MSG(node,
"Dhcp6Client::StartApplication: cannot get the node from the device.");
771 NS_ASSERT_MSG(ipv6,
"Dhcp6Client::StartApplication: node does not have IPv6.");
773 NS_LOG_DEBUG(
"Starting DHCPv6 application on node " << node->GetId());
776 uint32_t nInterfaces = ipv6->GetNInterfaces();
779 for (
uint32_t ifIndex = 1; ifIndex < nInterfaces; ifIndex++)
802 dhcpInterface->m_client =
this;
803 dhcpInterface->m_interfaceIndex = recvInterface;
804 dhcpInterface->m_socket =
nullptr;
809 std::vector<uint32_t> existingIaNaIds;
813 if (std::find(existingIaNaIds.begin(), existingIaNaIds.end(), iaid) ==
814 existingIaNaIds.end())
816 dhcpInterface->m_iaids.push_back(iaid);
817 existingIaNaIds.emplace_back(iaid);
824 ipv6Interface->TraceConnectWithoutContext(
837 if (interface == recvInterface &&
m_interfaces[interface])
842 ipv6l3->GetInterface(interface)->GetLinkLocalAddress().GetAddress();
847 socket->BindToNetDevice(device);
848 socket->SetRecvPktInfo(
true);
862 dhcpInterface->m_solicitTimer.Enable();
873 int32_t ifIndex = ipv6->GetInterfaceForDevice(device);
900 for (
auto iaid : dhcpInterface->m_iaids)
903 dhcpInterface->m_renewTime.GetSeconds(),
904 dhcpInterface->m_rebindTime.GetSeconds());
907 packet->AddHeader(header);
909 if ((dhcpInterface->m_socket->SendTo(packet,
918 NS_LOG_INFO(
"DHCPv6 client: Error while sending Solicit");
936 itr.second->Cleanup();
a polymophic address class
The base class for all ns3 applications.
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
void DeclineOffer()
Send a Decline message to the DHCPv6 server.
uint8_t m_nAcceptedAddresses
Number of addresses accepted by client.
Time m_prefLifetime
Preferred lifetime of the address.
Time m_rebindTime
REB_MAX_RT, Time after which client should send a Rebind message.
~InterfaceConfig()
Destructor.
void AcceptedAddress(const Ipv6Address &offeredAddress)
Accept the DHCPv6 offer.
InterfaceConfig()
The default constructor.
void DeclinedAddress(const Ipv6Address &offeredAddress)
Add a declined address to the list maintained by the client.
void Cleanup()
Cleanup the internal callbacks and timers.
Time m_renewTime
REN_MAX_RT, Time after which lease should be renewed.
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.
std::unordered_map< Ipv6Address, uint32_t, Ipv6AddressHash > m_iaidMap
Track the IPv6 Address - IAID association.
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.
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
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.
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.
void DoDispose() override
Destructor implementation.
Implements the unique identifier for DHCPv6.
bool IsInvalid() const
Check if the DUID is invalid.
void Initialize(Ptr< Node > node)
Initialize the DUID for a client or server.
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.
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.
virtual double GetValue()=0
Get the next random value drawn from the distribution.
virtual uint32_t GetInteger()
Get the next random value drawn from the distribution.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
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.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
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 > 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... > 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.
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.
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.