Skip to content

Commit

Permalink
[ip6] simplify SelectSourceAddress() (#8615)
Browse files Browse the repository at this point in the history
This commit updates `Ip6::SelectSourceAddress()`. A new version of
is added which as its input gets a destination `Ip6::Address`
instead of an `Ip6::MessageInfo`, and returns the selected source
address as an `Ip6::Address *`. This helps simplify its use (no need
to create or pass `MessageInfo` instances). This commit also moves
the implementation of `otIp6SelectSourceAddress()` from `ip6_api.cpp`
to `Ip6` class adding a version of `SelectSourceAddress()` which
updates a passed-in `MessageInfo`directly.
  • Loading branch information
abtink authored Jan 6, 2023
1 parent 28b4010 commit b64fab6
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 86 deletions.
10 changes: 1 addition & 9 deletions src/core/api/ip6_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,7 @@ bool otIp6IsAddressUnspecified(const otIp6Address *aAddress) { return AsCoreType

otError otIp6SelectSourceAddress(otInstance *aInstance, otMessageInfo *aMessageInfo)
{
Error error = kErrorNone;
const Ip6::Netif::UnicastAddress *netifAddr;

netifAddr = AsCoreType(aInstance).Get<Ip6::Ip6>().SelectSourceAddress(AsCoreType(aMessageInfo));
VerifyOrExit(netifAddr != nullptr, error = kErrorNotFound);
aMessageInfo->mSockAddr = netifAddr->GetAddress();

exit:
return error;
return AsCoreType(aInstance).Get<Ip6::Ip6>().SelectSourceAddress(AsCoreType(aMessageInfo));
}

#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
Expand Down
131 changes: 67 additions & 64 deletions src/core/net/ip6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,25 +215,23 @@ Error Ip6::AddMplOption(Message &aMessage, Header &aHeader)
return error;
}

Error Ip6::AddTunneledMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMessageInfo)
Error Ip6::AddTunneledMplOption(Message &aMessage, Header &aHeader)
{
Error error = kErrorNone;
Header tunnelHeader;
const Netif::UnicastAddress *source;
MessageInfo messageInfo(aMessageInfo);
Error error = kErrorNone;
Header tunnelHeader;
const Address *source;

// Use IP-in-IP encapsulation (RFC2473) and ALL_MPL_FORWARDERS address.
messageInfo.GetPeerAddr().SetToRealmLocalAllMplForwarders();

tunnelHeader.InitVersionTrafficClassFlow();
tunnelHeader.SetHopLimit(static_cast<uint8_t>(kDefaultHopLimit));
tunnelHeader.SetPayloadLength(aHeader.GetPayloadLength() + sizeof(tunnelHeader));
tunnelHeader.SetDestination(messageInfo.GetPeerAddr());
tunnelHeader.GetDestination().SetToRealmLocalAllMplForwarders();
tunnelHeader.SetNextHeader(kProtoIp6);

VerifyOrExit((source = SelectSourceAddress(messageInfo)) != nullptr, error = kErrorInvalidSourceAddress);
source = SelectSourceAddress(tunnelHeader.GetDestination());
VerifyOrExit(source != nullptr, error = kErrorInvalidSourceAddress);

tunnelHeader.SetSource(source->GetAddress());
tunnelHeader.SetSource(*source);

SuccessOrExit(error = AddMplOption(aMessage, tunnelHeader));
SuccessOrExit(error = aMessage.Prepend(tunnelHeader));
Expand All @@ -242,7 +240,7 @@ Error Ip6::AddTunneledMplOption(Message &aMessage, Header &aHeader, MessageInfo
return error;
}

Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMessageInfo)
Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader)
{
Error error = kErrorNone;

Expand Down Expand Up @@ -315,7 +313,7 @@ Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMes
}
#endif

SuccessOrExit(error = AddTunneledMplOption(aMessage, aHeader, aMessageInfo));
SuccessOrExit(error = AddTunneledMplOption(aMessage, aHeader));
}

exit:
Expand Down Expand Up @@ -467,10 +465,10 @@ Error Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t aI

if (aMessageInfo.GetSockAddr().IsUnspecified() || aMessageInfo.GetSockAddr().IsMulticast())
{
const Netif::UnicastAddress *source = SelectSourceAddress(aMessageInfo);
const Address *source = SelectSourceAddress(aMessageInfo.GetPeerAddr());

VerifyOrExit(source != nullptr, error = kErrorInvalidSourceAddress);
header.SetSource(source->GetAddress());
header.SetSource(*source);
}
else
{
Expand Down Expand Up @@ -507,7 +505,7 @@ Error Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t aI
}
#endif

SuccessOrExit(error = AddTunneledMplOption(aMessage, header, aMessageInfo));
SuccessOrExit(error = AddTunneledMplOption(aMessage, header));
}

aMessage.SetMulticastLoop(aMessageInfo.GetMulticastLoop());
Expand Down Expand Up @@ -1126,21 +1124,16 @@ Error Ip6::ProcessReceiveCallback(Message &aMessage,

Error Ip6::SendRaw(Message &aMessage, bool aAllowLoopBackToHost)
{
Error error = kErrorNone;
Header header;
MessageInfo messageInfo;
bool freed = false;
Error error = kErrorNone;
Header header;
bool freed = false;

SuccessOrExit(error = header.ParseFrom(aMessage));
VerifyOrExit(!header.GetSource().IsMulticast(), error = kErrorInvalidSourceAddress);

messageInfo.SetPeerAddr(header.GetSource());
messageInfo.SetSockAddr(header.GetDestination());
messageInfo.SetHopLimit(header.GetHopLimit());

if (header.GetDestination().IsMulticast())
{
SuccessOrExit(error = InsertMplOption(aMessage, header, messageInfo));
SuccessOrExit(error = InsertMplOption(aMessage, header));
}

error = HandleDatagram(aMessage, aAllowLoopBackToHost ? kFromHostAllowLoopBack : kFromHostDisallowLoopBack);
Expand Down Expand Up @@ -1379,110 +1372,120 @@ bool Ip6::ShouldForwardToThread(const MessageInfo &aMessageInfo, MessageOrigin a
return shouldForward;
}

const Netif::UnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo)
Error Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) const
{
Error error = kErrorNone;
const Address *source;

source = SelectSourceAddress(aMessageInfo.GetPeerAddr());
VerifyOrExit(source != nullptr, error = kErrorNotFound);
aMessageInfo.SetSockAddr(*source);

exit:
return error;
}

const Address *Ip6::SelectSourceAddress(const Address &aDestination) const
{
Address *destination = &aMessageInfo.GetPeerAddr();
uint8_t destinationScope = destination->GetScope();
const bool destinationIsRoutingLocator = Get<Mle::Mle>().IsRoutingLocator(*destination);
const Netif::UnicastAddress *rvalAddr = nullptr;
uint8_t rvalPrefixMatched = 0;
uint8_t destScope = aDestination.GetScope();
bool destIsRloc = Get<Mle::Mle>().IsRoutingLocator(aDestination);
const Netif::UnicastAddress *bestAddr = nullptr;
uint8_t bestMatchLen = 0;

for (const Netif::UnicastAddress &addr : Get<ThreadNetif>().GetUnicastAddresses())
{
const Address *candidateAddr = &addr.GetAddress();
uint8_t candidatePrefixMatched;
uint8_t overrideScope;
uint8_t matchLen;
uint8_t overrideScope;

if (Get<Mle::Mle>().IsAnycastLocator(*candidateAddr))
if (Get<Mle::Mle>().IsAnycastLocator(addr.GetAddress()))
{
// Don't use anycast address as source address.
continue;
}

candidatePrefixMatched = destination->PrefixMatch(*candidateAddr);
matchLen = aDestination.PrefixMatch(addr.GetAddress());

if (candidatePrefixMatched >= addr.mPrefixLength)
if (matchLen >= addr.mPrefixLength)
{
candidatePrefixMatched = addr.mPrefixLength;
overrideScope = addr.GetScope();
matchLen = addr.mPrefixLength;
overrideScope = addr.GetScope();
}
else
{
overrideScope = destinationScope;
overrideScope = destScope;
}

if (rvalAddr == nullptr)
if (bestAddr == nullptr)
{
// Rule 0: Prefer any address
rvalAddr = &addr;
rvalPrefixMatched = candidatePrefixMatched;
bestAddr = &addr;
bestMatchLen = matchLen;
}
else if (*candidateAddr == *destination)
else if (addr.GetAddress() == aDestination)
{
// Rule 1: Prefer same address
rvalAddr = &addr;
bestAddr = &addr;
ExitNow();
}
else if (addr.GetScope() < rvalAddr->GetScope())
else if (addr.GetScope() < bestAddr->GetScope())
{
// Rule 2: Prefer appropriate scope
if (addr.GetScope() >= overrideScope)
{
rvalAddr = &addr;
rvalPrefixMatched = candidatePrefixMatched;
bestAddr = &addr;
bestMatchLen = matchLen;
}
else
{
continue;
}
}
else if (addr.GetScope() > rvalAddr->GetScope())
else if (addr.GetScope() > bestAddr->GetScope())
{
if (rvalAddr->GetScope() < overrideScope)
if (bestAddr->GetScope() < overrideScope)
{
rvalAddr = &addr;
rvalPrefixMatched = candidatePrefixMatched;
bestAddr = &addr;
bestMatchLen = matchLen;
}
else
{
continue;
}
}
else if (addr.mPreferred && !rvalAddr->mPreferred)
else if (addr.mPreferred && !bestAddr->mPreferred)
{
// Rule 3: Avoid deprecated addresses
rvalAddr = &addr;
rvalPrefixMatched = candidatePrefixMatched;
bestAddr = &addr;
bestMatchLen = matchLen;
}
else if (candidatePrefixMatched > rvalPrefixMatched)
else if (matchLen > bestMatchLen)
{
// Rule 6: Prefer matching label
// Rule 7: Prefer public address
// Rule 8: Use longest prefix matching
rvalAddr = &addr;
rvalPrefixMatched = candidatePrefixMatched;
bestAddr = &addr;
bestMatchLen = matchLen;
}
else if ((candidatePrefixMatched == rvalPrefixMatched) &&
(destinationIsRoutingLocator == Get<Mle::Mle>().IsRoutingLocator(*candidateAddr)))
else if ((matchLen == bestMatchLen) && (destIsRloc == Get<Mle::Mle>().IsRoutingLocator(addr.GetAddress())))
{
// Additional rule: Prefer RLOC source for RLOC destination, EID source for anything else
rvalAddr = &addr;
rvalPrefixMatched = candidatePrefixMatched;
bestAddr = &addr;
bestMatchLen = matchLen;
}
else
{
continue;
}

// infer destination scope based on prefix match
if (rvalPrefixMatched >= rvalAddr->mPrefixLength)
if (bestMatchLen >= bestAddr->mPrefixLength)
{
destinationScope = rvalAddr->GetScope();
destScope = bestAddr->GetScope();
}
}

exit:
return rvalAddr;
return (bestAddr != nullptr) ? &bestAddr->GetAddress() : nullptr;
}

bool Ip6::IsOnLink(const Address &aAddress) const
Expand Down
21 changes: 16 additions & 5 deletions src/core/net/ip6.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,25 @@ class Ip6 : public InstanceLocator, private NonCopyable
void SetForwardingEnabled(bool aEnable) { mForwardingEnabled = aEnable; }

/**
* This method perform default source address selection.
* This method performs default source address selection.
*
* @param[in] aMessageInfo A reference to the message information.
* @param[in,out] aMessageInfo A reference to the message information.
*
* @retval kErrorNone Found a source address and updated SockAddr of @p aMessageInfo.
* @retval kErrorNotFound No source address was found and @p aMessageInfo is unchanged.
*
*/
Error SelectSourceAddress(MessageInfo &aMessageInfo) const;

/**
* This method performs default source address selection.
*
* @param[in] aDestination The destination address.
*
* @returns A pointer to the selected IPv6 source address or `nullptr` if no source address was found.
*
*/
const Netif::UnicastAddress *SelectSourceAddress(MessageInfo &aMessageInfo);
const Address *SelectSourceAddress(const Address &aDestination) const;

/**
* This method returns a reference to the send queue.
Expand Down Expand Up @@ -404,8 +415,8 @@ class Ip6 : public InstanceLocator, private NonCopyable
void SendIcmpError(Message &aMessage, Icmp::Header::Type aIcmpType, Icmp::Header::Code aIcmpCode);
#endif
Error AddMplOption(Message &aMessage, Header &aHeader);
Error AddTunneledMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMessageInfo);
Error InsertMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMessageInfo);
Error AddTunneledMplOption(Message &aMessage, Header &aHeader);
Error InsertMplOption(Message &aMessage, Header &aHeader);
Error RemoveMplOption(Message &aMessage);
Error HandleOptions(Message &aMessage, Header &aHeader, bool aIsOutbound, bool &aReceive);
Error HandlePayload(Header &aIp6Header,
Expand Down
13 changes: 5 additions & 8 deletions src/core/net/tcp6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,14 +780,11 @@ bool Tcp::AutoBind(const SockAddr &aPeer, SockAddr &aToBind, bool aBindAddress,

if (aBindAddress)
{
MessageInfo peerInfo;
const Netif::UnicastAddress *netifAddress;

peerInfo.Clear();
peerInfo.SetPeerAddr(aPeer.GetAddress());
netifAddress = Get<Ip6>().SelectSourceAddress(peerInfo);
VerifyOrExit(netifAddress != nullptr, success = false);
aToBind.GetAddress() = netifAddress->GetAddress();
const Address *source;

source = Get<Ip6>().SelectSourceAddress(aPeer.GetAddress());
VerifyOrExit(source != nullptr, success = false);
aToBind.SetAddress(*source);
}

if (aBindPort)
Expand Down

0 comments on commit b64fab6

Please sign in to comment.